**법고개(Bupgogae)**는 대형 언어 모델(LLM)이 생성한 법률 답변 속에서 '존재하지 않는 가짜 판례(Hallucination)'를 실시간으로 탐지하고 검증하는 크롬 확장프로그램입니다.
법률 실무가 AI에 의해 혁신되고 있지만, 거짓된 판례 인용은 치명적인 법적 리스크를 초래할 수 있습니다. 법고개는 변호사가 직접 기획하고 개발하여, 실무진이 안심하고 AI를 활용할 수 있는 환경을 제공합니다.
- 🚦 3단계 실시간 판례 검증 시스템
- 🟢 실존 판례: 공개 판례 DB와 교차 검증된 안전한 판례 (판례일련번호 기반 원문 직접 링크)
- 🟠 의심 판례: 사건번호 형식은 맞으나 DB에서 확인되지 않는 판례 (사법정보공개포털 검증 유도)
- 🔴 형식 오류: 미래 연도, 법원(1945년)·헌법재판소(1988년) 설립 이전 등 명백한 AI 환각 지적
- 🌐 멀티 LLM 플랫폼 지원 (어댑터 패턴 적용)
- ChatGPT (
chatgpt.com) - Claude (
claude.ai) - Google Gemini (
gemini.google.com) - Microsoft Copilot (
copilot.microsoft.com) - Perplexity (
perplexity.ai) - Grok (
grok.com) — 실험적 지원
- ChatGPT (
- 📖 사이드바 판례 원문 뷰어
- 초록색(안전) 배지로 검증된 판례 클릭 시, 화면 이탈 없이 우측 뷰어에서 법제처 원문을 즉시 열람합니다. (Shadow DOM 캡슐화로 호스트 UI와 충돌 방지)
- 📋 미확인 판례 일괄 복사
- 주황색(DB 미확인) 사건번호가 감지되면 안내 배너의 '사건번호 복사' 버튼으로 클립보드에 일괄 복사합니다. 단축키(
Alt+C)도 지원하지만, 일부 서비스가 단축키를 가로채는 경우 버튼이 안정적으로 동작합니다. 팝업에서 안내 배너 표시 여부를 켜고 끌 수 있습니다.
- 주황색(DB 미확인) 사건번호가 감지되면 안내 배너의 '사건번호 복사' 버튼으로 클립보드에 일괄 복사합니다. 단축키(
- 🔄 원격 설정 자동 업데이트 (Remote Config)
- 각 플랫폼의 DOM 셀렉터가 변경되어 탐지에 실패할 경우, 서버(
adapters.json)에서 최신 셀렉터를 자동으로 가져와 적용합니다. - 기존 어댑터에 내장된(Batteries-included) 셀렉터가 폴백(Fallback)으로 사용되므로, 서버에 접근할 수 없는 오프라인 환경에서도 정상 동작합니다.
- 순수 JSON 데이터만 수신하며 엄격한 CSS 화이트리스트 검증을 거칩니다 (MV3 CSP 준수).
- 각 플랫폼의 DOM 셀렉터가 변경되어 탐지에 실패할 경우, 서버(
- ⚡ 초고속 로컬 매칭
- 수십만 건의 판례 메타데이터를 압축된 JSON 형태로 로컬 IndexedDB에 동기화하여, 외부 API 통신 지연 없이 즉각적으로 판별합니다.
- 🔒 완벽한 프라이버시
- 모든 텍스트 분석과 검증은 브라우저 내부(Local)에서만 이루어지며, 사용자의 대화 내용이나 프롬프트를 외부 서버로 전송하지 않습니다.
방법 1: Chrome 웹 스토어 설치 (권장)
- Chrome 웹 스토어에서 법고개 다운로드 페이지에 접속하여 스토어 버전으로 설치합니다.
방법 2: 개발자 모드 설치 (수동 최신 빌드)
- 이 저장소를 로컬로 Clone 하거나 ZIP 파일로 다운로드합니다.
- 크롬 브라우저에서
chrome://extensions/에 접속합니다. - 우측 상단의 **'개발자 모드'**를 활성화합니다.
- '압축해제된 확장 프로그램을 로드합니다' 버튼을 클릭하고, 다운로드한 폴더 내의
extension/디렉토리를 선택합니다.
nash (개발하는 IP 변호사)
기술과 법률의 경계에서 새로운 가치를 만들어갑니다.
이 프로젝트는 GNU GPLv3 라이선스를 따릅니다.
bupgogae
Copyright 2026 nash-dir
이 소프트웨어의 코드 일부는 LLM 기반 AI 도구(Google Gemini, Anthropic Claude)의
보조를 받아 생성되었습니다. 최종 구현은 저자가 직접 검토, 테스트 및 승인하였습니다.
Bupgogae (법고개) is a Chrome extension that detects and verifies fabricated case law citations (hallucinations) generated by large language models (LLMs) in real time.
While AI is revolutionizing legal practice, fabricated case citations can lead to critical legal risks. Bupgogae is designed and developed by a practicing IP attorney to ensure legal professionals can safely use AI tools.
- 🚦 3-Level Real-Time Case Law Verification
- 🟢 Verified Case: Cross-verified against the public case law database (direct link to original judgment via serial ID)
- 🟠 Unverified Case: Valid case number format, but not found in the database (prompts manual verification)
- 🔴 Format Error: Future dates, or dates before the courts (1945) / Constitutional Court (1988) were established — clear AI hallucinations flagged with strikethrough
- 🌐 Multi-LLM Platform Support (Site Adapter Pattern)
- ChatGPT (
chatgpt.com) - Claude (
claude.ai) - Google Gemini (
gemini.google.com) - Microsoft Copilot (
copilot.microsoft.com) - Perplexity (
perplexity.ai) - Grok (
grok.com) — experimental
- ChatGPT (
- 📖 Built-in Sidebar Viewer
- Click any Green (Verified) badge to instantly view the original case law document from the Ministry of Government Legislation in a sliding sidebar, without leaving the chatbot tab. Uses Shadow DOM to prevent CSS conflicts.
- 📋 Extract Unverified Cases
- When Orange (Unverified) case numbers are detected, copy them all to your clipboard via the "Copy case numbers" button on the notification banner. The
Alt+Cshortcut also works, but the button stays reliable when a site overrides the shortcut. The banner can be toggled on/off from the popup.
- When Orange (Unverified) case numbers are detected, copy them all to your clipboard via the "Copy case numbers" button on the notification banner. The
- 🔄 Remote Config — Dynamic Selector Updates
- When a platform's DOM changes break detection, the extension automatically fetches updated CSS selectors from the server (
adapters.json). - Built-in (batteries-included) selectors serve as a fallback, ensuring full offline functionality when the server is unreachable.
- Only pure JSON data is fetched and validated against a strict CSS whitelist (MV3 CSP compliant).
- When a platform's DOM changes break detection, the extension automatically fetches updated CSS selectors from the server (
- ⚡ Ultra-Fast Local Matching
- Hundreds of thousands of case metadata entries are compressed and synchronized to local IndexedDB, enabling instant verification with zero API latency.
- 🔒 Complete Privacy
- All text analysis and verification happens entirely inside the browser. No conversation content or prompts are ever transmitted to external servers.
Method 1: Chrome Web Store (Recommended)
- Install directly from the Chrome Web Store.
Method 2: Developer Mode (Manual latest build)
- Clone or download this repository.
- Navigate to
chrome://extensions/in Chrome. - Enable Developer Mode in the top right corner.
- Click "Load unpacked" and select the
extension/directory.
This project is licensed under GNU GPLv3.
bupgogae
Copyright 2026 nash-dir
This product includes code that was partially generated with the assistance
of LLM-based AI tools (Google Gemini, Anthropic Claude).
The final implementation was reviewed, tested, and approved by the author.
Defensive Publication Notice (방어적 공개 고지)
This document is a deliberate public disclosure of the technical concepts embodied in this project, first published under GPLv3 on March 22, 2026. The authors intend for this disclosure to constitute prior art under patent law (35 U.S.C. §102; 대한민국 특허법 제29조), thereby preventing any party — including the authors — from obtaining patent protection over the methods described herein.
Each LLM chatbot platform (ChatGPT, Claude, Gemini, Copilot, Perplexity, Grok, etc.) renders AI-generated responses in a unique DOM structure. A browser extension that detects hallucinated citations must navigate these heterogeneous DOMs without coupling its core detection logic to any single platform.
The extension implements a Site Adapter Pattern — a variant of the Strategy pattern — that decouples site-specific DOM traversal from the shared detection pipeline. The architecture consists of:
-
Abstract Base Class (
SiteAdapter): Defines the interface contract:siteId— unique site identifier stringdisplayName— human-readable platform namegetResponseSelectors()— returns an ordered array of CSS selectors targeting AI response containersfindResponseContainers()— executes the selector resolution algorithm (inherited from base class)
-
Concrete Adapters: Each platform has a dedicated adapter (e.g.,
GeminiAdapter,ChatGPTAdapter) that only overridesgetResponseSelectors()with platform-specific CSS selectors. No adapter contains detection logic. -
Hostname-Based Registry: A static
ADAPTER_MAPmaps hostnames to adapter class names. On page load,getAdapter()performs an exact hostname match against the registry and instantiates the corresponding adapter. -
Shared Core Pipeline: Operates identically regardless of which adapter is active:
MutationObserver → settle (process after the response stops mutating)
→ adapter.findResponseContainers() [adapter-specific]
→ collectTextNodes(container) [shared, filters editables]
→ extractCaseNumbers(text) [shared, whitelist regex]
→ validateCaseNumber(parsed) [shared, Red filter cascade]
→ compressCaseKey(parsed) [shared, Hangul→ASCII]
→ chrome.runtime.sendMessage(LOOKUP_BATCH) [shared, IPC to SW]
→ renderPrecedentBadges(textNode) [shared, one-pass: Green/Orange/Red]
Render timing (settle + single-pass). Some platforms (e.g., Gemini, Copilot, Grok) re-render the response subtree while streaming, discarding externally injected badge nodes. To avoid flicker, the pipeline waits for the subtree to go quiet (a settle window) before processing, then renders once. Within a text node, all matches are split and badged in a single pass (
renderPrecedentBadges), so case numbers listed across consecutive lines — which some platforms place in one text node — all appear together instead of one-per-cycle.
The base class findResponseContainers() iterates through the selector array returned by resolveResponseSelectors() in priority order. For each selector, it queries the DOM via document.querySelectorAll(). The first selector that returns any results determines the container set for that scan cycle. This "first-match-wins" design allows adapters to specify increasingly broad fallback selectors without combinatorial explosion.
Each LLM platform's frontend changes frequently, potentially invalidating hardcoded CSS selectors. The extension addresses this through a Remote Config mechanism:
- Service Worker periodically fetches
adapters.jsonfrom the server (alongside the case law DB sync) and stores it inchrome.storage.local resolveResponseSelectors()checks remote config first, falling back to hardcoded selectors:Priority: Remote Config (server) → Hardcoded selectors (adapter class)- Auto-Fetch trigger — if all selectors fail to match any DOM elements, the content script sends a one-time
FETCH_ADAPTERSmessage to the Service Worker (throttled to once per page load to prevent infinite loops) - Security — only pure JSON is fetched and parsed via
res.json(); noeval(),innerHTML, or remote JS execution (MV3 CSP compliant)
This design ensures the extension survives DOM changes without requiring a Chrome Web Store update, while the hardcoded selectors provide offline resilience when the server is unreachable.
The collectTextNodes() function uses a DOM TreeWalker with a custom NodeFilter.acceptNode callback that rejects text nodes whose parent element satisfies any of:
parent.isContentEditable === trueparent.closest('[contenteditable="true"], [contenteditable=""], textarea, [role="textbox"]')returns non-null
This prevents the extension from injecting badges into prompt input areas, ensuring only AI-generated response text is scanned.
┌─────────────────────────────────────────────────────────────┐
│ Core Pipeline (shared) │
│ │
│ MutationObserver → extractCaseNumbers → validate → lookup │
│ → renderBadge │
│ ↑ │
│ findResponseContainers() │
│ (delegated to adapter) │
└──────────────────────────┬──────────────────────────────────┘
│
┌─────────┬─────────┼─────────┬─────────┐
│ │ │ │ │
┌────┴───┐ ┌──┴────┐ ┌──┴────┐ ┌──┴─────┐ ┌─┴──────┐
│ Gemini │ │ChatGPT│ │Claude │ │Copilot │ │Perplex.│ ...
│Adapter │ │Adapter│ │Adapter│ │Adapter │ │Adapter │
└────────┘ └───────┘ └───────┘ └────────┘ └────────┘
Naively querying a database for every potential case number extracted from LLM text incurs unnecessary latency and produces ambiguous results. Many hallucinated citations are structurally impossible — they violate the inherent rules of Korean case number formatting — and can be identified without any database lookup.
The extension implements a Multi-Tier Pre-Database Filtering system — a 4-level validation cascade that classifies each candidate case number before any database query. This produces a 3-class output taxonomy (Red / Orange / Green) that provides graduated confidence signaling to the user.
| Class | Meaning | Determined By |
|---|---|---|
| 🔴 Red (Format Error) | Structurally impossible — definite hallucination | Pre-DB cascade (zero latency) |
| 🟠 Orange (Unverified) | Valid format, not found in database | DB lookup: no match |
| 🟢 Green (Verified) | Confirmed real case | DB lookup: match found |
Before any IndexedDB query, each candidate passes through this cascade in strict order. The first failing check immediately classifies the candidate as Red and halts further processing:
| Level | Check | Rule | Example | Rationale |
|---|---|---|---|---|
| 🔴 L1 | Future year | fullYear > currentYear |
2030다12345 |
No case can exist in the future |
| 🔴 L2 | Pre-establishment | < 1945 (court), < 1988 (헌재) |
1940다100, 1987헌마1 |
Courts established 1945; Constitutional Court 1988 |
| 🔴 L3 | Invalid code | code ∉ validCodes (~159 types) |
2020뿡12345 |
뿡 is not a registered case type |
| 🔴 L4 | Zero serial | parseInt(serial) === 0 |
2020다0 |
Serial numbers are 1-indexed |
Key insight: Red badges with strikethrough appear instantly (zero latency), while Green/Orange classifications require an asynchronous LOOKUP_BATCH IPC round-trip to the Service Worker.
Legacy Korean case numbers use 2-digit years (e.g., 99다카34567). The system expands these relative to the current year with a sliding window (expandTwoDigitYear): a 2-digit year resolves to the most recent past year not exceeding the current year. For example, in 2026: 26 → 2026, 27 → 1927, 99 → 1999, 00 → 2000. This avoids a hardcoded pivot that drifts over time — a fixed 30 pivot would wrongly read 30다1 as 1930 from 2030 onward.
Korean case numbers follow a strict [Year][Code][Serial] structure:
2015 다 6302
──── ── ────
Year Code Serial
4-digit Hangul 1-7 digit
1-4 char
| Component | Rules | Examples |
|---|---|---|
| Year | 4 digits (19xx/20xx), or legacy 2-digit |
2015, 99 |
| Case Code (사건부호) | 1–4 Hangul characters from ~159 valid types | 다, 가합, 다카, 준재가단 |
| Serial | 1–7 digit sequential number | 6302, 215133 |
Challenges making regex design non-trivial:
- No delimiters —
2015다6302has no spaces or punctuation separating components - Variable-length codes — codes range from 1 to 4 Hangul characters (
다vs준재가단) - Legacy 2-digit years —
99다카34567must be disambiguated - Non-court codes — other government agencies (노동위원회, 검찰청, 중재원 etc.) use different case codes that must not be confused with court codes. A whitelist regex (built from
case_code_map) solves this at the extraction stage.
Instead of a broad regex that captures all Hangul combinations and filters afterward, the extension builds a dynamic whitelist regex from the case_code_map at initialization:
Static (fallback): /[가-힣]{1,4}/ ← matches ANY Hangul (high false positives)
Dynamic (primary): /(가합|가단|다|나|마|카|...)/ ← matches ONLY registered codes
Built from case_code_map keys, sorted longest-first
At initMeta(), the extension sorts all ~159 case codes by length (descending) to ensure greedy matching (가합 before 가), then builds a single RegExp:
// Built dynamically from case_code_map keys.
// (?<![0-9]) — left boundary so a run of digits (phone/account numbers)
// isn't mis-split into a bogus 2-digit-year case number.
_courtCaseRegex = new RegExp(
`(?<![0-9])((?:19|20)\\d{2}|\\d{2})(${sortedCodesPattern})(\\d{1,7})`, 'g'
);This whitelist approach eliminates false positives from non-court case codes (e.g., 부해 from labor commissions, 형제 from prosecutors) at the extraction stage, rather than requiring a downstream Red filter. The same dynamic regex also covers Constitutional Court codes (헌가, 헌마, …) since they live in case_code_map. The leading (?<![0-9]) boundary prevents a digit run such as 010-1234-5678도1 or 3015다1234 from being mis-matched as 78도1 / 15다1234.
Analyzing user conversations with AI chatbots is inherently privacy-sensitive. A server-based verification system would require transmitting conversation text — including prompts and responses — to an external API, creating privacy risks, network dependency, and latency.
The extension implements a Zero-Server Architecture where all text analysis, pattern matching, and case law verification occurs entirely within the user's browser. The complete case law database is stored locally in IndexedDB. No conversation data ever leaves the device.
User's Browser (all processing local — no network calls)
┌──────────────────────────────────────────────────────────────────┐
│ │
│ LLM Response Text │
│ │ │
│ ▼ │
│ [Whitelist Regex] case_code_map 기반 동적 정규식 (법원 + 헌재) │
│ │ { year, code, serial, type } │
│ ▼ │
│ [Red Filter Cascade] L1→L2→L3 │
│ │ pass? ──── fail → 🔴 Red badge (instant, zero latency) │
│ ▼ │
│ [Key Compression] "2015다6302" → "15Da6302" │
│ │ ASCII key │
│ ▼ │
│ [LOOKUP_BATCH IPC] Content Script → Service Worker │
│ │ │
│ ▼ │
│ [IndexedDB Query] Single readonly transaction │
│ │ found? ── yes → 🟢 Green badge (+ law.go.kr link) │
│ │ no → 🟠 Orange badge (manual check prompt) │
│ ▼ │
│ [Badge Render] Inline highlight + tooltip with metadata │
│ │
└──────────────────────────────────────────────────────────────────┘
▲ The ONLY network call: periodic db.json.gz download
│ (public case law data only — no user data ever transmitted)
Case numbers are compressed from variable-length Hangul into compact fixed-structure ASCII keys for fast IndexedDB lookups:
Original: 2015다6302 → Compressed: 15Da6302
┌────┐ ┌──┐
Year suffix (2 digits)
┌─┐ ┌──┐
Romanized code (case_code_map)
┌────┐ ┌────┐
Serial (as-is)
The case_code_map maps ~159 Hangul case codes to short romanized abbreviations (~40% reduction in average key length).
Each entry uses positional arrays instead of named fields to minimize JSON overhead:
{
"15Da6302": [[612529, 1, 230101, "양도소득세부과처분취소"]],
"24Du56290": [[612529, 1, 251204, "부당이득금"]]
}| Index | Field | Encoding |
|---|---|---|
[0] |
Serial ID | Numeric → direct law.go.kr link |
[1] |
Court code | Integer → court_code_map reverse lookup |
[2] |
Decision date | YYMMDD compact (6 digits) |
[3] |
Case name | Raw string (plain text) |
Case names are stored as raw strings without tokenization. We evaluated two compression strategies and rejected both:
| Tokens | Strategy | Raw Saved | After gzip | Decode Collisions |
|---|---|---|---|---|
| 34 | Flat | 8.6% | ~0.2 MB | 0 |
| 400 | BPE | 48.0% | ~0.5 MB | 0 |
Decision: Store raw text. gzip (applied by .crx packaging and R2 transfer) already compresses JSON efficiently. The marginal ~0.2–0.5 MB savings do not justify the added encoding complexity, debugging difficulty, or decode overhead.
The only network communication is a periodic download of a static, pre-built database file — no user data, telemetry, or analytics are ever transmitted:
Serverless Pipeline (daily 24:00) Extension
┌──────────────────────────┐ ┌──────────────────────────┐
│ 법제처 API → master.db │ │ Install: load bundled DB │
│ (date-modulus scan) │ │ from extension/data/ │
│ ↓ │ │ ↓ │
│ master.db → db.json.gz │ │ Every 6h: fetch │
│ ↓ │ │ db.json.gz from R2 │
│ Upload to Cloudflare R2 │──────────→ │ ETag 304? skip : replace │
│ ↓ │ │ ↓ │
│ Telegram report │ │ Non-destructive rebuild │
└──────────────────────────┘ └──────────────────────────┘
- Full-DB deploy — one
db.json.gzfile (~3 MB gzip) contains the entire case law database - ETag caching — R2 returns
304 Not Modifiedif unchanged; bandwidth cost is near-zero on most polls - Bundled DB — the full database ships with the extension for instant offline access on first install
- Non-destructive rebuild — on each sync the new keys are inserted over the existing store and only stale keys are pruned, so lookups never observe an empty/partial DB mid-sync (no green→orange flicker during updates)
- Batch lookup — content scripts send all detected case numbers in a single
LOOKUP_BATCHmessage, resolved in one IndexedDB readonly transaction - Adapter Remote Config —
adapters.jsonis fetched alongsidedb.json.gzon every sync cycle, providing up-to-date CSS selectors without extension updates
The backend data pipeline runs as a serverless cron job on GitHub Actions, scheduled daily at 24:00 KST (UTC 15:00):
법제처 Open API ──→ GitHub Actions Runner ──→ Cloudflare R2
(law.go.kr) │ (db.json.gz)
├── master.db (SQLite synced via R2)
├── blacklist.json (326 bad serials)
└── Telegram report
Because GitHub Actions operates in an ephemeral environment, the master.db SQLite state is synchronized using Cloudflare R2 before and after each execution. The script pipeline/sync_state.py handles the boto3 bidirectional state transfer, allowing the crawler to seamlessly continue its modulus queries without losing track of past scanned data.
Instead of scanning all dates daily, the crawler uses a 3-tier modulus strategy to distribute the scanning load:
| Tier | Window | Modulus | Dates/Day |
|---|---|---|---|
| T1 | 1948–1999 | date_offset % 56 |
~366 |
| T2 | 2000–year-before-last | date_offset % 15 |
~609 |
| T3 | Last year–today | Full scan (every day) | ~445 |
This scans ~1,420 dates/day (~21 min) while covering the full historical range every 56 days at most.
The crawler maintains a blacklist.json of 326 known-bad serial numbers (corrupted court names, garbled case numbers from the API). Blacklisted serials are:
- Skipped during UPSERT — prevents bad data from entering master.db
- Pre-seeded with corrections — corrupted records were manually corrected and backfilled via seeddata
Verified case badges link directly to law.go.kr/precInfoP.do?precSeq={serial} — a public URL that requires no API key and navigates directly to the full judgment page.
.github/
└── workflows/
└── daily-pipeline.yml # GHA Serverless Cron Scheduler
extension/
├── background/
│ └── db-sync.js # Service Worker — IndexedDB sync via R2
├── content/
│ ├── adapters/ # Site-specific DOM adapters
│ │ ├── base-adapter.js # SiteAdapter base class
│ │ └── registry.js # Inline adapters & Hostname → adapter mapping
│ ├── case-regex.js # Case number extraction & validation
│ ├── precedent-badge.js # 3-level inline highlight + tooltip
│ ├── sidebar.js # Shadow DOM sidebar for case law documents
│ └── bupgogae-content.js # Main controller (adapter-agnostic)
├── popup/ # Extension popup UI (enable/disable toggle)
├── icons/ # Extension icons (16/48/128 px)
├── data/ # Bundled case law database (140K+ entries)
└── manifest.json # Chrome Extension Manifest V3
pipeline/
├── api.py # 법제처 API client
├── compress.py # SQLite → compressed JSON converter
├── master_db.py # SQLite master DB with blacklist
├── crawler_runner.py # Crawler orchestrator (date-modulus)
├── sync_state.py # Local ↔ R2 serverless state synchronizer
├── upload_r2.py # R2 upload helper
└── blacklist.json # 326 known-bad serial numbers
To add support for a new chatbot in v0.8.0+, you only need to update two files.
- Add the CSS response selectors to
extension/data/adapters.json:
"hosts": {
"newsite.com": "newsite"
},
"adapters": {
"newsite": {
"responseSelectors": [
"[data-role=\"assistant\"] .prose",
".response-container"
]
}
}- Register the boilerplate adapter in
extension/content/adapters/registry.js:
class NewSiteAdapter extends window.bupgogaeAdapters.SiteAdapter {
get siteId() { return 'newsite'; }
get displayName() { return 'New Site AI'; }
}
window.bupgogaeAdapters.NewSiteAdapter = NewSiteAdapter;
const ADAPTER_MAP = {
// ...
'newsite.com': 'NewSiteAdapter',
};