# EUDAMED Scraper & Change Monitor (EU MDR/IVDR) (`yuancore/eudamed-device-monitor`) Actor

Export the EU EUDAMED medical device database (MDR/IVDR) to JSON/CSV/Excel and schedule daily change-monitoring of new registrations, status & certificate changes by manufacturer, SRN, UDI or risk class. Public data; not affiliated with the European Commission.

- **URL**: https://apify.com/yuancore/eudamed-device-monitor.md
- **Developed by:** [YuanCore](https://apify.com/yuancore) (community)
- **Categories:** Developer tools, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 12.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## EUDAMED Scraper & Change Monitor (EU MDR/IVDR)

Search, export and **monitor changes** in the EU **EUDAMED** public medical-devices database — the official European Commission registry for devices placed on the EU market under MDR (2017/745) and IVDR (2017/746). Export to **JSON / CSV / Excel**.

There is **no public bulk export** of other companies' devices in the official UI — you read it one row at a time. This actor turns the public registry into clean, structured, schedulable data, and (uniquely) lets you watch for **changes** instead of re-pulling everything.

### ⭐ Primary use — daily change monitoring

Set `monitorSince` to an ISO date and **schedule the actor daily**: it returns only devices whose `lastUpdateDate` is on/after that date — a lightweight change feed. Ideal for RA/QA and competitive-intelligence teams tracking newly registered or updated devices ahead of the MDR/IVDR registration waves (mandatory EUDAMED use lands **28 May 2026**).

This is the cheap, fast, intended mode. Use it instead of repeatedly dumping the whole database.

### Bulk / search pull (one-off)

Set filters in `searchParams` and a `maxItems` cap to pull a slice. ⚠️ **A full pull is ~2.5M devices and takes roughly 1.5–3 hours and significant compute** — only do it when you genuinely need a one-off export, and prefer narrowing with `searchParams`.

### What you get per device

`basicUdi`, `primaryDi`, `uuid`, `deviceName`, `tradeName`, `deviceModel`, `riskClass`, `manufacturerName`, `manufacturerSrn`, `deviceStatusType`, `applicableLegislation`, `sterile`, `multiComponent`, `issuingAgency`, `containerPackageCount`, `lastUpdateDate`, version info. Enable **Fetch full device detail** for the deep per-device record (EMDN, certificates, etc.).

### Who it's for

- **Regulatory Affairs / QA** — monitor competitor registrations, certificate and status changes.
- **Medical-device market intelligence** — map manufacturers, risk classes and EMDN categories across the EU.
- **Compliance / due-diligence** — verify a manufacturer's EUDAMED footprint.

### Input

| field | meaning |
|---|---|
| `monitorSince` | ISO date (YYYY-MM-DD) — only devices updated on/after it (the change feed). **Recommended.** |
| `searchParams` | extra EUDAMED API filter params (object), e.g. by status; leave `{}` for all |
| `maxItems` | stop after N devices. ⚠️ a full pull is ~2.5M ≈ 1.5–3h |
| `pageSize` | API page size (`size`), max 300 |
| `fetchDetails` | also pull the deep per-device detail record. ⚠️ **+1 API call per device — keep `maxItems` low (≤500) when on** |
| `includePersonalData` | include the authorised-representative name field. **Off by default (redacted)** — see Data & compliance |
| `languageIso2Code` | response language, default `en` |

### Reliability

- **Schema-drift guard** — if EUDAMED changes its API shape (or an unfiltered pull comes back empty), the run **fails loudly** instead of silently producing an empty/garbage dataset.
- **De-duplication** within a run; identity-less records are never folded together.
- **Core-field completeness** is tracked each run and warns if it collapses (a silent-corruption signal).
- An automated read-back test (`npm test`) asserts the above against the live API.

### Data & compliance

- Source is the **public** EUDAMED API (`ec.europa.eu/tools/eudamed`) — no login; public EU transparency data.
- Reused under the European Commission reuse policy (**CC BY 4.0**); attribute *European Commission – EUDAMED*. Data is **structured/normalized** by this actor.
- **Company-level data.** The authorised-representative name can identify a natural person, so it is **redacted by default**; enable `includePersonalData` only with a lawful basis. Users are responsible for GDPR-compliant use.
- **Not affiliated with the European Commission.** No warranty on accuracy/completeness; verify against the official source before relying on it for decisions.
- Polite pacing built in.

### FAQ

#### Is there an official EUDAMED API for downloading device data?
Not for *reading other companies' devices in bulk*. The European Commission exposes a restricted **machine-to-machine (M2M) API**, but it requires official registration through a national authority and is designed for **submitting your own** UDI/device data into EUDAMED — not for pulling the whole public registry out. The public **search UI** at `ec.europa.eu/tools/eudamed` is backed by undocumented JSON endpoints (e.g. `/api/devices/udiDiData`), but there is **no supported public bulk export**, no official CSV/Excel "download all," and no documented change feed. This actor reads only those **public, no-auth** endpoints and turns them into clean, schedulable, structured output. *Not affiliated with the European Commission.*

#### How do I export EUDAMED to Excel or CSV?
The official UI has no usable bulk "export to Excel/CSV" of the public registry — you read results one page at a time, and the Excel templates you find online are for **uploading your own data into EUDAMED**, not exporting other manufacturers' records. With this actor you run a search (or a `monitorSince` change pull), then on the **Storage / Dataset** tab click **Export** and pick **CSV**, **Excel (XLSX)**, **JSON**, or **HTML** — or fetch the dataset via Apify's API. Tip: narrow with `searchParams` and cap with `maxItems` first, because a full registry pull is ~2.5M devices and takes hours.

#### Can I monitor competitor registrations or status changes?
Yes — that's the headline mode. Set **`monitorSince`** to an ISO date and **schedule the actor daily**: it returns only devices whose `lastUpdateDate` is on/after that date — a lightweight diff feed of newly registered or updated devices. Combine it with `searchParams` (e.g. a manufacturer SRN, risk class, or device status) to watch a specific competitor, product family, or category. It's especially relevant in 2026: under **Commission Decision (EU) 2025/2371**, the first EUDAMED modules become **mandatory on 28 May 2026**, and legacy devices must be registered by **28 November 2026** — a sustained registration wave worth watching.

#### Is the data public and GDPR-compliant to use?
The source is the **public** EUDAMED database — no login, EU transparency data, reused under the European Commission reuse policy (CC BY 4.0; attribute *European Commission – EUDAMED*). The output is **company-level** (manufacturer, SRN, UDI, risk class, status). The one field that can identify a natural person — the **authorised-representative name** — is **redacted by default**; enable `includePersonalData` only if you have a lawful basis. You remain the controller for your downstream use. *Not affiliated with the European Commission; verify against the official source before relying on it for regulatory decisions.*

#### How fresh is this data?
EUDAMED is updated continuously as manufacturers and authorised representatives register and amend records. This actor reads the live public API at run time, so a scheduled daily run with `monitorSince` set to "yesterday" gives you a same-day view of what changed. Each output row carries `lastUpdateDate` (from EUDAMED) and `scrapedAt` (when this actor read it) so you can audit freshness.

### EUDAMED website vs this actor

| | Manual EUDAMED search (official UI) | This actor |
|---|---|---|
| **Bulk export** | None — read one page at a time | One run → CSV / Excel / JSON / HTML |
| **Change monitoring** | Not available — re-check manually | `monitorSince` returns only devices updated on/after a date; schedule daily |
| **Speed** | Searches commonly take 10–20s; each page = a new search | Paged API pulls, de-duplicated, structured |
| **Filtering** | Basic UI filters | `searchParams` passed straight to the EUDAMED API (status, class, SRN, etc.) |
| **Scheduling / automation** | Manual, browser-only | Apify Schedules + API/webhooks; pay-per-usage |
| **Structured output** | Copy/paste from the page | Normalized fields per device (`basicUdi`, `primaryDi`, `riskClass`, `manufacturerSrn`, `lastUpdateDate`, …) |
| **PII handling** | Names shown in UI | Authorised-rep name **redacted by default** (GDPR) |
| **Reliability** | You eyeball it | Schema-drift guard fails loudly on API shape changes / empty pulls; completeness tracked per run |

*Public data only; not affiliated with the European Commission. A full registry pull is ~2.5M devices (hours of compute) — prefer `monitorSince` + `searchParams`.*

# Actor input Schema

## `searchParams` (type: `object`):

Extra query params passed straight to the EUDAMED public API to filter results (e.g. {"deviceStatusCode":"refdata.device-model-status.on-the-market"}). Leave empty {} to list everything.
## `maxItems` (type: `integer`):

Stop after this many devices. ⚠️ EUDAMED holds ~2.5M — a FULL pull takes ~1.5-3h and consumes significant compute. The intended use is daily incremental monitoring via 'monitorSince', not repeated full dumps. Keep this modest unless you really need a one-off bulk export.
## `pageSize` (type: `integer`):

Devices fetched per API request (the EUDAMED 'size' param, max 300). Larger = fewer requests. Leave at the default unless tuning throughput.
## `fetchDetails` (type: `boolean`):

Also call the per-device detail endpoint (deep fields). ⚠️ Adds 1 API call PER device — keep maxItems low (e.g. ≤500) when enabled, or runs get very slow/expensive. Off by default.
## `includePersonalData` (type: `boolean`):

EUDAMED is public company-level data, but the authorised-representative field can hold an individual's name. Off by default = redacted. Enable only if you have a lawful basis to process it.
## `monitorSince` (type: `string`):

ISO date (YYYY-MM-DD). Only returns devices whose lastUpdateDate is on/after this — schedule daily for change feeds.
## `languageIso2Code` (type: `string`):

ISO 639-1 language code for EUDAMED reference-data labels in the response (e.g. 'en', 'de', 'fr'). Default 'en'.

## Actor input object example

```json
{
  "searchParams": {},
  "maxItems": 1000,
  "pageSize": 100,
  "fetchDetails": false,
  "includePersonalData": false,
  "languageIso2Code": "en"
}
````

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("yuancore/eudamed-device-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("yuancore/eudamed-device-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call yuancore/eudamed-device-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=yuancore/eudamed-device-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "EUDAMED Scraper & Change Monitor (EU MDR/IVDR)",
        "description": "Export the EU EUDAMED medical device database (MDR/IVDR) to JSON/CSV/Excel and schedule daily change-monitoring of new registrations, status & certificate changes by manufacturer, SRN, UDI or risk class. Public data; not affiliated with the European Commission.",
        "version": "0.1",
        "x-build-id": "YqJeEosBTgnL5LwFM"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/yuancore~eudamed-device-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-yuancore-eudamed-device-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/yuancore~eudamed-device-monitor/runs": {
            "post": {
                "operationId": "runs-sync-yuancore-eudamed-device-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/yuancore~eudamed-device-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-yuancore-eudamed-device-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchParams": {
                        "title": "EUDAMED filter params (advanced)",
                        "type": "object",
                        "description": "Extra query params passed straight to the EUDAMED public API to filter results (e.g. {\"deviceStatusCode\":\"refdata.device-model-status.on-the-market\"}). Leave empty {} to list everything.",
                        "default": {}
                    },
                    "maxItems": {
                        "title": "Max devices to fetch",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Stop after this many devices. ⚠️ EUDAMED holds ~2.5M — a FULL pull takes ~1.5-3h and consumes significant compute. The intended use is daily incremental monitoring via 'monitorSince', not repeated full dumps. Keep this modest unless you really need a one-off bulk export.",
                        "default": 1000
                    },
                    "pageSize": {
                        "title": "Page size (API 'size', max 300)",
                        "minimum": 1,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Devices fetched per API request (the EUDAMED 'size' param, max 300). Larger = fewer requests. Leave at the default unless tuning throughput.",
                        "default": 100
                    },
                    "fetchDetails": {
                        "title": "Fetch full device detail per record (slower)",
                        "type": "boolean",
                        "description": "Also call the per-device detail endpoint (deep fields). ⚠️ Adds 1 API call PER device — keep maxItems low (e.g. ≤500) when enabled, or runs get very slow/expensive. Off by default.",
                        "default": false
                    },
                    "includePersonalData": {
                        "title": "Include personal-name fields (GDPR)",
                        "type": "boolean",
                        "description": "EUDAMED is public company-level data, but the authorised-representative field can hold an individual's name. Off by default = redacted. Enable only if you have a lawful basis to process it.",
                        "default": false
                    },
                    "monitorSince": {
                        "title": "Change-monitoring: only devices updated on/after this date",
                        "type": "string",
                        "description": "ISO date (YYYY-MM-DD). Only returns devices whose lastUpdateDate is on/after this — schedule daily for change feeds."
                    },
                    "languageIso2Code": {
                        "title": "Language",
                        "type": "string",
                        "description": "ISO 639-1 language code for EUDAMED reference-data labels in the response (e.g. 'en', 'de', 'fr'). Default 'en'.",
                        "default": "en"
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
