novachess commited on
Commit
92cdf79
·
verified ·
1 Parent(s): f47c0c5

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ nova.onnx.data filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,5 +1,415 @@
1
- ---
2
- license: other
3
- license_name: nova-chess-engine-license
4
- license_link: LICENSE
5
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: nova-chess-engine-license
4
+ license_link: https://github.com/novachessai/novachess-engine/blob/main/LICENSE
5
+ language: en
6
+ tags:
7
+ - chess
8
+ - transformer
9
+ - human-move-prediction
10
+ - style-conditioned
11
+ pipeline_tag: other
12
+ library_name: onnx
13
+ ---
14
+
15
+ # Nova Chess Engine
16
+
17
+ A style-conditioned transformer that predicts human chess moves. Given
18
+ a board position, a target player rating, and two optional style parameters
19
+ (classical–hypermodern preference and aggression), Nova returns a
20
+ probability distribution over all legal moves calibrated to how a
21
+ player of that rating and style would play.
22
+
23
+ **Inference is a single forward pass of the neural network.** Nova
24
+ does not use Monte Carlo tree search, minimax, alpha-beta pruning,
25
+ or any form of engine-style position evaluation. There is no value
26
+ head and no lookahead. Move selection comes entirely from learned
27
+ patterns over the training corpus — fast on CPU (~35-50 ms per
28
+ position) and categorically different from search-based engines
29
+ like Stockfish or Leela.
30
+
31
+ **Play Nova directly at [novachess.ai](https://novachess.ai)** —
32
+ Nova powers the *Play* and *Train with Nova* features on the site,
33
+ where you can face Nova at any rating/style setting with built-in
34
+ analysis and post-game review.
35
+
36
+ - Developed by Nova Chess — <https://novachess.ai>
37
+ - Model type: pure-policy neural network over chess moves,
38
+ conditioned on position + rating + two style parameters.
39
+ Single forward pass per position; no search, no value head, no
40
+ game history.
41
+ - Language(s): not applicable — input is chess positions (18-channel
42
+ plane encoding), output is a distribution over 16,384 move indices
43
+ - License: custom non-commercial (see `LICENSE`)
44
+
45
+ Full results and reproducibility: [`RESULTS.md`](RESULTS.md).
46
+ Source code and docs: <https://github.com/novachessai/novachess-engine>
47
+
48
+
49
+ ## Model Details
50
+
51
+ ### Inputs
52
+
53
+ - `positions` — `float32` tensor of shape `(B, 18, 8, 8)`
54
+ - Planes 0–5: white pieces (P, N, B, R, Q, K), one-hot per square
55
+ - Planes 6–11: black pieces (P, N, B, R, Q, K)
56
+ - Plane 12: side to move (1s if white to move, 0s otherwise)
57
+ - Planes 13–16: castling rights (white-kingside, white-queenside,
58
+ black-kingside, black-queenside)
59
+ - Plane 17: en-passant file indicator
60
+ - `conditioning` — `float32` tensor of shape `(B, 3)`
61
+ - `rating_norm` = `(rating − 800) / (2700 − 800)`, clipped to `[0, 1]`
62
+ - `classical` ∈ `[0, 1]` — opening preference (higher = more
63
+ classical mainlines)
64
+ - `aggression` ∈ `[0, 1]` — tactical/sacrificial tendency
65
+
66
+ ### Outputs
67
+
68
+ - `logits` — `float32` tensor of shape `(B, 16384)`. Raw logits over
69
+ the 16,384-index move space. Caller is responsible for masking
70
+ illegal moves and applying softmax.
71
+
72
+ Move index encoding:
73
+
74
+ ```
75
+ move_index = promotion_offset + from_square * 64 + to_square
76
+ promotion_offset:
77
+ 0 no promotion (also queen promotion)
78
+ 4096 knight promotion
79
+ 8192 bishop promotion
80
+ 12288 rook promotion
81
+ ```
82
+
83
+ where `from_square` and `to_square` are standard 0–63 indices
84
+ (`a1 = 0, h8 = 63`).
85
+
86
+ ### Architectural distinction from prior work
87
+
88
+ Nova is **single-head pure-policy**: the network's only output is the
89
+ move distribution. There is no value head (no game-outcome
90
+ prediction), no auxiliary head (no side-task supervision on captures,
91
+ checks, etc.), no search at inference, no lookahead, and no use of
92
+ any position evaluator before, during, or after the forward pass.
93
+ Move selection comes entirely from the policy distribution the
94
+ network learned by predicting actual human moves at the conditioned
95
+ rating and style.
96
+
97
+ This contrasts with every published comparable model:
98
+
99
+ | Model | Heads at inference | Search | Notes |
100
+ |---|---|---|---|
101
+ | **Nova** (this release) | 1 (policy) | none | single forward pass, ~35–50 ms CPU |
102
+ | Maia-2 (NeurIPS 2024) | 3 (policy + value + auxiliary) | none | value head regresses W/D/L; auxiliary head predicts legal moves, captures, check delivery |
103
+ | Maia-3 (`maia3_simplified.onnx`) | 2 (policy + value) | none | drops Maia-2's auxiliary head; retains W/D/L value head |
104
+ | Allie (ICLR 2025) | 1 (policy) + value via search | adaptive MCTS at inference | policy is decoder-only over move sequences; MCTS provides per-position evaluation at runtime |
105
+ | Leela (LC0) | 2 (policy + value) | MCTS | engine-strength playing model |
106
+ | Stockfish (NNUE) | evaluation only | alpha-beta | not a human-move predictor |
107
+
108
+ The pure-policy stance is a deliberate design choice. It keeps the
109
+ model fast (one forward pass, no tree expansion), simple to deploy
110
+ (just the ONNX file — no MCTS implementation, no auxiliary supervision
111
+ data at training time, no value-head calibration to maintain), and
112
+ forces the network to learn move quality entirely from move-selection
113
+ patterns rather than offloading it to a parallel evaluator. The
114
+ benchmarks in `RESULTS.md` show this is competitive with multi-head
115
+ architectures on the move-prediction task itself.
116
+
117
+
118
+ ### Files in this repository
119
+
120
+ - `nova.onnx` + `nova.onnx.data` — ONNX export with external
121
+ data. Both files required at inference time; place in the same
122
+ directory before loading.
123
+ - `nova.pt` — PyTorch checkpoint (weights only) for research
124
+ and fine-tuning.
125
+ - `unified_sample_600k.pkl` — the 600K-position out-of-sample
126
+ evaluation set used in the results reported below. Schema:
127
+ `{fen, actual, rating, ply, min_clock, piece_count, band,
128
+ player_id, result, ...}`.
129
+ - `nova_neutral_600k.pkl`, `nova_actual_600k.pkl`,
130
+ `maia2_600k.pkl`, `maia3_600k.pkl` — per-position predictions from
131
+ each model on the 600K sample, used for the paired significance
132
+ tests in `RESULTS.md`.
133
+
134
+
135
+ ## Uses
136
+
137
+ ### Direct use
138
+
139
+ - Predict the probability distribution over legal moves that a human
140
+ of a specified rating and style would play from a given position.
141
+ - Sample moves to run as a human-like opponent or study partner.
142
+ - Score actual human moves by `P(actual_move | position, rating,
143
+ style)` for humanness analysis, move difficulty assessment, or
144
+ anti-cheat signals.
145
+ - Benchmark other human-move predictors against Nova on shared
146
+ evaluation sets.
147
+ - Fine-tune on specialized data (specific player corpora, specific
148
+ opening systems, specific time controls) for personal or research
149
+ use.
150
+
151
+ ### Downstream use
152
+
153
+ The model is used internally by Nova Chess to power the
154
+ *Play Nova* and *Train with Nova* features at https://novachess.ai,
155
+ where end users play or practice against the model at chosen rating
156
+ and style settings. The same weights published in this repository are
157
+ the ones served by the application.
158
+
159
+ The in-app version additionally wraps Nova's policy output with a
160
+ small calibration layer used to tune playing strength across rating
161
+ tiers. The two main components are a **per-tier temperature schedule**
162
+ (the primary calibration lever) and an **evaluation-only filter**:
163
+ after Nova samples a candidate move, Stockfish is consulted at low
164
+ depth to evaluate that specific candidate; if its evaluation falls
165
+ below a tier-dependent quality threshold, the move is probabilistically
166
+ replaced by re-sampling from Nova's own distribution.
167
+
168
+ **Every move the in-app bot plays still originates from Nova's policy
169
+ distribution.** Stockfish is never used to suggest, generate, or
170
+ select moves — only to evaluate moves Nova has already proposed, so
171
+ that obvious blunders at higher tiers can be probabilistically caught.
172
+ The model weights are never touched. The calibration layer is **not**
173
+ part of this release; the released checkpoint is the bare policy
174
+ model, exactly the surface that benchmarks and downstream research /
175
+ fine-tuning should target. See the README's "In-app behavior vs the
176
+ released model" section for the full distinction.
177
+
178
+ ### Out-of-scope use
179
+
180
+ - Not suitable as a chess-playing engine for maximum-strength
181
+ competition against search-based engines. Nova is trained on
182
+ human-move prediction — it maximizes `P(move | human of rating R)`,
183
+ not `P(best move)` — and uses no search, no lookahead, and no
184
+ position evaluation beyond the single forward pass of the policy
185
+ network. For engine-quality play, a search-based evaluator such as
186
+ Stockfish remains the correct choice.
187
+ - Not intended for cheating detection as a standalone verdict. Nova
188
+ probabilities can inform a cheat-detection pipeline but should not
189
+ be used as sole evidence for accusations.
190
+ - Not validated on chess variants (Chess960, King of the Hill, etc.)
191
+ — trained only on standard chess.
192
+ - Not a replacement for human coaching — move probabilities are not
193
+ explanations, and the model does not produce commentary or verbal
194
+ analysis.
195
+
196
+
197
+ ## Bias, Risks, and Limitations
198
+
199
+ - **Training-data distribution.** Nova is trained on ~520M positions
200
+ from Lichess rapid games played Apr–Nov 2025. The player population
201
+ is self-selected (online rapid players on one platform), skews
202
+ toward active users in rating bands 1100–2300, and may not
203
+ represent the full distribution of human chess play. Inferences
204
+ about moves at extreme ratings (particularly below 800 and above
205
+ 2500) have less training-data support.
206
+ - **Style axis limitations.** The classical and aggression axes
207
+ capture specific operational definitions (opening move choices for
208
+ classical; captures + territorial control + king pressure for
209
+ aggression). They do not capture all dimensions of human chess
210
+ style (combinational richness, prophylaxis, time management, etc.).
211
+ - **Rating conditioning is a scalar.** Nova receives a single number
212
+ for rating, not a distribution. The model has learned a continuous
213
+ interpolation of playing strength, but at the high end of the
214
+ rating axis the playing strength it produces may saturate below the
215
+ conditioned rating.
216
+ - **No game history.** Nova conditions on the current position only,
217
+ not on the preceding move sequence. Two positions with identical
218
+ FENs are indistinguishable to the model even if reached through
219
+ very different games.
220
+ - **No check for illegal moves.** The raw logits include mass on
221
+ illegal move indices. Callers must apply a legal-move mask before
222
+ sampling. See the README quickstart and `docs/serving.md` for the
223
+ reference masking pattern.
224
+ - **Value / result prediction is not supported.** This checkpoint is
225
+ policy-only; it does not output win/draw/loss probabilities.
226
+
227
+
228
+ ## Training Details
229
+
230
+ ### Training data
231
+
232
+ Nova was trained on a large corpus of Lichess rapid games, balanced
233
+ across six rating bands from 800 to 2700+. Position sampling and
234
+ filtering were tuned to keep all skill levels and all game phases
235
+ well-represented in training. Details of the data pipeline and
236
+ cohort balancing are not published.
237
+
238
+ ### Training procedure
239
+
240
+ Nova is trained end-to-end with a cross-entropy objective over the
241
+ 16,384-index move space. The output is the policy distribution over
242
+ legal moves, with no auxiliary value head. Specific architectural
243
+ dimensions and training hyperparameters are not published.
244
+
245
+ ### Inference cost
246
+
247
+ - CPU (ONNX fp32): 35–50 ms per position on a modern x86 core
248
+ - GPU (batched, H100): ~1 ms per position
249
+ - Inference memory: approximately 500 MB RAM per worker (fp32 weights
250
+ with external-data sidecar)
251
+
252
+
253
+ ## Evaluation
254
+
255
+ ### Evaluation data
256
+
257
+ A single held-out evaluation sample of **600,000 positions** drawn
258
+ from Lichess rapid games played in **March 2026**, stratified at
259
+ 100,000 positions per rating band. This sample is temporally held out
260
+ from Nova's training data and is shipped as `unified_sample_600k.pkl`
261
+ on Hugging Face.
262
+
263
+ ### Metrics
264
+
265
+ - **hit1** — fraction of positions where the model's top prediction
266
+ matches the human's actual move (top-1 accuracy)
267
+ - **hit5** — fraction of positions where the human's move is in the
268
+ model's top-5 predictions
269
+ - **Mean P(actual)** — mean probability mass that the model assigned
270
+ to the move the human actually played
271
+ - **Mean top-5 mass** — mean total probability mass assigned to the
272
+ top-5 predictions
273
+
274
+ ### Results
275
+
276
+ On the 600,000-position sample, comparing Nova against the publicly
277
+ available Maia-3 checkpoint (`maia3_simplified.onnx` from
278
+ https://maiachess.com) and the Maia-2 rapid checkpoint:
279
+
280
+ | Metric | Maia-2 | Maia-3 | Nova (neutral style) |
281
+ |---|---|---|---|
282
+ | Top-1 hit rate | 50.27 % | **54.83 %** | 54.60 % |
283
+ | Top-5 hit rate | 88.38 % | **91.23 %** | 91.10 % |
284
+ | Mean P(actual) | 38.44 % | 42.10 % | **42.51 %** |
285
+ | Mean top-5 mass | 89.33 % | 91.96 % | **92.26 %** |
286
+
287
+ All four Nova-vs-Maia-3 deltas are statistically significant under
288
+ paired McNemar tests (for hit rates) and paired t-tests (for
289
+ probability-mass metrics). Both probability-mass deltas remain
290
+ significant under a player-clustered bootstrap (95% CIs reported in
291
+ RESULTS.md).
292
+
293
+ Full breakdown by rating band, Maia tier (Skilled / Advanced /
294
+ Master), game phase, piece count, and three filter variants (all
295
+ positions; `ply ≥ 10`; `ply ≥ 10 + clock ≥ 30 s`) is in
296
+ [`RESULTS.md`](RESULTS.md).
297
+
298
+
299
+ ## How to use
300
+
301
+ Minimum-dependency inference example (CPU):
302
+
303
+ ```bash
304
+ pip install onnxruntime python-chess numpy
305
+ ```
306
+
307
+ ```python
308
+ import chess
309
+ import numpy as np
310
+ import onnxruntime as ort
311
+
312
+ PIECE = {"P":0,"N":1,"B":2,"R":3,"Q":4,"K":5,
313
+ "p":6,"n":7,"b":8,"r":9,"q":10,"k":11}
314
+
315
+ def fen_to_planes(fen):
316
+ planes = np.zeros((18, 8, 8), dtype=np.float32)
317
+ parts = fen.split()
318
+ board, turn, castling, ep = parts[0], parts[1], parts[2], parts[3]
319
+ for ri, rank_str in enumerate(board.split("/")):
320
+ rank_idx, file_idx = 7 - ri, 0
321
+ for ch in rank_str:
322
+ if ch.isdigit():
323
+ file_idx += int(ch)
324
+ else:
325
+ planes[PIECE[ch], rank_idx, file_idx] = 1.0
326
+ file_idx += 1
327
+ if turn == "w": planes[12].fill(1.0)
328
+ if "K" in castling: planes[13].fill(1.0)
329
+ if "Q" in castling: planes[14].fill(1.0)
330
+ if "k" in castling: planes[15].fill(1.0)
331
+ if "q" in castling: planes[16].fill(1.0)
332
+ if ep != "-" and len(ep) == 2:
333
+ planes[17, 0, ord(ep[0]) - ord("a")] = 1.0
334
+ return planes
335
+
336
+ session = ort.InferenceSession("nova.onnx",
337
+ providers=["CPUExecutionProvider"])
338
+
339
+ board = chess.Board()
340
+ positions = fen_to_planes(board.fen())[np.newaxis]
341
+ # rating=1600, neutral classical + aggression
342
+ conditioning = np.array([[(1600 - 800) / (2700 - 800), 0.5, 0.5]],
343
+ dtype=np.float32)
344
+ logits = session.run(None, {"positions": positions,
345
+ "conditioning": conditioning})[0][0]
346
+
347
+ # Mask illegals + softmax
348
+ legal = np.zeros(16384, dtype=bool)
349
+ for mv in board.legal_moves:
350
+ idx = mv.from_square * 64 + mv.to_square
351
+ if mv.promotion == chess.KNIGHT: idx += 4096
352
+ elif mv.promotion == chess.BISHOP: idx += 4096 * 2
353
+ elif mv.promotion == chess.ROOK: idx += 4096 * 3
354
+ legal[idx] = True
355
+ masked = np.where(legal, logits, -1e9)
356
+ probs = np.exp(masked - masked.max())
357
+ probs *= legal
358
+ probs /= probs.sum()
359
+
360
+ top = np.argsort(probs)[::-1][:5]
361
+ for i in top:
362
+ print(f" index {int(i):5d} p = {probs[i]*100:.2f}%")
363
+ ```
364
+
365
+ For production deployment notes (multi-worker setup, rate limiting,
366
+ temperature schedules, observability), see `docs/serving.md` in the
367
+ GitHub repository.
368
+
369
+
370
+ ## Citation
371
+
372
+ ```
373
+ Nova Chess Engine. Nova Chess, 2026.
374
+ https://github.com/novachessai/novachess-engine
375
+ https://huggingface.co/novachess/novachess-engine
376
+ ```
377
+
378
+ BibTeX:
379
+
380
+ ```bibtex
381
+ @misc{novachess_2026,
382
+ title = {Nova Chess Engine},
383
+ author = {Nova Chess},
384
+ year = {2026},
385
+ url = {https://github.com/novachessai/novachess-engine}
386
+ }
387
+ ```
388
+
389
+
390
+ ## Acknowledgments
391
+
392
+ Nova builds on prior work in human-move prediction. The evaluation
393
+ methodology (rating-band stratification, tier definitions, ply-based
394
+ filters, Lichess rapid data) follows conventions established by the
395
+ Maia project.
396
+
397
+ - Maia-1 — McIlroy-Young, Sen, Kleinberg & Anderson, *Aligning
398
+ Superhuman AI with Human Behavior: Chess as a Model System*,
399
+ KDD 2020. [arXiv:2006.01855](https://arxiv.org/abs/2006.01855)
400
+ - Maia-2 — Tang, Jiao, McIlroy-Young, Kleinberg, Sen & Anderson,
401
+ *Maia-2: A Unified Model for Human-AI Alignment in Chess*,
402
+ NeurIPS 2024. [arXiv:2409.20553](https://arxiv.org/abs/2409.20553)
403
+ - Maia-3 — Maia project, https://maiachess.com. The specific
404
+ checkpoint evaluated here is `maia3_simplified.onnx` published there.
405
+ - Allie — Khoshneviszadeh, Chi, Sheller et al., *Allie: Emergent
406
+ Human-Like Play Through Adaptive MCTS with a Decoder-Only
407
+ Transformer*, ICLR 2025.
408
+ [arXiv:2410.03893](https://arxiv.org/abs/2410.03893)
409
+
410
+
411
+ ## Contact
412
+
413
+ - Product website: <https://novachess.ai>
414
+ - GitHub issues: <https://github.com/novachessai/novachess-engine/issues>
415
+ - Commercial licensing inquiries: support@novachess.ai
maia2_600k.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b02202afcddd69889705634eb6e69d1e6ae0994b523772eedfdb69db3cac0c0b
3
+ size 157272872
maia3_600k.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8db1bef2246c8066aee12096bcfc7da3fc6e3326badbd88567e4577fb14493ef
3
+ size 177109192
nova.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c2256701b1fe1d8d6a909e8c9d4765d5e034d11d75c805df4900647dc2c16422
3
+ size 1252431
nova.onnx.data ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:92688b422b18ba5b311b6cd42a5578bdbf2803a3c79d594d4544fe346d219086
3
+ size 398393344
nova.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0b1d9f38a2d02d1d427e271df0d892ac762c617c4da7adf75cdc277a074813f0
3
+ size 1195390823
nova_actual_600k.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:907d38220b0176b3810139b5cad80ad1cbbeb4c2de3f39e3bf4ddd8b8fec4780
3
+ size 174083528
nova_neutral_600k.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7a3dd2bc3f4bd70bd33f8adefe23931a46bb0a8f1ff2745411b19504c751dfab
3
+ size 174083530
unified_sample_600k.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f2c658157c2432b03fffb6fef6ad4da4f0c8191e29e65cc0a7c06c5d8f96b6a9
3
+ size 90064441