Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
157ed26
fix(streaming): request usage in SSE streams (include_usage)
devswha Jul 24, 2026
afde4e6
Merge branch 'bot/stream-usage-capture' into dev
devswha Jul 24, 2026
6120e9e
ops(g002): first measured PAY-B-COST bundle — margin gate refuses as …
devswha Jul 24, 2026
dcfc368
feat(llm): native Anthropic adapter with prompt caching (opt-in)
devswha Jul 24, 2026
2c084b1
Merge branch 'bot/anthropic-native-cache' into dev
devswha Jul 24, 2026
c199f13
feat(llm): thinking control (default on) + G002 usage adapter v2 + ca…
devswha Jul 24, 2026
37eb11c
Merge branch 'bot/native-thinking-control' into dev
devswha Jul 24, 2026
3450a96
fix(types): document env param on buildNativeBody — unbreaks tsc lint…
devswha Jul 24, 2026
31048fb
feat(quality): fixed-judge override for live-quality scoring
devswha Jul 24, 2026
4aa0e43
Merge branch 'bot/live-quality-fixed-judge' into dev
devswha Jul 24, 2026
48dcd98
feat(quality): per-call usage/latency capture for live-quality cost a…
devswha Jul 24, 2026
2c79f5d
Merge branch 'bot/live-quality-usage-capture' into dev
devswha Jul 24, 2026
4f8cd15
feat(quality): subscription CLI backend as fixed judge (--judge-backend)
devswha Jul 24, 2026
33eff57
Merge branch 'bot/live-quality-judge-backend' into dev
devswha Jul 24, 2026
34ce4d2
fix(backends): kimi-cli compatibility with Kimi Code >= 0.28
devswha Jul 25, 2026
07c3cdf
fix(quality): sequential scoring for CLI-backend judges
devswha Jul 25, 2026
11fab7d
Merge branch 'bot/kimi-cli-0.28-compat' into dev
devswha Jul 25, 2026
8afb87b
docs(env): replace retired OpenClaw/Discord harness block with real p…
devswha Jul 25, 2026
f529215
Merge branch 'bot/env-example-provider-docs' into dev
devswha Jul 25, 2026
0b6ac09
feat(quality): provider reasoning control via extraBody pass-through
devswha Jul 25, 2026
39816c4
Merge branch 'bot/judge-extra-body' into dev
devswha Jul 25, 2026
ea92b9c
research(judges): challenger round — gemini-3.6-flash PASSes, non-rea…
devswha Jul 25, 2026
c446b20
Merge branch 'bot/judge-calibration-challengers' into dev
devswha Jul 25, 2026
d56203f
research(judges): confound separated — reasoning is not required, tie…
devswha Jul 25, 2026
f6c1349
docs(judges): flag the moving-alias risk and measured cost of the 5.3…
devswha Jul 25, 2026
e9ab593
ops(cost): measured prompt-cache economics and serving-engine comparison
devswha Jul 25, 2026
ee871ee
Merge branch 'bot/cache-economics' into dev
devswha Jul 25, 2026
8ffb920
feat(web): allowlist gemini-3.6-flash and restore the frozen v6.4 hold
devswha Jul 26, 2026
c039186
Merge branch 'bot/gemini36-allowlist' into dev
devswha Jul 26, 2026
4653c1b
feat(serving): default both tiers to gemini-3.6-flash; record the reg…
devswha Jul 26, 2026
2a671a2
Merge branch 'bot/gemini-default-and-register-handoff' into dev
devswha Jul 26, 2026
2c0a341
ops(quality): confirm the fidelity rubric bug with live production ev…
devswha Jul 27, 2026
12a1822
Merge branch 'bot/fidelity-bug-evidence' into dev
devswha Jul 27, 2026
d6f9a2c
fix(scoring): stop the fidelity gate from punishing the rewrite it ex…
devswha Jul 27, 2026
48a12b0
Merge branch 'bot/fidelity-rubric-fix' into dev
devswha Jul 27, 2026
c1d5678
fix(backends): disable MCP servers on gemini-cli invocations
devswha Jul 27, 2026
e08d2ad
Merge branch 'bot/gemini-cli-no-mcp' into dev
devswha Jul 27, 2026
c5cf088
ops(quality): remeasure after the fidelity fix — 9/22 to 17/22, regis…
devswha Jul 27, 2026
ca8b5ca
Merge branch 'bot/post-fix-remeasure' into dev
devswha Jul 27, 2026
5d9a39c
feat(quality): run the rewrite side on a subscription seat too (--bac…
devswha Jul 27, 2026
da5135c
Merge branch 'bot/candidate-backend' into dev
devswha Jul 27, 2026
0b615ff
research(judges): verify a judge actually grades meaning, not just AI…
devswha Jul 27, 2026
3ef7983
research(judges): record the first rubric-check results — a high AUC …
devswha Jul 27, 2026
0b98ef6
Merge branch 'bot/judge-rubric-check' into dev
devswha Jul 27, 2026
9c93161
fix(quality): harness was measuring a prompt neither surface ships
devswha Jul 27, 2026
1b8b674
Merge branch 'bot/harness-persona-parity' into dev
devswha Jul 27, 2026
c245640
ops(quality): 22-fixture remeasure after prompt parity — 9/22 to 20/22
devswha Jul 27, 2026
c3fe618
Merge branch 'bot/parity-remeasure' into dev
devswha Jul 27, 2026
a1f5c87
ops(engines): rerun the shipped engine decision on the fixed apparatus
devswha Jul 27, 2026
e054c53
Merge branch 'bot/engine-rematch' into dev
devswha Jul 27, 2026
90f52ee
ops(engines): close the cheaper-engine search — $0.030 is the floor
devswha Jul 27, 2026
d33a8b7
Merge branch 'bot/candidate-rerun-close' into dev
devswha Jul 27, 2026
7f07c50
fix(prompt): forbid inventing claims the source does not state
devswha Jul 28, 2026
2c9ef04
feat(quality): --repeat so a sweep can distinguish signal from variance
devswha Jul 28, 2026
dd60b01
Merge branch 'bot/no-fabrication-rule' into dev
devswha Jul 28, 2026
89a2f1c
feat(monitor): watch the tier that actually has users
devswha Jul 28, 2026
e520253
Merge branch 'bot/free-tier-monitor' into dev
devswha Jul 28, 2026
83c2221
fix(meaning-proxy): claim clock times instead of 422-blocking chat-lo…
devswha Jul 29, 2026
df7fa12
Merge branch 'bot/clock-time-number-safety' into dev
devswha Jul 29, 2026
3ebc61e
fix(playground): visually hide the approval status line, keep it for …
devswha Jul 29, 2026
c00a175
Merge branch 'bot/hide-output-status-visually' into dev
devswha Jul 29, 2026
3569534
release: v6.3.2 — version sync, changelog, and v6.4 hold re-freeze
devswha Jul 29, 2026
398acd8
Merge branch 'bot/release-6.3.2' into dev
devswha Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"name": "patina",
"source": "./",
"version": "6.3.1",
"version": "6.3.2",
"description": "Strip the AI packaging, keep the meaning. Detect and rewrite AI writing patterns across KO/EN/ZH/JA with MPS/fidelity checks. Runs the root SKILL.md as the /patina skill.",
"homepage": "https://github.com/devswha/patina",
"repository": "https://github.com/devswha/patina",
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://www.schemastore.org/claude-code-plugin-manifest.json",
"name": "patina",
"version": "6.3.1",
"version": "6.3.2",
"description": "Detect and rewrite AI writing patterns in Korean, English, Chinese, and Japanese so text reads as if a human wrote it. Meaning-preservation (MPS) verified, audit-friendly. The root SKILL.md is loaded as the /patina skill.",
"author": {
"name": "devswha",
Expand Down
101 changes: 63 additions & 38 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
# Local-only runtime / Discord config
# Copy to .env and fill with your own values.

DISCORD_CHANNEL=your-discord-channel-id
DISCORD_GUILD=your-discord-guild-id
DISCORD_ALLOWED_USERS=comma-separated-user-ids

PATINA_AGENT_ID=patina
PLANNER_AGENT_ID=planner
GENERATOR_AGENT_ID=generator
EVALUATOR_AGENT_ID=evaluator

RUNTIME_ENFORCE_ALLOWLIST=true
# ↑ Default flipped to true. Bootstrap will refuse to start unless
# DISCORD_ALLOWED_USERS is set. Set this back to false ONLY if you understand
# that any user who can post in the bound channel can drive the runtime.
PATINA_RUNTIME_CLI=your-runtime-cli-binary

# Optional: override if your old bot token lives elsewhere
# CLAWHIP_CONFIG=/home/you/.clawhip/config.toml
# Optional: direct token override if your runtime does not reuse the migrated bot token
# RUNTIME_DISCORD_TOKEN=

# Optional: isolated marketing bot profile (separate OpenClaw state/config)
# MARKETING_RUNTIME_PROFILE=marketing
# MARKETING_AGENT_ID=patina-marketing
# MARKETING_SOURCE_AGENT_ID=patina
# MARKETING_DISCORD_GUILD=your-discord-guild-id
# MARKETING_DISCORD_CHANNEL=your-marketing-channel-id
# MARKETING_DISCORD_ALLOWED_USERS=comma-separated-user-ids
# MARKETING_DISCORD_TOKEN=
# MARKETING_GATEWAY_PORT=18889
# MARKETING_WORKSPACE=/home/you/.openclaw-marketing/workspace
# MARKETING_ENFORCE_ALLOWLIST=true # default; bootstrap refuses without MARKETING_DISCORD_ALLOWED_USERS
# MARKETING_RESTART_GATEWAY=false
# patina environment reference — copy to .env and fill only what you use.
# .env is gitignored; never commit real values.

# ---------------------------------------------------------------------------
# CLI / local LLM provider keys (openai-http backend, quality:live harness)
# Lookup order: PATINA_API_KEY first, then the provider-specific key
# (src/auth.js HTTP_KEY_ENV_VARS). `--provider <name>` presets live in
# src/providers.js: openai, gemini, groq, kimi, moonshot, together.
# ---------------------------------------------------------------------------
# PATINA_API_KEY= # generic key, wins over provider-specific vars
# OPENAI_API_KEY= # default openai-http backend (gpt-5.5)
# GEMINI_API_KEY= # --provider gemini (gemini-2.5-pro)
# GROQ_API_KEY= # --provider groq
# TOGETHER_API_KEY= # --provider together
# KIMI_API_KEY= # --provider kimi (kimi-k2.5, api.moonshot.ai)
# MOONSHOT_API_KEY= # --provider moonshot (same endpoint as kimi)
# PATINA_API_KEY_FILE= # or read any key from a file (recommended for CI)

# Local subscription CLIs (claude / codex / gemini / kimi) need no key here —
# a logged-in seat is the credential. See also PATINA_LIVE_* and
# PATINA_LIVE_JUDGE_* (fixed-judge scoring) in tests/quality/README.md.

# ---------------------------------------------------------------------------
# Hosted playground / API service (Vercel `/api/rewrite`)
# Server-side only. The browser never sees these. All tiers fail closed:
Expand All @@ -46,9 +33,15 @@ PATINA_RUNTIME_CLI=your-runtime-cli-binary

# Free tier: the service's own provider key (rate-limited by IP) + HMAC secret
# that signs quota/subject KV keys (raw keys/licenses are never stored).
#
# Model choice (owner-approved 2026-07-26): gemini-3.6-flash. The prior default
# gpt-4.1-mini measured an AI-score improvement of only 0.2 across 22 fixtures
# — it returns the input nearly unchanged, so free traffic received no real
# rewrite while still scoring high on meaning preservation. gemini-3.6-flash
# measured 13.0. See docs/operations/serving-engine-cost-20260725.md.
# PATINA_FREE_API_KEY=your-provider-key
# PATINA_FREE_PROVIDER=openai
# PATINA_FREE_MODEL=gpt-4.1-mini
# PATINA_FREE_PROVIDER=gemini
# PATINA_FREE_MODEL=gemini-3.6-flash
# PATINA_QUOTA_HMAC_SECRET=your-long-random-secret

# --- Pro tier ($9.99/mo USD, Lemon Squeezy license-gated) -------------------
Expand All @@ -72,10 +65,42 @@ PATINA_RUNTIME_CLI=your-runtime-cli-binary
# Pro provider/model — REQUIRED in production (missing values fail pro requests
# closed with 503; no silent fallback to the free provider/model). Outside
# production they fall back to PATINA_FREE_PROVIDER/MODEL, then the preset.
# Both must be on the PROVIDER_PRESETS allowlist. Pro ships on Claude Sonnet 5.
# Both must be on the PROVIDER_PRESETS allowlist.
#
# Model choice (owner-approved 2026-07-26; evidence re-established 2026-07-27):
# gemini-3.6-flash, replacing claude-sonnet-5. Rerun on 22 live-quality
# fixtures after fixing a broken fidelity rubric and a harness prompt that
# omitted the persona (docs/operations/serving-engine-cost-20260725.md): the
# two engines both score 20/22 with MPS 90.4 vs 91.5. Quality is level; the
# case is cost and latency — $0.030 vs $0.156 per rewrite, 8.3s vs 27.7s.
# PATINA_PRO_PROVIDER=gemini
# PATINA_PRO_MODEL=gemini-3.6-flash
#
# Previous pin, kept for rollback:
# PATINA_PRO_PROVIDER=claude
# PATINA_PRO_MODEL=claude-sonnet-5

# --- Prompt caching (Anthropic only, opt-in) --------------------------------
# The rewrite prompt is ~99.7% fixed prefix (pattern catalog + profile + voice)
# with only the user text after the data fence, so it caches almost perfectly.
# Anthropic's OpenAI-compat endpoint ignores cache_control, so this flag routes
# paid calls through the native /v1/messages adapter with a cached prefix.
#
# Measured 2026-07-25 (ko web prompt, claude-sonnet-5): 34,254 cacheable prefix
# tokens; second identical call read 34,254/34,254 from cache and halved latency
# (25.2s -> 12.0s). Cost per request: $0.126 uncached, $0.151 on a cache miss
# (+20%, the 5m write surcharge), $0.033 on a hit (-74%).
#
# Break-even hit rate is 21.7%, i.e. roughly 3 requests/hour per language
# variant (the 5-minute ephemeral TTL refreshes on each hit). Below that this
# flag is a ~20% input surcharge; above it, savings approach 74%.
# PATINA_ANTHROPIC_NATIVE_CACHE=1
#
# Thinking stays at the provider default (ON for sonnet-5) because a measured
# A/B showed thinking-off rewrites amputate content. Set to 0 only for
# experiments, never to cut cost on the paid path.
# PATINA_ANTHROPIC_THINKING=1

# Pro limits (per-license). Defaults shown.
# PATINA_PRO_MAX_CHARS=20000
# PATINA_PRO_REQ_PER_DAY=200
Expand Down
2 changes: 1 addition & 1 deletion .patina.default.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "6.3.1"
version: "6.3.2"
language: ko # Korean (default) -- auto-loads all ko-*.md patterns
# language: en -- English -- auto-loads all en-*.md patterns
# language: zh -- Chinese -- auto-loads all zh-*.md patterns
Expand Down
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@ All notable changes to patina. Dates are release dates (YYYY-MM-DD).
Semver rationale: patch | minor | major — explain whether this changes patterns, schemas, CLI behavior, or docs only.
```

## 6.3.2 — 2026-07-29

**Hosted-rewrite fixes (chat-log pastes no longer 422), a fidelity-gate scoring fix, backend compatibility, and opt-in LLM plumbing. 6.4 stays reserved for the payment launch.**

Semver rationale: patch — bug fixes on the hosted rewrite surface, scoring, and CLI backends, plus strictly opt-in or allowlist-only additions; no default contract, tier limit, or pinned model changes. The v6.4 payment-launch hold (tag/publish prohibitions for 6.4.x) is untouched.

### Fixed

- **Chat-log/timeline pastes no longer fail the web rewrite**: clock times (`16:47`, `16:47 – 16:50`, `9:05:30`) hit the numeric-operator check as `digit:digit`, so the number-safety gate 422-rejected the whole paste before scoring — even for an identity rewrite — and the playground showed a misleading generic "check the mode/key" failure. Clock times are now first-class exact `time:` claims (leading-zero hour normalized); a rewrite that drops or drifts a time still fails closed as `numeric_claim_changed`, and ratios/scores (`1:2`, `3:1`) plus invalid times (`25:30`) keep the old fail-closed behavior. `number_safety_failed` also gets its own localized (en/ko/zh/ja) error copy in the playground.
- **Fidelity gate no longer punishes the rewrite it exists to grade**: the fidelity judge rubric penalized register normalization that the rewrite prompt itself mandates; live-quality fixtures went from 9/22 to 20/22 after the rubric fix plus prompt parity between the CLI and web surfaces.
- **Rewrite prompt forbids invented claims**: the strict rewrite prompt now explicitly prohibits adding claims the source does not state, closing a fabrication path the meaning floors could only catch after the fact.
- **`gemini-cli` backend disables MCP servers** on its invocations, so a user's local MCP config can never inject tools into a patina rewrite call.
- **`kimi-cli` ≥ 0.28 compatibility**: the backend now parses the stream-json assistant output of newer Kimi Code releases (with the legacy plain-text fallback retained).
- **SSE streams request usage accounting** (`include_usage`), so streamed rewrites report token usage like buffered calls.
- **Playground approval status line is screen-reader-only**: the visible "Unapproved — checks have not passed" line under every streaming message read as an alarming warning during normal in-flight rewrites; it is now visually clipped while the `role="status"` live region and localized copy stay intact for assistive tech.

### Added

- **`gemini-3.6-flash` allowlisted** on the web BYOK surface and eligible for `PATINA_FREE_MODEL` / `PATINA_PRO_MODEL`, after a 22-fixture live-quality comparison (better AI-score improvement and fewer meaning-loss fixtures than the prior Pro pin at ~1/5 the cost). All pinned defaults are unchanged; this only widens the allowlist.
- **Native Anthropic adapter with prompt caching (opt-in)** plus thinking control for OpenAI-compatible providers via `extraBody` pass-through — both dormant unless explicitly enabled.
- **Free-tier observability**: the pro monitor now also watches the free tier (the tier that actually has users), with the same closed outcome schema.
- **Live-quality harness upgrades** (dev tooling): fixed-judge override, `--judge-backend` / `--backend` subscription-CLI seats, per-call usage/latency capture, and `--repeat` for variance-aware sweeps.

## 6.3.1 — 2026-07-07

**Launch polish for the hosted playground and README — no CLI/engine changes.**
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<a href="https://opensource.org/licenses/MIT"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg"></a>
<a href="#quick-start"><img alt="Skill: Claude Code | Codex | Cursor | OpenCode" src="https://img.shields.io/badge/Skill-Claude%20Code%20%7C%20Codex%20%7C%20Cursor%20%7C%20OpenCode-blueviolet"></a>
<a href="https://github.com/devswha/patina"><img alt="Languages: KO | EN | ZH | JA" src="https://img.shields.io/badge/Languages-KO%20%7C%20EN%20%7C%20ZH%20%7C%20JA-green"></a>
<a href="CHANGELOG.md"><img alt="Version 6.3.1" src="https://img.shields.io/badge/version-6.3.1-blue"></a>
<a href="CHANGELOG.md"><img alt="Version 6.3.2" src="https://img.shields.io/badge/version-6.3.2-blue"></a>
</p>

<p align="center">
Expand Down Expand Up @@ -204,7 +204,7 @@ If meaning drifts, the change is retried or rolled back. Deterministic analysis

```yaml
# .patina.default.yaml
version: "6.3.1"
version: "6.3.2"
language: ko # ko | en | zh | ja
profile: default
output: rewrite # rewrite | diff | audit | score
Expand Down
4 changes: 2 additions & 2 deletions README_JA.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Skill](https://img.shields.io/badge/Skill-Claude%20Code%20%7C%20Codex%20%7C%20Cursor%20%7C%20OpenCode-blueviolet)](#クイックスタート)
[![Multi-language](https://img.shields.io/badge/Languages-KO%20%7C%20EN%20%7C%20ZH%20%7C%20JA-green)](https://github.com/devswha/patina)
[![Version](https://img.shields.io/badge/version-6.3.1-blue)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-6.3.2-blue)](CHANGELOG.md)

> **AIっぽさだけを落として、意味はそのまま。**

Expand Down Expand Up @@ -186,7 +186,7 @@ Input

```yaml
# .patina.default.yaml
version: "6.3.1"
version: "6.3.2"
language: ko # ko | en | zh | ja
profile: default
output: rewrite # rewrite | diff | audit | score
Expand Down
4 changes: 2 additions & 2 deletions README_KR.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Skill](https://img.shields.io/badge/Skill-Claude%20Code%20%7C%20Codex%20%7C%20Cursor%20%7C%20OpenCode-blueviolet)](#빠른-시작)
[![Multi-language](https://img.shields.io/badge/Languages-KO%20%7C%20EN%20%7C%20ZH%20%7C%20JA-green)](https://github.com/devswha/patina)
[![Version](https://img.shields.io/badge/version-6.3.1-blue)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-6.3.2-blue)](CHANGELOG.md)

<p align="center">
<a href="https://patina.vibetip.help/"><b>브라우저에서 바로 써보기 — 설치 없음</b></a>
Expand Down Expand Up @@ -186,7 +186,7 @@ Input

```yaml
# .patina.default.yaml
version: "6.3.1"
version: "6.3.2"
language: ko # ko | en | zh | ja
profile: default
output: rewrite # rewrite | diff | audit | score
Expand Down
4 changes: 2 additions & 2 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Skill](https://img.shields.io/badge/Skill-Claude%20Code%20%7C%20Codex%20%7C%20Cursor%20%7C%20OpenCode-blueviolet)](#快速开始)
[![Multi-language](https://img.shields.io/badge/Languages-KO%20%7C%20EN%20%7C%20ZH%20%7C%20JA-green)](https://github.com/devswha/patina)
[![Version](https://img.shields.io/badge/version-6.3.1-blue)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-6.3.2-blue)](CHANGELOG.md)

<p align="center">
<strong>去掉 AI 味,保留原意。</strong>
Expand Down Expand Up @@ -188,7 +188,7 @@ Input

```yaml
# .patina.default.yaml
version: "6.3.1"
version: "6.3.2"
language: ko # ko | en | zh | ja
profile: default
output: rewrite # rewrite | diff | audit | score
Expand Down
2 changes: 1 addition & 1 deletion SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: patina
version: 6.3.1
version: "6.3.2"
description: Detect and rewrite AI writing patterns in Korean, English, Chinese, and Japanese text so it reads as if a human wrote it. Meaning-preservation (MPS) verified.
allowed-tools:
- Read
Expand Down
Loading