diff --git a/.claude/AGENTS.md b/.claude/AGENTS.md new file mode 100644 index 0000000..c5929e7 --- /dev/null +++ b/.claude/AGENTS.md @@ -0,0 +1,203 @@ +# Agent Roles & Responsibilities + +This file defines cognitive boundaries for multi-agent operation in this repository. +Each agent owns a specific concern. Strict boundaries prevent scope drift and undetected +architecture violations. + +For operating instructions (WORKING.md protocol, skills, commit rules) see [CLAUDE.md](CLAUDE.md). + +--- + +## Agent roster + +| Agent | Owns | Cosmic Python layer | +|---|---|---| +| **Architect** | Layer boundaries and structural integrity | All layers — guards the dependency pyramid | +| **Domain Modeller** | Ubiquitous language and domain correctness | `models/` | +| **Implementer** | Feature delivery and test coverage | `services/` · `adapters/` · `entrypoints/` | +| **Reviewer** | Defect detection and boundary verification | All layers — read-only | + +--- + +## 1. Architect Agent + +**Owns** +- Clean Architecture boundary enforcement (`entrypoints → services → models`, `adapters → models`) +- Aggregate and bounded-context definitions +- Structural refactor approval +- ADR-lite decision records in `docs/architecture/` + +**Does NOT** +- Write production feature logic +- Modify infrastructure without architectural justification +- Approve changes that leak I/O into `models/` + +**Triggered when** +- A new aggregate or bounded context is introduced +- A cross-layer refactor is proposed +- Infrastructure concerns appear inside `models/` or `services/` +- A task spans multiple layers or sub-modules + +--- + +## 2. Domain Modeller Agent + +**Owns** +- Ubiquitous language alignment (names match the ERS–ERE contract) +- Entity and Value Object design in `models/` +- Explicit domain invariants +- Test naming in domain language + +**Does NOT** +- Choose infrastructure or transport technologies +- Optimise performance prematurely +- Introduce framework dependencies into `models/` + +**Triggered when** +- A new domain concept is introduced or renamed +- An invariant is unclear or missing +- Test names drift from domain language + +--- + +## 3. Implementer Agent + +**Owns** +- Stream-coding execution within the current task scope (WORKING.md) +- TDD/BDD: failing test before implementation +- Keeping code compiling and tests green after each slice +- Task file updates (slice / change / result / notes / next) + +**Does NOT** +- Change architecture without escalating to Architect +- Expand scope beyond WORKING.md +- Merge a slice while tests are red + +**Triggered when** +- A task slice is ready for coding (architecture approved, domain clear) + +--- + +## 4. Reviewer Agent + +**Owns** +- Post-implementation architecture violation detection +- Primitive obsession and magic-string identification +- Missing invariant and missing test coverage flags +- Confirming Clean Architecture boundaries hold + +**Does NOT** +- Introduce new features or domain rules +- Change domain behaviour silently +- Approve a slice with unresolved architecture violations + +**Triggered when** +- A stream slice is marked complete by the Implementer +- A PR is prepared + +--- + +## Handover protocol + +``` +Architect ──▶ Domain Modeller ──▶ Implementer ──▶ Reviewer + ▲ │ + └────────────── escalate if structural issue ────────────┘ +``` + +| From | To | Handover condition | +|---|---|---| +| Architect | Domain Modeller | Layer boundaries approved; aggregates and invariants need clarification | +| Domain Modeller | Implementer | Domain model and invariants are explicit; ubiquitous language confirmed | +| Implementer | Reviewer | Slice complete: tests green, task file updated, no open TODOs | +| Reviewer | Architect | Architecture violation found that cannot be resolved at implementation level | +| Reviewer | Domain Modeller | Domain rule is ambiguous or inconsistent with ubiquitous language | +| Any | Implementer (task file) | Scope ambiguity — clarify in task file before continuing | + +--- + +## Escalation matrix + +| Situation | Escalate to | Action | +|---|---|---| +| Domain rules are unclear | Domain Modeller | Stop; ask; document the decision in the task file | +| Architecture boundary would be violated | Architect | Stop; propose options; do not proceed without approval | +| Task scope expands beyond WORKING.md | Task file | Record the expansion request; wait for explicit approval | +| Tests are red and root cause is unknown | Implementer (self) + task file | Record the failure; do not merge; do not bypass with `--no-verify` | +| Conflicting guidance between skill and task file | Task file wins | Note the conflict in the task file for future review | +| Conflicting guidance between task file and architecture | Architect | Stop and surface with options; do not guess | + +--- + +## Stop conditions + +Halt execution and surface the issue if any of the following are true: + +- Domain invariants are not explicit and cannot be inferred safely +- A layer boundary must be violated to complete the slice +- Task scope has grown beyond what WORKING.md authorises +- Tests are red with no clear path to green +- An architectural decision is required but no ADR exists + + +# GitNexus MCP + +This project is indexed by GitNexus as **ere-basic** (344 symbols, 700 relationships, 16 execution flows). + +GitNexus provides a knowledge graph over this codebase — call chains, blast radius, execution flows, and semantic search. + +## Always Start Here + +For any task involving code understanding, debugging, impact analysis, or refactoring, you must: + +1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness +2. **Match your task to a skill below** and **read that skill file** +3. **Follow the skill's workflow and checklist** + +> If step 1 warns the index is stale, run `npx gitnexus analyze` in the terminal first. + +## Skills + +| Task | Read this skill file | +|------|---------------------| +| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/exploring/SKILL.md` | +| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/impact-analysis/SKILL.md` | +| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/debugging/SKILL.md` | +| Rename / extract / split / refactor | `.claude/skills/gitnexus/refactoring/SKILL.md` | + +## Tools Reference + +| Tool | What it gives you | +|------|-------------------| +| `query` | Process-grouped code intelligence — execution flows related to a concept | +| `context` | 360-degree symbol view — categorized refs, processes it participates in | +| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence | +| `detect_changes` | Git-diff impact — what do your current changes affect | +| `rename` | Multi-file coordinated rename with confidence-tagged edits | +| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) | +| `list_repos` | Discover indexed repos | + +## Resources Reference + +Lightweight reads (~100-500 tokens) for navigation: + +| Resource | Content | +|----------|---------| +| `gitnexus://repo/{name}/context` | Stats, staleness check | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores | +| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members | +| `gitnexus://repo/{name}/processes` | All execution flows | +| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace | +| `gitnexus://repo/{name}/schema` | Graph schema for Cypher | + +## Graph Schema + +**Nodes:** File, Function, Class, Interface, Method, Community, Process +**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"}) +RETURN caller.name, caller.filePath +``` + + diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 0000000..cd0ce5e --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1,228 @@ +# ERE — Claude Operating Instructions + +This file governs how Claude operates in this repository. +It overrides defaults where noted. For domain and architecture details, read the docs — not this file. + +--- + +## Project at a glance + +| Item | Reference | +|---|---| +| What ERE is | [README.md](README.md) | +| Architecture layers and patterns | [docs/architecture/ERE-OVERVIEW.md](docs/architecture/ERE-OVERVIEW.md) | +| ERS–ERE interface contract | [docs/ERS-ERE-System-Technical-Contract.pdf](docs/ERS-ERE-System-Technical-Contract.pdf) | +| Cosmic Python blueprint | [docs/architecture/ERE-COSMIC-PYTHON-ARCHITECTURE.md](docs/architecture/ERE-COSMIC-PYTHON-ARCHITECTURE.md) | +| Current task | [WORKING.md](WORKING.md) → `docs/tasks/yyyy-mm-dd-*.md` | + +--- + +## Before you start — always + +1. Read `WORKING.md` — it points to the current active task. +2. Read the referenced `docs/tasks/yyyy-mm-dd-*.md` fully (spec + history). +3. If the task file is missing, create it before doing anything else. +4. Align changes with `README.md` intent and `docs/architecture/` decisions. + +> The task file is a **living document** — update it as you progress, not only at the end. +> Record what you changed, why, what you learned, and what comes next. + +--- + +## Skills + +Before planning or coding, load these skills from `/.claude/skills/`: + +| Skill | When to apply | +|---|---| +| `stream-coding` | Primary workflow driver for all implementation | +| `cosmic-python` | Layer design, ports/adapters, SOLID enforcement | +| `bdd` | Scenario writing, step definitions, feature files | +| `gitnexus` | Codebase navigation, blast-radius analysis | +| `git-commit-and-pr` | Commit hygiene, PR narrative | + +If a skill conflicts with the task file, the **task file wins** for that scope. +If a skill conflicts with architecture constraints, **stop and surface the conflict**. + +--- + +## Repository structure + +``` +src/ere/ +├── adapters/ # Infrastructure: Redis, cluster store, resolver strategies +├── entrypoints/ # Thin drivers: Redis pub/sub consumer +├── models/ # Domain models from erspec + ERE extensions (no I/O) +└── services/ # Use-case orchestration + +test/ +├── features/ # Gherkin BDD feature files +├── steps/ # pytest-bdd step definitions +└── test_data/ # RDF fixtures (Turtle) + +docs/ +├── tasks/ # yyyy-mm-dd-.md — spec + engineering diary +└── architecture/ # ERE-OVERVIEW.md, sequence diagrams, ADRs +``` + +--- + +## How to work — stream loop + +Repeat until the task-file acceptance criteria are all checked: + +1. **Orient** — re-read WORKING.md and the task file; identify the next smallest slice. +2. **Slice** — define one vertical increment; state it in one sentence of domain language. +3. **Prove** — write a failing test (unit) or scenario (BDD) first. +4. **Implement** — minimal code to pass; stay within layer boundaries. +5. **Refactor** — remove duplication, clarify naming, keep domain pure. +6. **Record** — update the task file: slice / change / result / notes / next. +7. **Commit** — small, coherent increment aligned with the slice. Never add coauthors or tool names in commit messages (e.g. claude, haiku, etc.). + +**If you cannot describe the slice in one sentence, it is too large.** + +--- + +## Architecture rules + +Dependency direction is enforced at CI time via `importlinter`. Never violate it: + +``` +entrypoints → services → models + ↘ + adapters → models +``` + +- `models/` — no framework imports, no I/O, no side effects. +- `adapters/` — infrastructure only; never call `services/`. +- `services/` — orchestrate domain and adapters; never import from `entrypoints/`. +- `entrypoints/` — parse input, call services, format output; no business logic. + +- use best practices for OpenTelemetry and logging, but do not instrument prematurely — wait until a clear need arises to understand execution flows or debug issues. + + +Anti-patterns to refuse: +- I/O or framework imports inside `models/` +- Business rules inside `adapters/` or `entrypoints/` +- Magic strings or raw dicts where constants/enums belong +- Circular imports between layers or modules +- imports are not groupped in teh header of the module but are scattered across the code + +--- + +## Testing rules + +- **Unit tests per layer** — each layer tests its own responsibility only. +- **BDD for service use cases** — feature files in `test/features/`, steps in `test/steps/`. +- **TDD by default** — write the failing test before the implementation. +- **80 %+ coverage** target on new production code. +- Use `pytest-bdd` with `target_fixture` (no `ctx` dict); use `parsers.re` when `parsers.parse` cannot handle edge cases (empty strings, quoted numeric values). + +--- + +## Commit rules + +Format: `type(scope): concise description` + +Examples: +- `test(services): add BDD scenario for conflict detection` +- `feat(adapters): implement content-hash mock resolver` +- `refactor(entrypoints): extract request validation to services` + +**Never include** co-author lines, tool names, agent names, or internal implementation details in commit messages. Focus on the *what* and *why* of the code change. + +## Git hygiene rules + +- **Never stage or commit files you haven't modified** — use `git add ` to stage only your changes, or `git add -p` to review hunks before staging. +- **Never revert or reset files outside your current task scope**. +--- + +## Autonomy rules + +You **may** do without asking: +- Refactor for clarity within the current task scope +- Strengthen tests and BDD scenarios +- Extract ports/adapters when coupling appears +- Update the task file and README + +You **must not** do without explicit instruction: +- Expand scope beyond WORKING.md +- Introduce speculative features +- Break architecture boundaries +- Make domain modelling decisions without evidence — ask first + +--- + +## Definition of done + +A task slice is done when: +- [ ] Tests pass and coverage is meaningful for the new behaviour +- [ ] Layer boundaries are clean (no I/O in models, no business logic in entrypoints) +- [ ] Task file is updated (slice / change / result / notes / next) +- [ ] No silent TODOs — follow-ups are explicitly recorded +- [ ] Any non-trivial architectural decision is captured as an ADR-lite note + +--- + + +# GitNexus MCP + +This project is indexed by GitNexus as **ere-basic** (344 symbols, 700 relationships, 16 execution flows). + +GitNexus provides a knowledge graph over this codebase — call chains, blast radius, execution flows, and semantic search. + +## Always Start Here + +For any task involving code understanding, debugging, impact analysis, or refactoring, you must: + +1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness +2. **Match your task to a skill below** and **read that skill file** +3. **Follow the skill's workflow and checklist** + +> If step 1 warns the index is stale, run `npx gitnexus analyze` in the terminal first. + +## Skills + +| Task | Read this skill file | +|------|---------------------| +| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/exploring/SKILL.md` | +| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/impact-analysis/SKILL.md` | +| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/debugging/SKILL.md` | +| Rename / extract / split / refactor | `.claude/skills/gitnexus/refactoring/SKILL.md` | + +## Tools Reference + +| Tool | What it gives you | +|------|-------------------| +| `query` | Process-grouped code intelligence — execution flows related to a concept | +| `context` | 360-degree symbol view — categorized refs, processes it participates in | +| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence | +| `detect_changes` | Git-diff impact — what do your current changes affect | +| `rename` | Multi-file coordinated rename with confidence-tagged edits | +| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) | +| `list_repos` | Discover indexed repos | + +## Resources Reference + +Lightweight reads (~100-500 tokens) for navigation: + +| Resource | Content | +|----------|---------| +| `gitnexus://repo/{name}/context` | Stats, staleness check | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores | +| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members | +| `gitnexus://repo/{name}/processes` | All execution flows | +| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace | +| `gitnexus://repo/{name}/schema` | Graph schema for Cypher | + +## Graph Schema + +**Nodes:** File, Function, Class, Interface, Method, Community, Process +**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"}) +RETURN caller.name, caller.filePath +``` + + diff --git a/.claude/skills/bdd/SKILL.md b/.claude/skills/bdd/SKILL.md new file mode 100644 index 0000000..81deaec --- /dev/null +++ b/.claude/skills/bdd/SKILL.md @@ -0,0 +1,72 @@ +You are an expert in Gherkin (BDD), Behaviour-Driven Development, and pytest-bdd in Python. + +Your task: given a short description of a system behaviour (and optionally existing code APIs, domain objects, and test data), produce: +1) A Gherkin .feature file (or additions to an existing feature) that is readable, stable, and business-meaningful. +2) A pytest-bdd implementation in Python that is idiomatic pytest: fixture-driven, minimal shared mutable state, reusable steps, clear assertions, and deterministic isolation. + +STRICT BEST PRACTICES (must follow): + +A. Gherkin authoring +- Use declarative, domain language, not UI/technical details. +- Prefer Scenario Outlines with Examples tables for data-driven cases. +- Keep scenarios independent: each scenario must fully set up its preconditions (use Background only for truly universal setup). +- Avoid “And” chains that hide meaning; each step should add a distinct fact or action. +- Keep step vocabulary consistent across the feature file: prefer a small set of reusable step phrases. +- Use explicit identifiers and stable expected outcomes: avoid brittle time-based or order-based assertions unless the behaviour is order-sensitive. +- Clearly separate: Given (preconditions), When (single action), Then (assertions). +- Use tags (e.g. @integration, @slow) when helpful; keep them minimal and meaningful. +- Include a short description comment at the top of the feature: what is under test, what API/function is exercised, and where test data lives. + +B. pytest-bdd implementation +- Do NOT implement your own “ctx dict” unless absolutely necessary. +- Prefer `target_fixture` to pass results between steps instead of shared state. +- Use pytest fixtures for sessions/resources (HTTP client, DB session, service bootstrap). Choose fixture scope deliberately: + - session scope for expensive immutable setup + - function (scenario) scope for isolated state +- Step functions should be thin: call domain code, return results, and avoid doing complex orchestration inside steps. +- Assertions belong in Then steps. When steps should perform actions and produce results. +- For expected exceptions: + - Prefer asserting in Then steps by executing the call inside `pytest.raises(...)` if feasible. + - If action must be in When and assertion later, store only minimal exception info in a fixture/state object; keep it typed and explicit. +- Make step reuse safe: + - If a step can be repeated, ensure it is idempotent or its output is keyed (avoid relying on list positions). +- Use parsing with `pytest_bdd.parsers` for structured parameters. +- Use helper functions for loading test data, but avoid one fixture per file unless necessary; prefer a single loader fixture (e.g. `load_rdf(path)`). +- Keep step names stable; do not generate many near-duplicate steps. + +C. Output format +Return the following sections in order: + +1) FEATURE FILE +- Provide a complete .feature file content. +- Put it under a path suggestion like: tests/features/.feature + +2) PYTHON TEST MODULE +- Provide a complete pytest module under a path suggestion like: tests/bdd/test_.py +- Include `scenarios("...")` or explicit `@scenario` bindings. +- Include step definitions using pytest fixtures and `target_fixture`. +- Use type hints and dataclasses only if they reduce complexity; otherwise keep it minimal. + +3) CONFTST.PY RECOMMENDATIONS +- Provide only the minimal conftest fixtures needed (e.g. service factory, data loader). +- If the user already has conftest patterns, adapt to them rather than inventing a new framework. + +4) RUN COMMANDS +- Provide best-practice commands for: + - local dev (pytest) + - selective runs (markers, -k) + - reproducible runs (tox) + - convenience wrapper (make) if relevant + +D. Behaviour fidelity +- Do not invent APIs. If API details are missing, infer minimal interfaces and clearly mark them as assumptions. +- Use deterministic test data. If input files exist, reference them by relative paths, and use a loader fixture. + +E. Style +- Use British English in comments and explanatory text. +- Keep code clean, readable, and ready to paste into a real repository. +- Align to clean code principles: single responsibility, clear naming, minimal duplication, and modularity. +- Align to clean architecture principles: separate domain logic from test orchestration, and keep test code focused on expressing behaviour rather than implementation details. + +If you are given an existing feature example, align the vocabulary and structure to it. +If you are given existing fixtures (e.g. load_rdf), reuse them rather than creating duplicates. \ No newline at end of file diff --git a/.claude/skills/gitnexus/debugging/SKILL.md b/.claude/skills/gitnexus/debugging/SKILL.md new file mode 100644 index 0000000..10bd06b --- /dev/null +++ b/.claude/skills/gitnexus/debugging/SKILL.md @@ -0,0 +1,85 @@ +--- +name: gitnexus-debugging +description: Trace bugs through call chains using knowledge graph +--- + +# Debugging with GitNexus + +## When to Use +- "Why is this function failing?" +- "Trace where this error comes from" +- "Who calls this method?" +- "This endpoint returns 500" +- Investigating bugs, errors, or unexpected behavior + +## Workflow + +``` +1. gitnexus_query({query: ""}) → Find related execution flows +2. gitnexus_context({name: ""}) → See callers/callees/processes +3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow +4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed +``` + +> If "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklist + +``` +- [ ] Understand the symptom (error message, unexpected behavior) +- [ ] gitnexus_query for error text or related code +- [ ] Identify the suspect function from returned processes +- [ ] gitnexus_context to see callers and callees +- [ ] Trace execution flow via process resource if applicable +- [ ] gitnexus_cypher for custom call chain traces if needed +- [ ] Read source files to confirm root cause +``` + +## Debugging Patterns + +| Symptom | GitNexus Approach | +|---------|-------------------| +| Error message | `gitnexus_query` for error text → `context` on throw sites | +| Wrong return value | `context` on the function → trace callees for data flow | +| Intermittent failure | `context` → look for external calls, async deps | +| Performance issue | `context` → find symbols with many callers (hot paths) | +| Recent regression | `detect_changes` to see what your changes affect | + +## Tools + +**gitnexus_query** — find code related to error: +``` +gitnexus_query({query: "payment validation error"}) +→ Processes: CheckoutFlow, ErrorHandling +→ Symbols: validatePayment, handlePaymentError, PaymentException +``` + +**gitnexus_context** — full context for a suspect: +``` +gitnexus_context({name: "validatePayment"}) +→ Incoming calls: processCheckout, webhookHandler +→ Outgoing calls: verifyCard, fetchRates (external API!) +→ Processes: CheckoutFlow (step 3/7) +``` + +**gitnexus_cypher** — custom call chain traces: +```cypher +MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"}) +RETURN [n IN nodes(path) | n.name] AS chain +``` + +## Example: "Payment endpoint returns 500 intermittently" + +``` +1. gitnexus_query({query: "payment error handling"}) + → Processes: CheckoutFlow, ErrorHandling + → Symbols: validatePayment, handlePaymentError + +2. gitnexus_context({name: "validatePayment"}) + → Outgoing calls: verifyCard, fetchRates (external API!) + +3. READ gitnexus://repo/my-app/process/CheckoutFlow + → Step 3: validatePayment → calls fetchRates (external) + +4. Root cause: fetchRates calls external API without proper timeout +``` diff --git a/.claude/skills/gitnexus/exploring/SKILL.md b/.claude/skills/gitnexus/exploring/SKILL.md new file mode 100644 index 0000000..819e1af --- /dev/null +++ b/.claude/skills/gitnexus/exploring/SKILL.md @@ -0,0 +1,75 @@ +--- +name: gitnexus-exploring +description: Navigate unfamiliar code using GitNexus knowledge graph +--- + +# Exploring Codebases with GitNexus + +## When to Use +- "How does authentication work?" +- "What's the project structure?" +- "Show me the main components" +- "Where is the database logic?" +- Understanding code you haven't seen before + +## Workflow + +``` +1. READ gitnexus://repos → Discover indexed repos +2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness +3. gitnexus_query({query: ""}) → Find related execution flows +4. gitnexus_context({name: ""}) → Deep dive on specific symbol +5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow +``` + +> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklist + +``` +- [ ] READ gitnexus://repo/{name}/context +- [ ] gitnexus_query for the concept you want to understand +- [ ] Review returned processes (execution flows) +- [ ] gitnexus_context on key symbols for callers/callees +- [ ] READ process resource for full execution traces +- [ ] Read source files for implementation details +``` + +## Resources + +| Resource | What you get | +|----------|-------------| +| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) | +| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) | +| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) | + +## Tools + +**gitnexus_query** — find execution flows related to a concept: +``` +gitnexus_query({query: "payment processing"}) +→ Processes: CheckoutFlow, RefundFlow, WebhookHandler +→ Symbols grouped by flow with file locations +``` + +**gitnexus_context** — 360-degree view of a symbol: +``` +gitnexus_context({name: "validateUser"}) +→ Incoming calls: loginHandler, apiMiddleware +→ Outgoing calls: checkToken, getUserById +→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3) +``` + +## Example: "How does payment processing work?" + +``` +1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes +2. gitnexus_query({query: "payment processing"}) + → CheckoutFlow: processPayment → validateCard → chargeStripe + → RefundFlow: initiateRefund → calculateRefund → processRefund +3. gitnexus_context({name: "processPayment"}) + → Incoming: checkoutHandler, webhookHandler + → Outgoing: validateCard, chargeStripe, saveTransaction +4. Read src/payments/processor.ts for implementation details +``` diff --git a/.claude/skills/gitnexus/gitnexus-cli/SKILL.md b/.claude/skills/gitnexus/gitnexus-cli/SKILL.md new file mode 100644 index 0000000..c9e0af3 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-cli/SKILL.md @@ -0,0 +1,82 @@ +--- +name: gitnexus-cli +description: "Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: \"Index this repo\", \"Reanalyze the codebase\", \"Generate a wiki\"" +--- + +# GitNexus CLI Commands + +All commands work via `npx` — no global install required. + +## Commands + +### analyze — Build or refresh the index + +```bash +npx gitnexus analyze +``` + +Run from the project root. This parses all source files, builds the knowledge graph, writes it to `.gitnexus/`, and generates CLAUDE.md / AGENTS.md context files. + +| Flag | Effect | +| -------------- | ---------------------------------------------------------------- | +| `--force` | Force full re-index even if up to date | +| `--embeddings` | Enable embedding generation for semantic search (off by default) | + +**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook runs `analyze` automatically after `git commit` and `git merge`, preserving embeddings if previously generated. + +### status — Check index freshness + +```bash +npx gitnexus status +``` + +Shows whether the current repo has a GitNexus index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed. + +### clean — Delete the index + +```bash +npx gitnexus clean +``` + +Deletes the `.gitnexus/` directory and unregisters the repo from the global registry. Use before re-indexing if the index is corrupt or after removing GitNexus from a project. + +| Flag | Effect | +| --------- | ------------------------------------------------- | +| `--force` | Skip confirmation prompt | +| `--all` | Clean all indexed repos, not just the current one | + +### wiki — Generate documentation from the graph + +```bash +npx gitnexus wiki +``` + +Generates repository documentation from the knowledge graph using an LLM. Requires an API key (saved to `~/.gitnexus/config.json` on first use). + +| Flag | Effect | +| ------------------- | ----------------------------------------- | +| `--force` | Force full regeneration | +| `--model ` | LLM model (default: minimax/minimax-m2.5) | +| `--base-url ` | LLM API base URL | +| `--api-key ` | LLM API key | +| `--concurrency ` | Parallel LLM calls (default: 3) | +| `--gist` | Publish wiki as a public GitHub Gist | + +### list — Show all indexed repos + +```bash +npx gitnexus list +``` + +Lists all repositories registered in `~/.gitnexus/registry.json`. The MCP `list_repos` tool provides the same information. + +## After Indexing + +1. **Read `gitnexus://repo/{name}/context`** to verify the index loaded +2. Use the other GitNexus skills (`exploring`, `debugging`, `impact-analysis`, `refactoring`) for your task + +## Troubleshooting + +- **"Not inside a git repository"**: Run from a directory inside a git repo +- **Index is stale after re-analyzing**: Restart Claude Code to reload the MCP server +- **Embeddings slow**: Omit `--embeddings` (it's off by default) or set `OPENAI_API_KEY` for faster API-based embedding diff --git a/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md b/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md new file mode 100644 index 0000000..9510b97 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-debugging/SKILL.md @@ -0,0 +1,89 @@ +--- +name: gitnexus-debugging +description: "Use when the user is debugging a bug, tracing an error, or asking why something fails. Examples: \"Why is X failing?\", \"Where does this error come from?\", \"Trace this bug\"" +--- + +# Debugging with GitNexus + +## When to Use + +- "Why is this function failing?" +- "Trace where this error comes from" +- "Who calls this method?" +- "This endpoint returns 500" +- Investigating bugs, errors, or unexpected behavior + +## Workflow + +``` +1. gitnexus_query({query: ""}) → Find related execution flows +2. gitnexus_context({name: ""}) → See callers/callees/processes +3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow +4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed +``` + +> If "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklist + +``` +- [ ] Understand the symptom (error message, unexpected behavior) +- [ ] gitnexus_query for error text or related code +- [ ] Identify the suspect function from returned processes +- [ ] gitnexus_context to see callers and callees +- [ ] Trace execution flow via process resource if applicable +- [ ] gitnexus_cypher for custom call chain traces if needed +- [ ] Read source files to confirm root cause +``` + +## Debugging Patterns + +| Symptom | GitNexus Approach | +| -------------------- | ---------------------------------------------------------- | +| Error message | `gitnexus_query` for error text → `context` on throw sites | +| Wrong return value | `context` on the function → trace callees for data flow | +| Intermittent failure | `context` → look for external calls, async deps | +| Performance issue | `context` → find symbols with many callers (hot paths) | +| Recent regression | `detect_changes` to see what your changes affect | + +## Tools + +**gitnexus_query** — find code related to error: + +``` +gitnexus_query({query: "payment validation error"}) +→ Processes: CheckoutFlow, ErrorHandling +→ Symbols: validatePayment, handlePaymentError, PaymentException +``` + +**gitnexus_context** — full context for a suspect: + +``` +gitnexus_context({name: "validatePayment"}) +→ Incoming calls: processCheckout, webhookHandler +→ Outgoing calls: verifyCard, fetchRates (external API!) +→ Processes: CheckoutFlow (step 3/7) +``` + +**gitnexus_cypher** — custom call chain traces: + +```cypher +MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"}) +RETURN [n IN nodes(path) | n.name] AS chain +``` + +## Example: "Payment endpoint returns 500 intermittently" + +``` +1. gitnexus_query({query: "payment error handling"}) + → Processes: CheckoutFlow, ErrorHandling + → Symbols: validatePayment, handlePaymentError + +2. gitnexus_context({name: "validatePayment"}) + → Outgoing calls: verifyCard, fetchRates (external API!) + +3. READ gitnexus://repo/my-app/process/CheckoutFlow + → Step 3: validatePayment → calls fetchRates (external) + +4. Root cause: fetchRates calls external API without proper timeout +``` diff --git a/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md b/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md new file mode 100644 index 0000000..927a4e4 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-exploring/SKILL.md @@ -0,0 +1,78 @@ +--- +name: gitnexus-exploring +description: "Use when the user asks how code works, wants to understand architecture, trace execution flows, or explore unfamiliar parts of the codebase. Examples: \"How does X work?\", \"What calls this function?\", \"Show me the auth flow\"" +--- + +# Exploring Codebases with GitNexus + +## When to Use + +- "How does authentication work?" +- "What's the project structure?" +- "Show me the main components" +- "Where is the database logic?" +- Understanding code you haven't seen before + +## Workflow + +``` +1. READ gitnexus://repos → Discover indexed repos +2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness +3. gitnexus_query({query: ""}) → Find related execution flows +4. gitnexus_context({name: ""}) → Deep dive on specific symbol +5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow +``` + +> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklist + +``` +- [ ] READ gitnexus://repo/{name}/context +- [ ] gitnexus_query for the concept you want to understand +- [ ] Review returned processes (execution flows) +- [ ] gitnexus_context on key symbols for callers/callees +- [ ] READ process resource for full execution traces +- [ ] Read source files for implementation details +``` + +## Resources + +| Resource | What you get | +| --------------------------------------- | ------------------------------------------------------- | +| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) | +| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) | +| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) | + +## Tools + +**gitnexus_query** — find execution flows related to a concept: + +``` +gitnexus_query({query: "payment processing"}) +→ Processes: CheckoutFlow, RefundFlow, WebhookHandler +→ Symbols grouped by flow with file locations +``` + +**gitnexus_context** — 360-degree view of a symbol: + +``` +gitnexus_context({name: "validateUser"}) +→ Incoming calls: loginHandler, apiMiddleware +→ Outgoing calls: checkToken, getUserById +→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3) +``` + +## Example: "How does payment processing work?" + +``` +1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes +2. gitnexus_query({query: "payment processing"}) + → CheckoutFlow: processPayment → validateCard → chargeStripe + → RefundFlow: initiateRefund → calculateRefund → processRefund +3. gitnexus_context({name: "processPayment"}) + → Incoming: checkoutHandler, webhookHandler + → Outgoing: validateCard, chargeStripe, saveTransaction +4. Read src/payments/processor.ts for implementation details +``` diff --git a/.claude/skills/gitnexus/gitnexus-guide/SKILL.md b/.claude/skills/gitnexus/gitnexus-guide/SKILL.md new file mode 100644 index 0000000..937ac73 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-guide/SKILL.md @@ -0,0 +1,64 @@ +--- +name: gitnexus-guide +description: "Use when the user asks about GitNexus itself — available tools, how to query the knowledge graph, MCP resources, graph schema, or workflow reference. Examples: \"What GitNexus tools are available?\", \"How do I use GitNexus?\"" +--- + +# GitNexus Guide + +Quick reference for all GitNexus MCP tools, resources, and the knowledge graph schema. + +## Always Start Here + +For any task involving code understanding, debugging, impact analysis, or refactoring: + +1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness +2. **Match your task to a skill below** and **read that skill file** +3. **Follow the skill's workflow and checklist** + +> If step 1 warns the index is stale, run `npx gitnexus analyze` in the terminal first. + +## Skills + +| Task | Skill to read | +| -------------------------------------------- | ------------------- | +| Understand architecture / "How does X work?" | `gitnexus-exploring` | +| Blast radius / "What breaks if I change X?" | `gitnexus-impact-analysis` | +| Trace bugs / "Why is X failing?" | `gitnexus-debugging` | +| Rename / extract / split / refactor | `gitnexus-refactoring` | +| Tools, resources, schema reference | `gitnexus-guide` (this file) | +| Index, status, clean, wiki CLI commands | `gitnexus-cli` | + +## Tools Reference + +| Tool | What it gives you | +| ---------------- | ------------------------------------------------------------------------ | +| `query` | Process-grouped code intelligence — execution flows related to a concept | +| `context` | 360-degree symbol view — categorized refs, processes it participates in | +| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence | +| `detect_changes` | Git-diff impact — what do your current changes affect | +| `rename` | Multi-file coordinated rename with confidence-tagged edits | +| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) | +| `list_repos` | Discover indexed repos | + +## Resources Reference + +Lightweight reads (~100-500 tokens) for navigation: + +| Resource | Content | +| ---------------------------------------------- | ----------------------------------------- | +| `gitnexus://repo/{name}/context` | Stats, staleness check | +| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores | +| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members | +| `gitnexus://repo/{name}/processes` | All execution flows | +| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace | +| `gitnexus://repo/{name}/schema` | Graph schema for Cypher | + +## Graph Schema + +**Nodes:** File, Function, Class, Interface, Method, Community, Process +**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"}) +RETURN caller.name, caller.filePath +``` diff --git a/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md b/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md new file mode 100644 index 0000000..e19af28 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md @@ -0,0 +1,97 @@ +--- +name: gitnexus-impact-analysis +description: "Use when the user wants to know what will break if they change something, or needs safety analysis before editing code. Examples: \"Is it safe to change X?\", \"What depends on this?\", \"What will break?\"" +--- + +# Impact Analysis with GitNexus + +## When to Use + +- "Is it safe to change this function?" +- "What will break if I modify X?" +- "Show me the blast radius" +- "Who uses this code?" +- Before making non-trivial code changes +- Before committing — to understand what your changes affect + +## Workflow + +``` +1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this +2. READ gitnexus://repo/{name}/processes → Check affected execution flows +3. gitnexus_detect_changes() → Map current git changes to affected flows +4. Assess risk and report to user +``` + +> If "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklist + +``` +- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents +- [ ] Review d=1 items first (these WILL BREAK) +- [ ] Check high-confidence (>0.8) dependencies +- [ ] READ processes to check affected execution flows +- [ ] gitnexus_detect_changes() for pre-commit check +- [ ] Assess risk level and report to user +``` + +## Understanding Output + +| Depth | Risk Level | Meaning | +| ----- | ---------------- | ------------------------ | +| d=1 | **WILL BREAK** | Direct callers/importers | +| d=2 | LIKELY AFFECTED | Indirect dependencies | +| d=3 | MAY NEED TESTING | Transitive effects | + +## Risk Assessment + +| Affected | Risk | +| ------------------------------ | -------- | +| <5 symbols, few processes | LOW | +| 5-15 symbols, 2-5 processes | MEDIUM | +| >15 symbols or many processes | HIGH | +| Critical path (auth, payments) | CRITICAL | + +## Tools + +**gitnexus_impact** — the primary tool for symbol blast radius: + +``` +gitnexus_impact({ + target: "validateUser", + direction: "upstream", + minConfidence: 0.8, + maxDepth: 3 +}) + +→ d=1 (WILL BREAK): + - loginHandler (src/auth/login.ts:42) [CALLS, 100%] + - apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%] + +→ d=2 (LIKELY AFFECTED): + - authRouter (src/routes/auth.ts:22) [CALLS, 95%] +``` + +**gitnexus_detect_changes** — git-diff based impact analysis: + +``` +gitnexus_detect_changes({scope: "staged"}) + +→ Changed: 5 symbols in 3 files +→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline +→ Risk: MEDIUM +``` + +## Example: "What breaks if I change validateUser?" + +``` +1. gitnexus_impact({target: "validateUser", direction: "upstream"}) + → d=1: loginHandler, apiMiddleware (WILL BREAK) + → d=2: authRouter, sessionManager (LIKELY AFFECTED) + +2. READ gitnexus://repo/my-app/processes + → LoginFlow and TokenRefresh touch validateUser + +3. Risk: 2 direct callers, 2 processes = MEDIUM +``` diff --git a/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md b/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md new file mode 100644 index 0000000..f48cc01 --- /dev/null +++ b/.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md @@ -0,0 +1,121 @@ +--- +name: gitnexus-refactoring +description: "Use when the user wants to rename, extract, split, move, or restructure code safely. Examples: \"Rename this function\", \"Extract this into a module\", \"Refactor this class\", \"Move this to a separate file\"" +--- + +# Refactoring with GitNexus + +## When to Use + +- "Rename this function safely" +- "Extract this into a module" +- "Split this service" +- "Move this to a new file" +- Any task involving renaming, extracting, splitting, or restructuring code + +## Workflow + +``` +1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents +2. gitnexus_query({query: "X"}) → Find execution flows involving X +3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs +4. Plan update order: interfaces → implementations → callers → tests +``` + +> If "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklists + +### Rename Symbol + +``` +- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits +- [ ] Review graph edits (high confidence) and ast_search edits (review carefully) +- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits +- [ ] gitnexus_detect_changes() — verify only expected files changed +- [ ] Run tests for affected processes +``` + +### Extract Module + +``` +- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs +- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers +- [ ] Define new module interface +- [ ] Extract code, update imports +- [ ] gitnexus_detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +### Split Function/Service + +``` +- [ ] gitnexus_context({name: target}) — understand all callees +- [ ] Group callees by responsibility +- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update +- [ ] Create new functions/services +- [ ] Update callers +- [ ] gitnexus_detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +## Tools + +**gitnexus_rename** — automated multi-file rename: + +``` +gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) +→ 12 edits across 8 files +→ 10 graph edits (high confidence), 2 ast_search edits (review) +→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}] +``` + +**gitnexus_impact** — map all dependents first: + +``` +gitnexus_impact({target: "validateUser", direction: "upstream"}) +→ d=1: loginHandler, apiMiddleware, testUtils +→ Affected Processes: LoginFlow, TokenRefresh +``` + +**gitnexus_detect_changes** — verify your changes after refactoring: + +``` +gitnexus_detect_changes({scope: "all"}) +→ Changed: 8 files, 12 symbols +→ Affected processes: LoginFlow, TokenRefresh +→ Risk: MEDIUM +``` + +**gitnexus_cypher** — custom reference queries: + +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"}) +RETURN caller.name, caller.filePath ORDER BY caller.filePath +``` + +## Risk Rules + +| Risk Factor | Mitigation | +| ------------------- | ----------------------------------------- | +| Many callers (>5) | Use gitnexus_rename for automated updates | +| Cross-area refs | Use detect_changes after to verify scope | +| String/dynamic refs | gitnexus_query to find them | +| External/public API | Version and deprecate properly | + +## Example: Rename `validateUser` to `authenticateUser` + +``` +1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) + → 12 edits: 10 graph (safe), 2 ast_search (review) + → Files: validator.ts, login.ts, middleware.ts, config.json... + +2. Review ast_search edits (config.json: dynamic reference!) + +3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false}) + → Applied 12 edits across 8 files + +4. gitnexus_detect_changes({scope: "all"}) + → Affected: LoginFlow, TokenRefresh + → Risk: MEDIUM — run tests for these flows +``` diff --git a/.claude/skills/gitnexus/impact-analysis/SKILL.md b/.claude/skills/gitnexus/impact-analysis/SKILL.md new file mode 100644 index 0000000..0b81e4a --- /dev/null +++ b/.claude/skills/gitnexus/impact-analysis/SKILL.md @@ -0,0 +1,94 @@ +--- +name: gitnexus-impact-analysis +description: Analyze blast radius before making code changes +--- + +# Impact Analysis with GitNexus + +## When to Use +- "Is it safe to change this function?" +- "What will break if I modify X?" +- "Show me the blast radius" +- "Who uses this code?" +- Before making non-trivial code changes +- Before committing — to understand what your changes affect + +## Workflow + +``` +1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this +2. READ gitnexus://repo/{name}/processes → Check affected execution flows +3. gitnexus_detect_changes() → Map current git changes to affected flows +4. Assess risk and report to user +``` + +> If "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklist + +``` +- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents +- [ ] Review d=1 items first (these WILL BREAK) +- [ ] Check high-confidence (>0.8) dependencies +- [ ] READ processes to check affected execution flows +- [ ] gitnexus_detect_changes() for pre-commit check +- [ ] Assess risk level and report to user +``` + +## Understanding Output + +| Depth | Risk Level | Meaning | +|-------|-----------|---------| +| d=1 | **WILL BREAK** | Direct callers/importers | +| d=2 | LIKELY AFFECTED | Indirect dependencies | +| d=3 | MAY NEED TESTING | Transitive effects | + +## Risk Assessment + +| Affected | Risk | +|----------|------| +| <5 symbols, few processes | LOW | +| 5-15 symbols, 2-5 processes | MEDIUM | +| >15 symbols or many processes | HIGH | +| Critical path (auth, payments) | CRITICAL | + +## Tools + +**gitnexus_impact** — the primary tool for symbol blast radius: +``` +gitnexus_impact({ + target: "validateUser", + direction: "upstream", + minConfidence: 0.8, + maxDepth: 3 +}) + +→ d=1 (WILL BREAK): + - loginHandler (src/auth/login.ts:42) [CALLS, 100%] + - apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%] + +→ d=2 (LIKELY AFFECTED): + - authRouter (src/routes/auth.ts:22) [CALLS, 95%] +``` + +**gitnexus_detect_changes** — git-diff based impact analysis: +``` +gitnexus_detect_changes({scope: "staged"}) + +→ Changed: 5 symbols in 3 files +→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline +→ Risk: MEDIUM +``` + +## Example: "What breaks if I change validateUser?" + +``` +1. gitnexus_impact({target: "validateUser", direction: "upstream"}) + → d=1: loginHandler, apiMiddleware (WILL BREAK) + → d=2: authRouter, sessionManager (LIKELY AFFECTED) + +2. READ gitnexus://repo/my-app/processes + → LoginFlow and TokenRefresh touch validateUser + +3. Risk: 2 direct callers, 2 processes = MEDIUM +``` diff --git a/.claude/skills/gitnexus/refactoring/SKILL.md b/.claude/skills/gitnexus/refactoring/SKILL.md new file mode 100644 index 0000000..7fe71c4 --- /dev/null +++ b/.claude/skills/gitnexus/refactoring/SKILL.md @@ -0,0 +1,113 @@ +--- +name: gitnexus-refactoring +description: Plan safe refactors using blast radius and dependency mapping +--- + +# Refactoring with GitNexus + +## When to Use +- "Rename this function safely" +- "Extract this into a module" +- "Split this service" +- "Move this to a new file" +- Any task involving renaming, extracting, splitting, or restructuring code + +## Workflow + +``` +1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents +2. gitnexus_query({query: "X"}) → Find execution flows involving X +3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs +4. Plan update order: interfaces → implementations → callers → tests +``` + +> If "Index is stale" → run `npx gitnexus analyze` in terminal. + +## Checklists + +### Rename Symbol +``` +- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits +- [ ] Review graph edits (high confidence) and ast_search edits (review carefully) +- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits +- [ ] gitnexus_detect_changes() — verify only expected files changed +- [ ] Run tests for affected processes +``` + +### Extract Module +``` +- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs +- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers +- [ ] Define new module interface +- [ ] Extract code, update imports +- [ ] gitnexus_detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +### Split Function/Service +``` +- [ ] gitnexus_context({name: target}) — understand all callees +- [ ] Group callees by responsibility +- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update +- [ ] Create new functions/services +- [ ] Update callers +- [ ] gitnexus_detect_changes() — verify affected scope +- [ ] Run tests for affected processes +``` + +## Tools + +**gitnexus_rename** — automated multi-file rename: +``` +gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) +→ 12 edits across 8 files +→ 10 graph edits (high confidence), 2 ast_search edits (review) +→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}] +``` + +**gitnexus_impact** — map all dependents first: +``` +gitnexus_impact({target: "validateUser", direction: "upstream"}) +→ d=1: loginHandler, apiMiddleware, testUtils +→ Affected Processes: LoginFlow, TokenRefresh +``` + +**gitnexus_detect_changes** — verify your changes after refactoring: +``` +gitnexus_detect_changes({scope: "all"}) +→ Changed: 8 files, 12 symbols +→ Affected processes: LoginFlow, TokenRefresh +→ Risk: MEDIUM +``` + +**gitnexus_cypher** — custom reference queries: +```cypher +MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"}) +RETURN caller.name, caller.filePath ORDER BY caller.filePath +``` + +## Risk Rules + +| Risk Factor | Mitigation | +|-------------|------------| +| Many callers (>5) | Use gitnexus_rename for automated updates | +| Cross-area refs | Use detect_changes after to verify scope | +| String/dynamic refs | gitnexus_query to find them | +| External/public API | Version and deprecate properly | + +## Example: Rename `validateUser` to `authenticateUser` + +``` +1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true}) + → 12 edits: 10 graph (safe), 2 ast_search (review) + → Files: validator.ts, login.ts, middleware.ts, config.json... + +2. Review ast_search edits (config.json: dynamic reference!) + +3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false}) + → Applied 12 edits across 8 files + +4. gitnexus_detect_changes({scope: "all"}) + → Affected: LoginFlow, TokenRefresh + → Risk: MEDIUM — run tests for these flows +``` diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2570269 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,60 @@ +# Version control +.git +.gitignore +.gitattributes + +# Python +__pycache__ +*.pyc +*.pyo +.venv +.mypy_cache +.pytest_cache +.ruff_cache +*.egg-info + +# IDE +.vscode +.idea + +# Environment +.env +.env.* +!.env.example + +# Docker (no need to send these into the build context) +src/infra/Dockerfile +src/infra/compose.dev.yaml +src/infra/README.md +src/infra/.env +src/infra/.env.* + +# AI / tooling config +.claude +CLAUDE.md + +# CI +.github + +# Docs +docs + +# Build artifacts and data +dist +build +data +reports +coverage.xml +htmlcov +.coverage +.tox + +# Tests and demo (not needed at runtime) +test +src/demo + +# Project config (not needed at runtime) +sonar-project.properties +.pylintrc +.importlinter +tox.ini diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bfec021 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Enforce Unix line endings +*.sh text eol=lf +Dockerfile text eol=lf +*.yaml text eol=lf diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..105b9ce --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,137 @@ +# CI workflow for Entity Resolution Engine (ERE) +# =============================================== +# Runs on push to develop and on PRs targeting develop. +# +# Jobs: +# 1. quality — Install, lint, test & verify (tox), SonarCloud +# 2. trigger-staging-deploy — on push to develop only, triggers the +# Deploy ERSys Staging workflow on enity-resolution-ops via the +# GitHub workflow_dispatch API +# +# Required secrets: +# - SONAR_TOKEN: SonarCloud authentication token +# - CI_GH_TOKEN: org-level PAT for cross-repo workflow dispatch + +name: CI + +on: + push: + branches: [develop] + pull_request: + branches: [develop] + +permissions: + contents: read + +jobs: + quality: + name: Lint, Test & Verify + runs-on: ubuntu-latest + + services: + redis: + image: redis:7 + ports: + - 6379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + # ------------------------------------------------------------------ + # Checkout + # ------------------------------------------------------------------ + - uses: actions/checkout@v6 + with: + fetch-depth: 0 # Full history required for SonarCloud analysis + + # ------------------------------------------------------------------ + # Python & Poetry + # ------------------------------------------------------------------ + - name: Read Python version from pyproject.toml + id: python-version + run: echo "version=$(grep -m1 'python = ' src/pyproject.toml | grep -oP '\d+\.\d+' | head -1)" >> $GITHUB_OUTPUT + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ steps.python-version.outputs.version }} + + - name: Install Poetry + run: pipx install poetry + + - name: Configure git credentials for private dependencies + run: | + git config --global url."https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/".insteadOf "https://github.com/" + # NOTE: If GITHUB_TOKEN lacks cross-repo access, replace with: + # git config --global url."https://x-access-token:${{ secrets.GH_TOKEN_PRIVATE_REPOS }}@github.com/".insteadOf "https://github.com/" + + # ------------------------------------------------------------------ + # Dependency caching + # ------------------------------------------------------------------ + - name: Cache Poetry dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cache/pypoetry + .tox + key: poetry-${{ runner.os }}-${{ hashFiles('src/poetry.lock', 'tox.ini') }} + restore-keys: | + poetry-${{ runner.os }}- + + # ------------------------------------------------------------------ + # Install + # ------------------------------------------------------------------ + - name: Install dependencies + run: cd src && poetry install --with dev + + # ------------------------------------------------------------------ + # Lint, Test & Verify (tox) + # ------------------------------------------------------------------ + - name: Prepare environment file + run: cp src/infra/.env.example src/infra/.env + + - name: Run quality checks (unit tests + architecture + clean-code) + run: cd src && poetry run tox -e py312,architecture,clean-code + env: + REDIS_HOST: localhost + REDIS_PORT: 6379 + REDIS_PASSWORD: "" + + # ------------------------------------------------------------------ + # SonarCloud + # ------------------------------------------------------------------ + - name: Check for SonarCloud Token + id: sonar_check + run: | + if [ -z "${{ secrets.SONAR_TOKEN }}" ]; then + echo "has_token=false" >> $GITHUB_OUTPUT + else + echo "has_token=true" >> $GITHUB_OUTPUT + fi + + - name: SonarCloud scan + if: always() && steps.sonar_check.outputs.has_token == 'true' + uses: SonarSource/sonarqube-scan-action@v6 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + trigger-staging-deploy: + name: Trigger staging deploy + needs: quality + if: github.event_name == 'push' && github.repository_owner == 'meaningfy-ws' + runs-on: ubuntu-latest + env: + OPS_REPO: meaningfy-ws/enity-resolution-ops + DEPLOY_WORKFLOW: deploy-staging.yml + DEPLOY_REF: develop + steps: + - name: Trigger deploy workflow on ops repo + run: | + curl -sf -X POST \ + -H "Authorization: token ${{ secrets.CI_GH_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${OPS_REPO}/actions/workflows/${DEPLOY_WORKFLOW}/dispatches" \ + -d '{"ref":"${{ env.DEPLOY_REF }}","inputs":{"repo":"${{ github.repository }}","sha":"${{ github.sha }}"}}' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6379a8e --- /dev/null +++ b/.gitignore @@ -0,0 +1,219 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock +#poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +#pdm.lock +#pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +#pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +infra/.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +.vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Cursor +# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to +# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data +# refer to https://docs.cursor.com/context/ignore-files +.cursorignore +.cursorindexingignore + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# macOS garbage +.DS_Store +.project +.gitnexus +.claude/settings.local.json +poetry.toml +.vscode +.import_linter_cache +.pycharm_plugin +.idea diff --git a/.importlinter b/.importlinter new file mode 100644 index 0000000..311e360 --- /dev/null +++ b/.importlinter @@ -0,0 +1,11 @@ +[importlinter] +root_packages = + ere + +[importlinter:contract:layers] +name = ERE three-layer architecture +type = layers +layers = + ere.entrypoints + ere.services + ere.adapters diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..fbfd3f9 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,98 @@ +[MASTER] +# Ignore patterns +ignore=CVS,tests,__pycache__ +ignore-patterns=test_.*?\.py,_test_.*?\.py +persistent=yes +load-plugins= + +[MESSAGES CONTROL] +# Disable specific warnings that conflict with our style or are false positives +disable=C0111, # missing-docstring (we document via type hints) + C0103, # invalid-name (allow single letter vars like i, j, k, x, y, z) + C0301, # line-too-long (handled by Ruff formatter) + C0303, # trailing-whitespace (handled by formatter) + C0305, # trailing-newlines (handled by formatter) + C0321, # multiple-statements (handled by formatter) + C0415, # import-outside-toplevel (sometimes necessary) + W0107, # unnecessary-pass + W0221, # arguments-differ (common in inheritance) + W0311, # bad-indentation (handled by formatter) + W0511, # fixme (TODO/FIXME comments are useful) + W0603, # global-statement + W0613, # unused-argument (common in abstract methods) + W0707, # raise-missing-from + R0903, # too-few-public-methods (dataclasses often have few methods) + R0913, # too-many-arguments (7 args is reasonable for services) + R0914, # too-many-locals (20 locals is reasonable for complex functions) + R1705, # no-else-return + R1711, # useless-return + R0801, # duplicate-code (detected separately) + E1134 # not-a-mapping (false positive with config objects) + +[REPORTS] +output-format=text +reports=no +score=yes + +[BASIC] +# Good names for short variables +good-names=i,j,k,v,e,ex,f,fp,fd,x,y,z,id,pk,db,df,dt,ts,tz,io,ok,_,__,Run,log,url,uri,api,sql,xml,json,csv,ttl,rdf,ns,ctx,cfg,tmp,value +bad-names=foo,bar,baz,toto,tutu,tata,temp,tmp2,tmp3,data,info,obj,item,thing,stuff,do_stuff,handle,process,manager,helper,util,utility,common,misc,base,abstract,generic,value,result,output,input,flag,flag1,flag2,aux,auxiliary + +# Naming patterns for code elements +name-group= +include-naming-hint=no +function-rgx=[a-z_][a-z0-9_]{2,30}$ +variable-rgx=[a-z_][a-z0-9_]{2,30}$ +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +attr-rgx=[a-z_][a-z0-9_]{2,30}$ +argument-rgx=[a-z_][a-z0-9_]{2,30}$ +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ +class-rgx=[A-Z_][a-zA-Z0-9]+$ +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +[FORMAT] +max-line-length=120 +max-module-lines=1000 +indent-string=' ' + +[MISCELLANEOUS] +notes=FIXME,XXX,TODO + +[SIMILARITIES] +min-similarity-lines=10 +ignore-comments=yes +ignore-docstrings=yes +ignore-imports=yes + +[TYPECHECK] +ignore-mixin-members=yes +ignored-classes=SQLObject + +[VARIABLES] +init-import=no +dummy-variables-rgx=_|dummy + +[CLASSES] +defining-attr-methods=__init__,__new__,setUp +valid-classmethod-first-arg=cls +valid-metaclass-classmethod-first-arg=mcs + +[DESIGN] +# SOLID Principles enforcement thresholds +max-args=7 # SRP: keep functions focused +max-attributes=10 # SRP: keep classes cohesive +max-bool-expr=5 # DIP: complex conditions suggest abstraction needed +max-branches=15 # Cyclomatic complexity (SRP) +max-locals=20 # Keep functions readable +max-returns=6 # SRP: multiple returns suggest multiple responsibilities +max-statements=75 # Keep methods manageable +min-public-methods=1 # Allow classes with few public methods + +[IMPORTS] +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +[EXCEPTIONS] +overgeneral-exceptions=builtins.Exception diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7b9d592 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,219 @@ +# ERE — Agent Operating Instructions + +This file governs how AI agents operate in this repository. +It complements `CLAUDE.md` (which governs Claude Code specifically) and `.claude/CLAUDE.md` (project instructions). + +--- + +## Commits and PRs + +- **Never auto-commit** unless the user explicitly asks. +- **Never force-push** to `main` or `develop`. +- **Never add co-author lines**, tool names, or agent names to commit messages. +- Commit format: `type(scope): concise description` — e.g. `feat(adapters): add splink resolver factory`. +- Stage only files you modified: `git add `, never `git add -A` blindly. +- Before committing, run `make lint` and `make test-unit` to verify nothing is broken. +- PRs target `develop` (not `main`) unless told otherwise. +- When creating a PR, include a short summary and a test-plan checklist. + +--- + +## Working Methodology + +### Before touching code + +1. Read `WORKING.md` — it points to the active task file. +2. Read the referenced `docs/tasks/yyyy-mm-dd-*.md` fully. +3. Understand the current branch state: `git log --oneline -10`. + +### Running the stack for integration tests + +Integration tests require Redis to be running. Start it first: + +```bash +make infra-up # starts Redis + RedisInsight via Docker Compose +make test-integration # then run integration tests +make infra-down # tear down when done +``` + +Unit tests do **not** require any infrastructure: + +```bash +make test-unit # fast, self-contained, uses your venv +``` + +### Typical development loop + +```bash +make install # first time or after pyproject.toml changes +make test-unit # red → green → refactor +make lint # quick style check +make check-architecture # verify import-linter contracts +make all-quality-checks # before opening a PR +``` + +--- + +## Tooling Reference + +| Target | What it does | +|--------|-------------| +| `make install` | Install deps via Poetry | +| `make test-unit` | pytest unit suite + coverage report | +| `make test-integration` | integration tests (Redis must be up) | +| `make test-coverage` | HTML coverage report → `htmlcov/index.html` | +| `make lint` | pylint (fast, your venv) | +| `make format` | Ruff formatter | +| `make lint-fix` | Ruff auto-fix | +| `make check-clean-code` | pylint + radon + xenon (tox isolated) | +| `make check-architecture` | import-linter contracts (tox isolated) | +| `make all-quality-checks` | lint + clean-code + architecture | +| `make ci` | full tox pipeline (py312 + architecture + clean-code) | +| `make infra-up` | Start Redis stack (Docker Compose) | +| `make infra-down` | Stop Redis stack | +| `make infra-watch` | Live-reload mode (syncs `src/` and `src/config/`) | + +--- + +## Architecture Rules (enforced by import-linter) + +Dependency direction must never be violated: + +``` +entrypoints → services → models + ↘ + adapters → models +``` + +- `models/` — no I/O, no framework imports, no side effects. +- `adapters/` — infrastructure only; never calls `services/`. +- `services/` — orchestrates domain and adapters; never imports from `entrypoints/`. +- `entrypoints/` — parses input, calls services, formats output; no business logic. + +Violations block CI. Check with `make check-architecture` before opening a PR. + +--- + +## Memory Conventions + +Save to memory only what is non-obvious and persists across conversations: + +- Architectural decisions that aren't evident from the code (e.g. resolver factory registry pattern, DuckDB threading model). +- Design constraints explained by the user that aren't in comments or docs. +- User preferences about how to collaborate (e.g. "never suggest walrus operators", "prefer explicit factory injection"). + +Do **not** save to memory: +- Current task state (use the task file in `docs/tasks/`). +- Git history or recent changes (readable via `git log`). +- File paths or code structure (readable from the repo). + +--- + +## Gotchas + +- **`logging.basicConfig` is a no-op** when handlers already exist (conftest sets them up via `dictConfig`). Mock it with `patch("logging.basicConfig")` in logging tests. +- **DuckDB in tests**: use in-memory mode (`:memory:`) or a temp file via `tmp_path`; never a fixed path that leaks between tests. +- **Integration tests are marked** with `@pytest.mark.integration` — `make test-unit` skips them automatically. +- **`infra/.env`** is required for `make infra-*` targets. Copy from `infra/.env.example` on first use. +- **Config files** live in `src/config/` (moved from repo root in the 2026-04 restructure). Do not confuse with `infra/config/`. +- **erspec models** are LinkML-generated with snake_case fields (e.g. `legal_name`, not `legalName`). Do not edit generated files — update the schema and regenerate. +- **`ERE_LOG_LEVEL`** is the canonical env var for log level in this service (not `LOG_LEVEL`). + +--- + + +# GitNexus — Code Intelligence + +This project is indexed by GitNexus as **entity-resolution-engine-basic** (528 symbols, 1372 relationships, 36 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. + +> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. + +## Always Do + +- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. +- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. +- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. +- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. +- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`. + +## When Debugging + +1. `gitnexus_query({query: ""})` — find execution flows related to the issue +2. `gitnexus_context({name: ""})` — see all callers, callees, and process participation +3. `READ gitnexus://repo/entity-resolution-engine-basic/process/{processName}` — trace the full execution flow step by step +4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed + +## When Refactoring + +- **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`. +- **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code. +- After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed. + +## Never Do + +- NEVER edit a function, class, or method without first running `gitnexus_impact` on it. +- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. +- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph. +- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope. + +## Tools Quick Reference + +| Tool | When to use | Command | +|------|-------------|---------| +| `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` | +| `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` | +| `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` | +| `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` | +| `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` | +| `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` | + +## Impact Risk Levels + +| Depth | Meaning | Action | +|-------|---------|--------| +| d=1 | WILL BREAK — direct callers/importers | MUST update these | +| d=2 | LIKELY AFFECTED — indirect deps | Should test | +| d=3 | MAY NEED TESTING — transitive | Test if critical path | + +## Resources + +| Resource | Use for | +|----------|---------| +| `gitnexus://repo/entity-resolution-engine-basic/context` | Codebase overview, check index freshness | +| `gitnexus://repo/entity-resolution-engine-basic/clusters` | All functional areas | +| `gitnexus://repo/entity-resolution-engine-basic/processes` | All execution flows | +| `gitnexus://repo/entity-resolution-engine-basic/process/{name}` | Step-by-step execution trace | + +## Self-Check Before Finishing + +Before completing any code modification task, verify: +1. `gitnexus_impact` was run for all modified symbols +2. No HIGH/CRITICAL risk warnings were ignored +3. `gitnexus_detect_changes()` confirms changes match expected scope +4. All d=1 (WILL BREAK) dependents were updated + +## Keeping the Index Fresh + +After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it: + +```bash +npx gitnexus analyze +``` + +If the index previously included embeddings, preserve them by adding `--embeddings`: + +```bash +npx gitnexus analyze --embeddings +``` + +To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.** + +> Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`. + +## CLI + +- Re-index: `npx gitnexus analyze` +- Check freshness: `npx gitnexus status` +- Generate docs: `npx gitnexus wiki` + + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..aad6ffa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,127 @@ +# Changelog + +All notable changes to the Basic Entity Resolution Engine (Basic ERE) are documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- + +## [Unreleased] + + +## [1.1.0-rc.4] - 2026-06-30 + +### Changed +* Dockerfile updated to use fully qualified Docker Hub reference for the Python base image + + +## [1.1.0-rc.3] - 2026-06-10 + +### Changed +- Package author updated to Publications Office of the European Union +- `poetry.lock` refreshed with updated dependency pins +- Installation instructions updated + +## [1.1.0-rc.2] - 2026-05-15 + +### Added +- Optional TLS support for Redis connections via `REDIS_TLS` environment variable +- Redis adapter extracted as a reusable, standalone component +- `REDIS_PASSWORD` documented in configuration reference +- Environment variable reference section added to configuration documentation + +### Changed +- `REQUEST_QUEUE` / `RESPONSE_QUEUE` renamed to `ERSYS_REQUEST_QUEUE` / `ERSYS_RESPONSE_QUEUE` — update `.env` files accordingly +- Dependency versions pinned to exact values for reproducible builds +- Makefile made compatible with macOS `make` tool +- `rdflib` and `pyyaml` moved from development to main dependencies +- `logging.exception` used instead of `logging.error` for exception logging with stack traces + + +## [1.0.0-rc.1] - 2026-04-21 + +### Added +- Unit test suite expanded to meet the 80% coverage threshold + +### Changed +- Repository layout restructured: `config/`, `demo/`, `pyproject.toml`, `poetry.lock`, and `infra/` consolidated under `src/`; all tooling, Makefile targets, and path references updated accordingly +- Docker: multi-stage wheel-based build with non-root user for improved security and build reproducibility; configuration decoupled from the image and mounted at runtime +- CI: SonarCloud scan made conditional on token availability; coverage report path mapping corrected; integration tests excluded from the tox pipeline to keep unit runs self-contained; staging deployment gated behind explicit dispatch +- Environment variables aligned with ERSys naming convention + +## [0.3.0] - 2026-03-04 + +### Added + +**Core Entity Resolution Engine** +- Probabilistic entity resolution using Splink (probabilistic record linkage) +- Incremental clustering with stable, deterministic cluster identifiers (`SHA256(source_id, request_id, entity_type)`) +- Cold-start parameter initialization for Splink comparisons (configurable m/u probabilities per field) +- Expectation-Maximization (EM) training for automatic probabilistic model refinement as mention database grows +- Idempotent processing: re-submitting identical requests yields identical clustering outcomes + +**Redis Queue Integration** +- `RedisQueueWorker` for asynchronous message consumption and response publishing +- Support for `EntityMentionResolutionRequest` and `EntityMentionResolutionResponse` message types +- Configurable request/response queue names via environment variables +- Full adherence to ERS–ERE Technical Contract v0.2 + +**Data Storage & Repositories** +- `DuckDBMentionRepository`: Stores entity mentions with idempotency tracking +- `DuckDBSimilarityRepository`: Caches Splink comparison results for reuse +- `DuckDBClusterRepository`: Manages cluster assignments and lifecycle +- In-memory or persistent DuckDB storage (configurable via `DUCKDB_PATH`) + +**RDF Data Ingestion** +- `TurtleRDFMapper` for parsing Turtle-format RDF entity data +- Configurable field extraction via `rdf_mapping.yaml` (predicates, namespaces) +- Support for nested RDF properties (e.g., `registeredAddress/hasCountryCode`) +- Declarative entity type definitions (no hardcoded types) + +**Configuration & Customization** +- `resolver.yaml`: Splink comparison rules, cold-start parameters, threshold tuning +- `rdf_mapping.yaml`: RDF field binding and extraction rules per entity type +- Environment variable overrides for deployment flexibility +- CLI argument support for config paths and log levels + +**Diagnostic & Observability** +- Comprehensive TRACE-level logging throughout the service +- Training status and parameter visualization (cold-start vs. EM-trained) +- EM training progress logging with m/u probability estimation milestones +- Request/response payload logging for debugging + +**Testing Infrastructure** +- Unit tests for adapters (DuckDB repositories, RDF mapper, Splink linker) +- Integration tests for full entity resolution workflow with real adapters +- BDD scenarios (Gherkin) for clustering behaviour and algorithm verification +- End-to-end tests for Redis queue integration and service startup +- Test fixtures for consistent service and mapper setup across test layers +- Stress test framework with synthetic datasets (org-mid.csv) for throughput/latency benchmarking + +**Architecture & Code Quality** +- Layered Cosmic Python architecture: models → adapters/services → entrypoints +- Import-linter enforcement of dependency boundaries (no circular imports) +- SOLID principles: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion +- 80%+ test coverage target on new production code +- Comprehensive docstrings and type hints + +**Docker & Deployment** +- Multi-stage Dockerfile for production-ready containerization +- `compose.dev.yaml` for full-stack setup (Redis + ERE service) +- `.env.example` template for configuration + +**Documentation** +- README with architecture overview, capabilities, and quickstart +- ERS–ERE Technical Contract specification (PDF) +- Architecture documentation with layered design diagrams +- Algorithm documentation with step-by-step resolution flow +- Configuration reference for resolver and RDF mapping tuning +- Contributing guidelines and branch naming conventions +- CLAUDE.md for development workflow and architecture rules + +**Demo Application** +- `demo/demo.py`: Sends synthetic entity mentions and displays clustering results +- Configurable mention datasets with ground-truth clusters +- Queue interaction examples and Redis integration demonstration + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7b9d592 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,219 @@ +# ERE — Agent Operating Instructions + +This file governs how AI agents operate in this repository. +It complements `CLAUDE.md` (which governs Claude Code specifically) and `.claude/CLAUDE.md` (project instructions). + +--- + +## Commits and PRs + +- **Never auto-commit** unless the user explicitly asks. +- **Never force-push** to `main` or `develop`. +- **Never add co-author lines**, tool names, or agent names to commit messages. +- Commit format: `type(scope): concise description` — e.g. `feat(adapters): add splink resolver factory`. +- Stage only files you modified: `git add `, never `git add -A` blindly. +- Before committing, run `make lint` and `make test-unit` to verify nothing is broken. +- PRs target `develop` (not `main`) unless told otherwise. +- When creating a PR, include a short summary and a test-plan checklist. + +--- + +## Working Methodology + +### Before touching code + +1. Read `WORKING.md` — it points to the active task file. +2. Read the referenced `docs/tasks/yyyy-mm-dd-*.md` fully. +3. Understand the current branch state: `git log --oneline -10`. + +### Running the stack for integration tests + +Integration tests require Redis to be running. Start it first: + +```bash +make infra-up # starts Redis + RedisInsight via Docker Compose +make test-integration # then run integration tests +make infra-down # tear down when done +``` + +Unit tests do **not** require any infrastructure: + +```bash +make test-unit # fast, self-contained, uses your venv +``` + +### Typical development loop + +```bash +make install # first time or after pyproject.toml changes +make test-unit # red → green → refactor +make lint # quick style check +make check-architecture # verify import-linter contracts +make all-quality-checks # before opening a PR +``` + +--- + +## Tooling Reference + +| Target | What it does | +|--------|-------------| +| `make install` | Install deps via Poetry | +| `make test-unit` | pytest unit suite + coverage report | +| `make test-integration` | integration tests (Redis must be up) | +| `make test-coverage` | HTML coverage report → `htmlcov/index.html` | +| `make lint` | pylint (fast, your venv) | +| `make format` | Ruff formatter | +| `make lint-fix` | Ruff auto-fix | +| `make check-clean-code` | pylint + radon + xenon (tox isolated) | +| `make check-architecture` | import-linter contracts (tox isolated) | +| `make all-quality-checks` | lint + clean-code + architecture | +| `make ci` | full tox pipeline (py312 + architecture + clean-code) | +| `make infra-up` | Start Redis stack (Docker Compose) | +| `make infra-down` | Stop Redis stack | +| `make infra-watch` | Live-reload mode (syncs `src/` and `src/config/`) | + +--- + +## Architecture Rules (enforced by import-linter) + +Dependency direction must never be violated: + +``` +entrypoints → services → models + ↘ + adapters → models +``` + +- `models/` — no I/O, no framework imports, no side effects. +- `adapters/` — infrastructure only; never calls `services/`. +- `services/` — orchestrates domain and adapters; never imports from `entrypoints/`. +- `entrypoints/` — parses input, calls services, formats output; no business logic. + +Violations block CI. Check with `make check-architecture` before opening a PR. + +--- + +## Memory Conventions + +Save to memory only what is non-obvious and persists across conversations: + +- Architectural decisions that aren't evident from the code (e.g. resolver factory registry pattern, DuckDB threading model). +- Design constraints explained by the user that aren't in comments or docs. +- User preferences about how to collaborate (e.g. "never suggest walrus operators", "prefer explicit factory injection"). + +Do **not** save to memory: +- Current task state (use the task file in `docs/tasks/`). +- Git history or recent changes (readable via `git log`). +- File paths or code structure (readable from the repo). + +--- + +## Gotchas + +- **`logging.basicConfig` is a no-op** when handlers already exist (conftest sets them up via `dictConfig`). Mock it with `patch("logging.basicConfig")` in logging tests. +- **DuckDB in tests**: use in-memory mode (`:memory:`) or a temp file via `tmp_path`; never a fixed path that leaks between tests. +- **Integration tests are marked** with `@pytest.mark.integration` — `make test-unit` skips them automatically. +- **`infra/.env`** is required for `make infra-*` targets. Copy from `infra/.env.example` on first use. +- **Config files** live in `src/config/` (moved from repo root in the 2026-04 restructure). Do not confuse with `infra/config/`. +- **erspec models** are LinkML-generated with snake_case fields (e.g. `legal_name`, not `legalName`). Do not edit generated files — update the schema and regenerate. +- **`ERE_LOG_LEVEL`** is the canonical env var for log level in this service (not `LOG_LEVEL`). + +--- + + +# GitNexus — Code Intelligence + +This project is indexed by GitNexus as **entity-resolution-engine-basic** (528 symbols, 1372 relationships, 36 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely. + +> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first. + +## Always Do + +- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user. +- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows. +- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits. +- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance. +- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`. + +## When Debugging + +1. `gitnexus_query({query: ""})` — find execution flows related to the issue +2. `gitnexus_context({name: ""})` — see all callers, callees, and process participation +3. `READ gitnexus://repo/entity-resolution-engine-basic/process/{processName}` — trace the full execution flow step by step +4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed + +## When Refactoring + +- **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`. +- **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code. +- After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed. + +## Never Do + +- NEVER edit a function, class, or method without first running `gitnexus_impact` on it. +- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis. +- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph. +- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope. + +## Tools Quick Reference + +| Tool | When to use | Command | +|------|-------------|---------| +| `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` | +| `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` | +| `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` | +| `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` | +| `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` | +| `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` | + +## Impact Risk Levels + +| Depth | Meaning | Action | +|-------|---------|--------| +| d=1 | WILL BREAK — direct callers/importers | MUST update these | +| d=2 | LIKELY AFFECTED — indirect deps | Should test | +| d=3 | MAY NEED TESTING — transitive | Test if critical path | + +## Resources + +| Resource | Use for | +|----------|---------| +| `gitnexus://repo/entity-resolution-engine-basic/context` | Codebase overview, check index freshness | +| `gitnexus://repo/entity-resolution-engine-basic/clusters` | All functional areas | +| `gitnexus://repo/entity-resolution-engine-basic/processes` | All execution flows | +| `gitnexus://repo/entity-resolution-engine-basic/process/{name}` | Step-by-step execution trace | + +## Self-Check Before Finishing + +Before completing any code modification task, verify: +1. `gitnexus_impact` was run for all modified symbols +2. No HIGH/CRITICAL risk warnings were ignored +3. `gitnexus_detect_changes()` confirms changes match expected scope +4. All d=1 (WILL BREAK) dependents were updated + +## Keeping the Index Fresh + +After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it: + +```bash +npx gitnexus analyze +``` + +If the index previously included embeddings, preserve them by adding `--embeddings`: + +```bash +npx gitnexus analyze --embeddings +``` + +To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.** + +> Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`. + +## CLI + +- Re-index: `npx gitnexus analyze` +- Check freshness: `npx gitnexus status` +- Generate docs: `npx gitnexus wiki` + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f49a4e1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f35fa84 --- /dev/null +++ b/Makefile @@ -0,0 +1,238 @@ +SHELL=/bin/bash -o pipefail + +# +# ERE Makefile: Developer-friendly interface for testing & quality assurance +# +# This Makefile provides quick, discoverable targets for common development tasks. +# It uses your active Poetry environment for fast feedback during development. +# +# For CI/CD: Use `tox` (see tox.ini) for reproducible, isolated test environments. +# tox is independent of Poetry and manages its own dependencies in CI. +# +# Three-environment model (Cosmic Python / Clean Code): +# make test-unit → pytest + coverage (your venv, fast) +# make lint → pylint checks (your venv, fast) +# make check-clean-code → tox isolated: pylint + radon + xenon +# make check-architecture → tox isolated: import-linter +# make all-quality-checks → full pipeline: lint + architecture + clean-code +# +# For CI/CD in GitHub Actions: +# tox -e py312,architecture,clean-code +# + +BUILD_PRINT = \e[1;34m +END_BUILD_PRINT = \e[0m + +PROJECT_PATH = $(shell pwd) +SRC_PATH = ${PROJECT_PATH}/src +TEST_PATH = ${PROJECT_PATH}/test +BUILD_PATH = ${PROJECT_PATH}/dist +INFRA_PATH = ${PROJECT_PATH}/src/infra +COMPOSE_FILE = ${INFRA_PATH}/compose.dev.yaml +ENV_FILE = ${INFRA_PATH}/.env + +# Auto-export all .env variables to every recipe shell (if the file exists) +ifneq ($(wildcard $(ENV_FILE)),) +include $(ENV_FILE) +ENV_VARS := $(shell sed -n '/^[[:space:]]*\#/d; /^[[:space:]]*$$/d; s/^[[:space:]]*\([A-Za-z_][A-Za-z0-9_]*\)[[:space:]]*=.*/\1/p' "$(ENV_FILE)") +export $(ENV_VARS) +endif + +PACKAGE_NAME = ere + +ICON_DONE = [✔] +ICON_ERROR = [x] +ICON_WARNING = [!] +ICON_PROGRESS = [-] + +#----------------------------------------------------------------------------- +# Dev commands +#----------------------------------------------------------------------------- +.PHONY: help install-poetry install build +help: ## Display available targets + @ echo -e "$(BUILD_PRINT)Available targets:$(END_BUILD_PRINT)" + @ echo "" + @ echo -e " $(BUILD_PRINT)Development:$(END_BUILD_PRINT)" + @ echo " install - Install project dependencies via Poetry" + @ echo " install-poetry - Install Poetry if not present" + @ echo " build - Build the package distribution" + @ echo "" + @ echo -e " $(BUILD_PRINT)Testing:$(END_BUILD_PRINT)" + @ echo " test - Run all tests" + @ echo " test-unit - Run unit tests with coverage (fast, your venv)" + @ echo " test-integration - Run integration tests only" + @ echo " test-coverage - Generate HTML coverage report" + @ echo "" + @ echo -e " $(BUILD_PRINT)Code Quality (Developer):$(END_BUILD_PRINT)" + @ echo " format - Format code with Ruff" + @ echo " lint - Run pylint checks (your venv, fast)" + @ echo " lint-fix - Auto-fix with Ruff" + @ echo "" + @ echo -e " $(BUILD_PRINT)Code Quality (CI/Isolated):$(END_BUILD_PRINT)" + @ echo " check-clean-code - Clean-code checks: pylint + radon + xenon (tox)" + @ echo " check-architecture - Validate layer contracts (tox)" + @ echo " all-quality-checks - Run all quality checks" + @ echo " ci - Full CI pipeline for GitHub Actions" + @ echo "" + @ echo -e " $(BUILD_PRINT)Infrastructure (Docker):$(END_BUILD_PRINT)" + @ echo " infra-build - Build the ERE Docker image" + @ echo " infra-up - Start services (docker compose up -d)" + @ echo " infra-down - Stop and remove stack containers and networks" + @ echo " infra-down-volumes - Stop services and remove volumes (clean slate)" + @ echo " infra-rebuild - Rebuild images and start services" + @ echo " infra-rebuild-clean - Rebuild from scratch (no cache) and start" + @ echo " infra-logs - Follow service logs" + @ echo " infra-watch - Start services with file watching (sync src/ and src/config/)" + @ echo "" + @ echo -e " $(BUILD_PRINT)Utilities:$(END_BUILD_PRINT)" + @ echo " clean - Remove build artifacts and caches" + @ echo " help - Display this help message" + @ echo "" + +install-poetry: ## Install Poetry if not present + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Installing Poetry $(END_BUILD_PRINT)" + @ pip install "poetry>=2.0.0" + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Poetry is installed$(END_BUILD_PRINT)" + +install: install-poetry ## Install project dependencies + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Installing ERE requirements$(END_BUILD_PRINT)" + @ cd src && poetry lock + @ cd src && poetry install --with dev + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) ERE requirements are installed$(END_BUILD_PRINT)" + +build: ## Build the package distribution + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Building package$(END_BUILD_PRINT)" + @ cd src && poetry build + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Package built successfully$(END_BUILD_PRINT)" + +#----------------------------------------------------------------------------- +# Testing commands +#----------------------------------------------------------------------------- +.PHONY: test test-unit test-integration test-coverage +test: ## Run all tests + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Running all tests$(END_BUILD_PRINT)" + @ cd src && poetry run pytest --rootdir=$(SRC_PATH) $(TEST_PATH) + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) All tests passed$(END_BUILD_PRINT)" + +test-unit: ## Run unit tests with coverage (fast, uses your venv) + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Running unit tests with coverage$(END_BUILD_PRINT)" + @ cd src && poetry run pytest --rootdir=$(SRC_PATH) $(TEST_PATH) -m "not integration" \ + --cov=ere --cov-report=term-missing --cov-report=html:htmlcov + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Unit tests passed (coverage: htmlcov/index.html)$(END_BUILD_PRINT)" + +test-integration: check-env ## Run integration tests only (requires Redis — run make infra-up first) + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Running integration tests$(END_BUILD_PRINT)" + @ cd src && poetry run pytest --rootdir=$(SRC_PATH) $(TEST_PATH) -m "integration" + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Integration tests passed$(END_BUILD_PRINT)" + +test-coverage: ## Generate detailed HTML coverage report + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Generating coverage report$(END_BUILD_PRINT)" + @ cd src && poetry run pytest --rootdir=$(SRC_PATH) $(TEST_PATH) -m "not integration" \ + --cov=ere --cov-report=html:htmlcov --cov-report=term-missing + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Coverage report: htmlcov/index.html$(END_BUILD_PRINT)" + +#----------------------------------------------------------------------------- +# Code quality commands +#----------------------------------------------------------------------------- +.PHONY: format lint lint-fix check-clean-code check-architecture all-quality-checks ci + +format: ## Format code with Ruff + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Formatting code$(END_BUILD_PRINT)" + @ cd src && poetry run ruff format $(SRC_PATH) $(TEST_PATH) + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Format complete$(END_BUILD_PRINT)" + +lint: ## Run pylint checks (style, naming, SOLID principles) — uses your venv + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Running pylint checks$(END_BUILD_PRINT)" + @ cd src && poetry run pylint --rcfile=$(PROJECT_PATH)/.pylintrc $(SRC_PATH)/ere $(TEST_PATH) + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Pylint checks passed$(END_BUILD_PRINT)" + +lint-fix: ## Auto-fix code style with Ruff + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Auto-fixing with Ruff$(END_BUILD_PRINT)" + @ cd src && poetry run ruff check --fix $(SRC_PATH) $(TEST_PATH) + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Auto-fix complete$(END_BUILD_PRINT)" + +check-clean-code: ## Clean-code checks: pylint + radon + xenon (isolated tox) + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Running clean-code checks (tox isolated)$(END_BUILD_PRINT)" + @ cd src && poetry run tox -e clean-code + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Clean-code checks passed$(END_BUILD_PRINT)" + +check-architecture: ## Validate architectural boundaries (isolated tox) + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Checking architecture contracts (tox isolated)$(END_BUILD_PRINT)" + @ cd src && poetry run tox -e architecture + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Architecture checks passed$(END_BUILD_PRINT)" + +all-quality-checks: lint check-clean-code check-architecture ## Run all: lint + clean-code + architecture + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) All quality checks passed!$(END_BUILD_PRINT)" + +ci: ## Full CI pipeline for GitHub Actions (tox) + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Running full CI pipeline$(END_BUILD_PRINT)" + @ set -a && . $(ENV_FILE) && set +a && poetry -C ./src run tox -e py312,architecture,clean-code + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) CI pipeline complete$(END_BUILD_PRINT)" + +#----------------------------------------------------------------------------- +# Infrastructure commands (Docker) +#----------------------------------------------------------------------------- +.PHONY: check-env infra-build infra-up infra-down infra-down-volumes infra-rebuild infra-rebuild-clean infra-logs infra-watch + +check-env: + @ test -f $(ENV_FILE) || (echo -e "$(BUILD_PRINT)$(ICON_ERROR) Missing $(ENV_FILE). Run: cp infra/.env.example infra/.env$(END_BUILD_PRINT)" && exit 1) + +infra-build: check-env ## Build the ERE Docker image + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Building ERE Docker image$(END_BUILD_PRINT)" + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) build + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) ERE image built$(END_BUILD_PRINT)" + +infra-up: check-env ## Start services (docker compose up -d) + @ docker network create ersys-local || true + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Starting ERE stack$(END_BUILD_PRINT)" + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) up -d + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) ERE stack is running — use 'make infra-logs' to follow output$(END_BUILD_PRINT)" + +infra-down: check-env ## Stop and remove ERE stack containers and networks + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Stopping ERE stack$(END_BUILD_PRINT)" + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) down + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) ERE stack stopped$(END_BUILD_PRINT)" + +infra-down-volumes: check-env ## Stop services and remove volumes (clean slate) + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Stopping ERE stack and removing volumes$(END_BUILD_PRINT)" + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) down -v + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) ERE stack stopped and volumes removed$(END_BUILD_PRINT)" + +infra-rebuild: check-env ## Rebuild images and start services + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Rebuilding ERE stack$(END_BUILD_PRINT)" + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) up -d --build + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) ERE stack rebuilt and started$(END_BUILD_PRINT)" + +infra-rebuild-clean: check-env ## Rebuild from scratch (no cache) and start + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Rebuilding ERE stack (no cache)$(END_BUILD_PRINT)" + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) build --no-cache + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) up -d + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) ERE stack rebuilt (clean) and started$(END_BUILD_PRINT)" + +infra-logs: check-env ## Follow service logs + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) logs -f + +infra-watch: check-env ## Start services with file watching (sync src/ and src/config/) + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Starting ERE stack with watch$(END_BUILD_PRINT)" + @ docker compose -f $(COMPOSE_FILE) --env-file $(ENV_FILE) watch + +#----------------------------------------------------------------------------- +# Utility commands +#----------------------------------------------------------------------------- +.PHONY: clean +clean: ## Remove build artifacts and caches + @ echo -e "$(BUILD_PRINT)$(ICON_PROGRESS) Cleaning build artifacts and caches$(END_BUILD_PRINT)" + @ rm -rf $(BUILD_PATH) + @ rm -rf .pytest_cache + @ rm -rf .tox + @ rm -rf *.egg-info + @ rm -rf src/*.egg-info + @ rm -rf htmlcov coverage.xml + @ cd src && poetry run ruff clean + @ find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true + @ find . -type f -name "*.pyc" -delete 2>/dev/null || true + @ find . -type f -name "*.pyo" -delete 2>/dev/null || true + @ echo -e "$(BUILD_PRINT)$(ICON_DONE) Clean complete$(END_BUILD_PRINT)" + +# Default target +.DEFAULT_GOAL := help diff --git a/README.md b/README.md index b2aae55..0d38610 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,373 @@ -# entity-resolution-engine-basic -A simple, demonstrator implementation of the Entity Resolution Engine (ERE). This serves as an example for developers to understand the ERE specification and message consumption logic. +# Basic Entity Resolution Engine (Basic ERE) + +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=OP-TED_entity-resolution-engine-basic&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=OP-TED_entity-resolution-engine-basic) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=OP-TED_entity-resolution-engine-basic&metric=coverage)](https://sonarcloud.io/summary/new_code?id=OP-TED_entity-resolution-engine-basic) +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE) +[![Python](https://img.shields.io/badge/Python-3.12-blue.svg)](https://www.python.org/downloads/) + +> A basic implementation of the ERE component of the Entity Resolution System (ERSys). + +## Overview + +The **Basic Entity Resolution Engine (Basic ERE)** is an asynchronous microservice that implements entity resolution for predefined entity types. It supports incremental clustering with stable cluster identifiers. + +Its primary purpose is to interact with the Entity Resolution System (ERSys). It adheres to the [ERS–ERE Technical Contract](docs/ERS-ERE-System-Technical-Contract.pdf), which establishes the communication protocol between ERE and ERS (part of ERSys) via a message queue (Redis). It also provides a foundation for other ERE implementations. + +### Capabilities + +* **Entity mention resolution**: Accepts a structured entity mention and returns one or more cluster candidates with similarity and confidence scores + +* **Cluster lifecycle management**: Creates new singleton clusters for unknown entities; assigns known entities to the best-matching cluster + +* **Canonical identifier derivation**: Derives cluster IDs deterministically: `SHA256(concat(source_id, request_id, entity_type))` + +* **Idempotent processing**: Re-submitting the same request (same identifier triad) returns the same clustering outcome + +* **Cold-start and incremental resolution**: Builds cluster structure organically without prior training data and doesn't require global reclustering. + +* **RDF data ingestion**: Accepts RDF (Turtle) entity data with configurable field mapping and extraction + +* **Declarative entity type support**: Arbitrary entity types specified via configuration files (no hardcoding) + +* **Automatic probabilistic model training**: Trains the entity resolution model on-the-fly as the mention database grows (based on statistical distribution and not human-in-the-loop; uses Expectation-Maximisation); + + +For detailed documentation, see: +- [Architecture](docs/architecture.md) - description of the applied architecture +- [Algorithm](docs/algorithm.md) - incremental probabilistic entity linking +- [Configuration](src/config/README.md) - field mapping, model tuning, Splink setup +- [Environment variables](src/config/README.md#environment-variables) - all env var definitions, defaults, and groups +- [ERS–ERE Technical Contract v0.2](docs/ERS-ERE-System-Technical-Contract.pdf) + + +### Dependencies + +ERE relies on **ers-spec** (from [entity-resolution-spec](https://github.com/OP-TED/entity-resolution-spec)), which provides: +- **Shared domain models** - Common entity types and concepts across the ERSys ecosystem +- **ERE contract message models** - Standardized request/response structures for ERE–ERS communication (`EntityMentionResolutionRequest`, `EntityMentionResolutionResponse`, `EREErrorResponse`) + +This ensures type-safe, versioned communication between ERE and other ERSys components. + +#### External Infrastructure Dependencies +To function, the ERE service requires the following external infrastructure: +- **Redis**: Used as the message broker for the request/response queues (`ere_requests` and `ere_responses`). +- **Docker**: Required for containerized deployment and local development. +- **Python 3.12**: The runtime environment for the engine. + + +## Getting Started + +> **To set up the complete ERSys stack** (ERS + ERE + Webapp), see the +> [Installation Guide](https://github.com/OP-TED/entity-resolution-service/blob/develop/INSTALL.md). +> The instructions below cover running ERE standalone. + +### Prerequisites + +- Python 3.12+ +- [Poetry](https://python-poetry.org/) 2.x +- Docker + Docker Compose + +### 1. Clone and install + +```bash +git clone https://github.com/OP-TED/entity-resolution-engine-basic.git +cd entity-resolution-engine-basic +make install +``` + +### 2. Configure the environment + +```bash +cp src/infra/.env.example src/infra/.env +``` + +The defaults work for local development. Notable variables in `src/infra/.env`: + +| Variable | Default | Description | +|----------|---------|-------------| +| `REDIS_HOST` | `ersys-redis` | Redis host (shared network `ersys-local`) | +| `REDIS_PORT` | `6379` | Redis port | +| `REDIS_PASSWORD` | `changeme` | Redis password — **must match ERS** | +| `REDIS_DB` | `0` | Redis database index | +| `REDIS_TLS` | `false` | Enable TLS-encrypted Redis connection — set to `true` when the Redis endpoint requires TLS | +| `ERSYS_REQUEST_QUEUE` | `ere_requests` | Inbound request queue name — **must match ERS** | +| `ERSYS_RESPONSE_QUEUE` | `ere_responses` | Outbound response queue name — **must match ERS** | +| `ERE_LOG_LEVEL` | `INFO` | Log level | +| `RDF_MAPPING_PATH` | *(bundled `/app/config/rdf_mapping.yaml`)* | Path to the RDF field mapping config YAML. Override to use a custom mapping outside Docker. | +| `RESOLVER_CONFIG_PATH` | *(bundled `/app/config/resolver.yaml`)* | Path to the Splink resolver config YAML. Override to use a custom resolver config outside Docker. | +| `DUCKDB_PATH` | *(resolver default)* | Path to the DuckDB database file. Leave unset to use the path defined in `resolver.yaml`. | + +> **Schema or configuration changes:** If you have modified `src/config/resolver.yaml` or +> `src/config/rdf_mapping.yaml` and the DuckDB database has already been initialised, +> remove the data volume before restarting to avoid schema mismatch errors: +> ```bash +> docker volume rm ere-local_ere-data +> # or for a full clean slate: +> make infra-down-volumes +> ``` + +### 3. Start the stack + +```bash +make infra-up # start ERE + Redis + RedisInsight +make infra-logs # follow service logs +make infra-down # stop all services + +Note: `make infra-up` creates a shared external network `ersys-local` used for cross-component communication. +To remove it manually: `docker network rm ersys-local` +``` + +> **Rebuilding with a clean cache:** If you have upgraded the source or made changes to the +> image and need to discard Docker layer cache, run: +> ```bash +> make infra-rebuild-clean +> ``` + +| Service | URL / Port | +|---------|-----------| +| Redis | `localhost:6379` | +| RedisInsight | `http://localhost:5540` | + +### What this stack does NOT include + +This repo starts ERE and its own Redis instance. It does **not** include the ERS backend or the web UI. + +ERE communicates exclusively through Redis queues — it has no HTTP API. Without ERS publishing requests to `ere_requests`, ERE will start and listen but process nothing. + +- To add ERS: follow the Getting Started section in [entity-resolution-service](https://github.com/OP-TED/entity-resolution-service#getting-started). +- To add the web UI: follow the Getting Started section in [entity-resolution-service-webapp](https://github.com/OP-TED/entity-resolution-service-webapp#getting-started). + +#### Running ERE alongside ERS (shared Redis) + +> For the full stack setup, see the +> [Installation Guide](https://github.com/OP-TED/entity-resolution-service/blob/develop/INSTALL.md). + +ERS starts its own Redis on port 6379. ERE also starts Redis on port 6379 by default — running both simultaneously causes a port conflict. + +**Solution**: let ERS own Redis, point ERE at it: + +1. In `src/infra/.env`, set `REDIS_HOST=ersys-redis` +2. Comment out the `ersys-redis` and `redisinsight` service blocks in `src/infra/compose.dev.yaml` +3. Start ERS first (`make up` in the ERS repo), then ERE (`make infra-up`) + +Queue names and `REDIS_PASSWORD` must match between both `.env` files (defaults already align). + +### 4. Run the demo + +With ERE running (`make infra-up`), launch the demo script to observe end-to-end resolution: + +```bash +cd src && poetry run python demo/demo.py # 8 mentions, 2 clusters (default) +cd src && poetry run python demo/demo.py --data demo/data/org-small.json # 100 mentions +``` + +> The demo connects directly to Redis (`localhost:6379`). Set `REDIS_HOST=localhost` in `src/infra/.env` before running. + +```bash +make infra-logs # inspect ERE service logs +make infra-down # stop when done +``` + +See [`src/demo/README.md`](src/demo/README.md) for datasets, configuration, and example output. + +--- + + +## Usage + +ERE has no HTTP API. It communicates exclusively through Redis message queues: +- **Request queue**: `ere_requests` - ERS publishes `EntityMentionResolutionRequest` messages +- **Response queue**: `ere_responses` - ERE publishes `EntityMentionResolutionResponse` or `EREErrorResponse` messages + + +### Make targets +Available targets (`make help`): +``` + Development: + install - Install project dependencies via Poetry + install-poetry - Install Poetry if not present + build - Build the package distribution + + Testing: + test - Run all tests + test-unit - Run unit tests with coverage (fast, your venv) + test-integration - Run integration tests only + test-coverage - Generate HTML coverage report + + Code Quality (Developer): + format - Format code with Ruff + lint - Run pylint checks (your venv, fast) + lint-fix - Auto-fix with Ruff + + Code Quality (CI/Isolated): + check-clean-code - Clean-code checks: pylint + radon + xenon (tox) + check-architecture - Validate layer contracts (tox) + all-quality-checks - Run all quality checks + ci - Full CI pipeline for GitHub Actions + + Infrastructure (Docker): + infra-build - Build the ERE Docker image + infra-up - Start services (docker compose up -d) + infra-down - Stop and remove stack containers and networks + infra-down-volumes - Stop services and remove volumes (clean slate) + infra-rebuild - Rebuild images and start services + infra-rebuild-clean - Rebuild from scratch (no cache) and start + infra-logs - Follow service logs + infra-watch - Start services with file watching (sync src/ and src/config/) + + Utilities: + clean - Remove build artifacts and caches + help - Display this help message +``` + +### Configuration (Resolver and Mapper) + +Entity resolution behaviour is configured via two YAML files: +- **Resolver configuration** ([resolver.yaml](./src/config/resolver.yaml)): Splink comparisons, cold-start parameters, similarity thresholds +- **RDF mapping** ([rdf_mapping.yaml](./src/config/rdf_mapping.yaml)): RDF namespace bindings, field extraction rules, entity type definitions + +For detailed configuration options and tuning, see the [configuration page](./src/config/README.md). + +### Examples + +A working demo is available that demonstrates ERE as a black-box service communicating through Redis queues. + +```bash +# Prerequisites: Redis must be running, ERE service must be listening +python src/demo/demo.py # Uses org-tiny.json (8 mentions, 2 clusters) +python src/demo/demo.py --data src/demo/data/org-small.json # 100 mentions, realistic clustering +``` + +The demo: +- Loads entity mentions from JSON datasets stored in `src/demo/data/` +- Sends mentions to the request queue via RDF Turtle messages +- Listens for resolution responses with cluster assignments +- Logs all interactions with timestamps and outputs a clustering summary + +**Datasets**: Multiple datasets available: +- `org-tiny.json` (default) — 8 organization mentions +- `org-small.json` — 100 organization mentions (corresponds to `test/stress/data/org-small.csv`) +- `org-mid.json` — 1,000 organization mentions (corresponds to `test/stress/data/org-mid.csv`) + +Note: For practical reasons (Turtle syntax is more verbose and less popular than JSON), the `demo.py` script accepts JSON files of a fixed structure and constructs RDF payloads from them on the fly. + +See [`src/demo/README.md`](src/demo/README.md) for datasets, configuration, logging, prerequisites, troubleshooting, and example output. + + +## Project + +### Repository Layout + +This repository places the self-contained Python project (source code, dependencies, and tooling config) under `src/`. The canonical `Makefile` lives at the repo root and owns all build logic. Recipes invoke `cd src &&` internally so that Poetry, Ruff, and pytest all resolve correctly against the `src/` project. All `make` targets are run from the repo root — no need to `cd src` first. + +### Structure + +ERE follows a **Cosmic Python layered architecture** that enforces clear separation of concerns and testability. The `src/ere/` directory contains four layers: domain models (pure business logic), services (use-case orchestration), adapters (infrastructure integrations), and entrypoints (external drivers). Test suites mirror this structure with unit, integration, and BDD scenarios, while documentation covers architecture decisions and implementation tasks. `src/demo/` provides working examples with sample datasets, and `src/infra/` contains containerisation and configuration for local development. + +``` +src/ +├── ere/ # Python package +│ ├── adapters/ # Redis client, cluster store, resolver implementations +│ ├── entrypoints/ # Redis pub/sub consumer +│ ├── models/ # Domain models (entities, value objects, exceptions) +│ └── services/ # Resolution use-case orchestration +├── config/ +│ ├── resolver.yaml # Splink comparisons, blocking rules, thresholds +│ ├── rdf_mapping.yaml # RDF namespace bindings, field extraction rules +│ └── README.md # Configuration documentation +├── demo/ +│ ├── demo.py # Entity resolution demonstration script +│ ├── data/ # Sample datasets (derived from TED procurement data) +│ └── README.md # Demo usage and configuration guide +├── infra/ +│ ├── Dockerfile # ERE service image definition +│ ├── compose.dev.yaml # Docker Compose for local development +│ └── .env.example # Environment variable template +├── pyproject.toml # Project metadata and dependencies +└── poetry.lock + +test/ +├── features/ # Gherkin BDD feature files +├── steps/ # pytest-bdd step definitions +├── integration/ # Integration tests (full stack) +├── e2e/ # End-to-end tests (Redis queue flows) +├── test_data/ # RDF test fixtures (Turtle) +└── conftest.py # Shared fixtures and test configuration + +docs/ +├── ERS-ERE-System-Technical-Contract.pdf +└── *.md # Architecture, algorithm, glossary +``` + +### Tooling + +| Category | Tools | +|---|---| +| Language | Python 3.12+ | +| Entity resolution engine | Splink (probabilistic record linkage) | +| Data storage | DuckDB (embedded) | +| Message broker | Redis | +| Package management | Poetry | +| Build & task runner | Make | +| Containerisation | Docker + Docker Compose | +| Test runner | pytest, pytest-bdd (Gherkin) | +| Code quality | Ruff (formatting, linting), Pylint (style/SOLID) | +| Architecture enforcement | importlinter (dependency validation) | + +### Data Sources + +The datasets stored in `demo/data/` and `test/` directories have been derived from public procurement data published by the European Commission at [TED (Tenders Electronic Daily)](https://ted.europa.eu/en/). These datasets are used for demonstration, testing, and benchmarking the entity resolution engine. The derived datasets maintain the character of the original procurement data while being tailored for the specific purposes of validating ERE functionality across realistic entity resolution scenarios. + + + +## Testing + +ERE has several test layers aligned with its Cosmic Python architecture. + +| Test Type | Location | Purpose | +|---|---|---| +| **Unit Tests (adapters)** | `test/unit/adapters/` | Verify individual adapter components (DuckDB repositories, RDF mapper, Splink linker) in isolation | +| **Unit Tests (services)** | `test/unit/services/` | Validate service-layer use-case orchestration; entity resolution workflow | +| **Integration Tests** | `test/integration/` | Test EntityResolver with all real adapters (DuckDB, Splink); full entity mention flow with clustering | +| **BDD Scenarios** | `test/features/` + `test/features/steps/` | Gherkin feature files + pytest-bdd step definitions; document resolution algorithm behaviour; verify clustering rules and thresholds | +| **End-to-End Tests** | `test/e2e/` | Full service startup; Redis queue integration; request/response payload structure validation | +| **Stress Tests** | `test/stress/` | Load testing and performance profiling; throughput and latency benchmarks | + +**Stress Test Datasets**: Committed to `test/stress/data/`. +See [Stress Test & Datasets README](test/stress/README.md) for dataset descriptions and usage. + +### Running Tests + +```bash +# All tests (unit + integration; requires Docker) +make test + +# Unit tests only (no Docker required) +make test-unit + +# Integration tests (requires Docker) +make test-integration + +# Code formatting and linting +make format # Auto-format with Ruff +make lint # Lint without modifying files +make lint-fix # Lint with auto-fix +``` + +### Key Testing Practices + +- **TDD by default** - write failing tests before implementing features +- **Layer isolation** - each layer tests its own responsibility only +- **Fixture-driven setup** - reusable fixtures in `conftest.py` for service/mapper creation + + +## Contributing + +Contributions are welcome. Please open an issue before submitting a pull request. + +- Follow the existing code style (run `make lint-check` before pushing) +- Write tests for new behaviour (BDD features or unit tests) +- Keep commits small and well-described +- Branch naming: `feature//` (e.g. `feature/ERS1-124/conflict-detection`) + +For development workflow and architecture guidelines, see [CLAUDE.md](.claude/CLAUDE.md). diff --git a/docs/ERS-ERE-System-Technical-Contract.pdf b/docs/ERS-ERE-System-Technical-Contract.pdf new file mode 100644 index 0000000..481ed82 Binary files /dev/null and b/docs/ERS-ERE-System-Technical-Contract.pdf differ diff --git a/docs/algorithm.md b/docs/algorithm.md new file mode 100644 index 0000000..201dbbd --- /dev/null +++ b/docs/algorithm.md @@ -0,0 +1,129 @@ +# Entity Resolution Algorithm + +## Overview + +The ERE (Entity Resolution Engine) implements an **online clustering algorithm** that resolves entity mentions into clusters incrementally as they arrive. Each incoming mention is scored against existing mentions, assigned to the best-matching cluster (if the similarity meets a threshold), or creates a new singleton cluster. + + + +## Core Concept + +Mentions are grouped into **clusters** representing the same real-world entity. A mention belongs to exactly one cluster at any given time. When a new mention arrives: + +1. **Score** it against existing mentions using a similarity function and evaluate match probability +2. **Persist** all computed match probabilities (mention-links) +3. **Assign** the mention to the best-matching cluster or create a new one +4. **Return** a ranked list of candidate clusters + + + +## Resolution Flow + +For each incoming mention `m`: + +### Step 0: Check for Known Mention (Idempotency) +If the mention was already resolved in a prior request: +- **Return cached result** (the ranked list of candidates from the previous resolution) +- Do not re-run the full resolution pipeline (avoids duplicate entries in repositories) +- The cached result reflects current cluster state (if other mentions have joined the cluster since, scores may have updated) + +If the mention is unknown, proceed to Step 1. + +### Step 1: Find Candidates +Apply **blocking rules** to identify a subset of existing mentions to compare with (reduces computational cost). This prevents every new mention from being compared against every existing mention. + +### Step 2: Compute Similarities +Compare the new mention against all candidate mentions using a similarity linker (e.g., Splink for probabilistic name matching). This produces: +- **Pairwise similarity scores** (all stored, regardless of threshold) +- **Mention-links**: records that a comparison exists between two mentions + +Note: The algorithm delegates similarity computation to Splink, which provides match probabilities. These roughly correspond to similarity scores but differ in one significant aspect: Splink probabilities are discrete (not continuous) for performance reasons. Consequently, two pairs of mentions may have slightly different similarity scores (e.g., Jaro-Winkler) but the same probability score. Nevertheless, this has no major impact on the overall outcome. + +### Step 3: Cluster Assignment (Greedy Online) +- Find the **best-matching mention** (highest similarity among candidates) +- If best similarity ≥ **threshold**: + - **Extend** the cluster of the best match +- Otherwise: + - **Create new singleton cluster** with this mention as the sole member. Similarity to the new cluster is 0. + +Note: Order of arrival matters. The algorithm makes a greedy decision based only on the best current match, with no retrospective re-clustering. + +### Step 4: Persist and Update +- Save the mention to the repository (now part of the search space) +- Register the mention with the similarity linker (part of the candidate set for future mentions) + +### Step 5: Generate Candidate Output +Return a ranked list of candidate clusters: +- Include the cluster the mention was assigned to (with best-match similarity, or 0.0 if singleton) +- Include other clusters that have a computed link to this mention (below-threshold similarities) +- Rank by similarity score +- Prune to top-N (configurable, default 100) + +### Step 5: Generate Candidate Output +Return a ranked list of candidate clusters: +- Include the cluster to which the mention was assigned (with best-match similarity, or 0.0 if singleton) +- Include other clusters that have a computed link to this mention (below-threshold similarities) +- Rank by similarity score +- Prune to top-N (configurable, default 100) + +Output is never empty; at least the cluster to which the mention was assigned (existing or newly created) is always returned. + + + +## Key Design Decisions + +### All Similarities Stored, Not All Create Edges +- **Mention-links** (computed similarities) are preserved regardless of threshold; they're used to propose alternative candidate clusters in the resolution response +- **Cluster membership** (cluster edges) uses only the single best match ≥ threshold +- This enables: + - Cluster formation via strong matches only + - Alternative candidates to be returned even if below threshold (for user review, A/B testing, etc.) + +### Threshold vs. Below-Threshold +- **Threshold-gated**: Determines whether a mention joins an existing cluster +- **Below-threshold links**: Still recorded; contribute to candidate generation and ranking +- A mention can appear as a candidate for multiple clusters via different link paths + +### Online Greedy, Not Batch +The algorithm processes mentions one at a time, making immediate clustering decisions. This is efficient but order-dependent: +- Early mentions establish clusters +- Later mentions join based on similarity to whoever was seen first +- Retrospective re-clustering is not performed + + + +## Selected configuration Parameters + +| Parameter | Purpose | +|--|--| +| **threshold** | Minimum similarity score to extend an existing cluster | +| **top_n** | Maximum candidate clusters returned per mention | +| **blocking_rules** | Pre-filters to reduce similarity computation | + +The complete list of configuration parameters together with comprehensive description is available in [Configuration](../config/README.md). + +## Outputs + +For each resolved mention, the service returns a **ResolutionResult**: + +```python +ResolutionResult( + candidates: tuple[ + CandidateCluster( + cluster_id: ClusterId, # Unique cluster identifier + score: float # Similarity score (best mention-link to this cluster) + ), + ... + ] +) +``` + +**Properties:** +- **Non-empty**: Always contains at least one candidate (the mention's own cluster) +- **Ranked**: Sorted descending by score +- **Pruned**: Limited to top-N candidates (default 100, configurable) +- **Complete**: Includes: + - The cluster the mention was assigned to (score = 0.0 if singleton, or best-match similarity) + - Other clusters linked via mention-links (below-threshold similarities) + +The first CandidateCluster (`.candidates[0]`) is the algorithm's implied best cluster for the mention. Additional references represent alternatives based on computed similarities. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..02613ac --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,42 @@ +# ERE Architecture + +This document describes the layered architecture of ERE. + + +## Layered Architecture + +ERE follows [Cosmic Python](https://www.cosmicpython.com/) layered architecture with a strict +one-way dependency flow: + +``` +entrypoints → services → models + ↘ + adapters → models +``` + +| Layer | Path | Responsibility | +|---|---|---| +| **Models** | `src/ere/models/` | Domain entities (`EntityMention`, `ClusterReference`, …), value objects, pure business rules — no I/O | +| **Adapters** | `src/ere/adapters/` | Infrastructure: Redis client, cluster store, `AbstractResolver` implementations | +| **Services** | `src/ere/services/` | Use-case orchestration; owns transaction boundaries and resolution workflow | +| **Entrypoints** | `src/ere/entrypoints/` | Redis pub/sub consumer; thin layer that parses input and delegates to services | + +Architectural boundaries are enforced at CI time via `importlinter`. + + +## Async Pub/Sub Interface + +ERE communicates exclusively through Redis pub/sub channels: + +``` +ERS Redis ERE +────────────────── ────────────────────── ────────────────────────── +Publish request → [ere_requests] → Consume & validate + Resolve entity mention + Publish clustering outcome +Consume response ← [ere_responses] ← (cluster_id + scores) +``` + +Requests and responses are JSON-serialised `ERERequest` / `EREResponse` subclasses. +The contract is intentionally decoupled from the transport: any broker that supports +at-least-once delivery and idempotent semantics may be used. diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 0000000..98d1375 --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,43 @@ +# Entity Resolver Glossary + +This document defines the domain terms and business rules for the Entity Resolver component. + +--- + +## Terms + +| Term | Definition | +|---|---| +| **Mention** | An incoming data record representing one observation of a real-world entity. The primary unit processed in each resolution request. A mention belongs to exactly one cluster at any point in time. | +| **Entity** | A distinct real-world organization that one or more mentions may refer to. Not directly stored — inferred through the cluster a mention belongs to. | +| **Entity Resolution** | The process of determining which mentions refer to the same real-world entity and grouping them accordingly. | +| **Cluster** | A set of mentions determined to refer to the same real-world entity. Each cluster has a unique ID, initialized to the mention ID of the first mention in the cluster. | +| **Cluster ID** | The identifier of a cluster. Initialized to the mention ID of the first mention assigned to that cluster. Serves as the canonical identifier for the entity the cluster represents. | +| **Cluster Reference** | A `(cluster_id, score)` pair returned as part of the resolution output. Identifies a candidate cluster and expresses how strongly it is associated with the resolved mention. | +| **Resolution Request `r(m)`** | A request to resolve a single mention `m`. Produces a ranked list of cluster references, with the top-ranked entry being the algorithm's implied canonical cluster for the mention. | +| **Blocking** | A pre-filtering step that narrows the set of existing mentions to compare against, based on blocking rules. Reduces unnecessary computation. | +| **Blocking Rules (BR)** | Declarative rules used to eliminate mention pairs that cannot plausibly match (e.g., different country). | +| **Pairwise Similarity Score** | A numeric value in [0, 1] expressing how similar two mentions are, as computed by the similarity function. | +| **Threshold (THR)** | The minimum pairwise similarity score required for a mention to be added to an existing cluster. Default: 0.8. | +| **Mention Link** | A recorded association between two mentions for which a similarity score has been computed, regardless of whether that score meets THR. Used for candidate cluster discovery. | +| **Cluster Extension** | The act of adding a mention to an existing cluster because its best pairwise similarity with any existing mention is ≥ THR. A mention can be added to at most one cluster per resolution request. | +| **Comparison Function / Identity Function** | A per-entity-type function that defines which entity properties are taken into consideration when determining similarity between two mentions. Fixed per entity type. | +| **Candidate Clusters / Cluster References** | The output of a resolution request: a ranked list of cluster references, pruned to top-N. Cannot be empty. The top entry is the implied canonical cluster for the resolved mention. | +| **N** | The maximum number of cluster references returned per resolution request. Default: 100. User-configurable. | + +--- + +## Business Rules + +1. Each resolution request processes exactly one mention and always returns at least one cluster reference. +2. The top-ranked cluster reference in the output is the algorithm's implied canonical cluster for the mention. +3. A mention is added to an existing cluster only if its best pairwise similarity with any existing mention is ≥ THR. +4. Only the single best-matching existing mention determines cluster assignment per request. +5. If no candidate passes THR (or blocking produces an empty candidate set), a new singleton cluster is created with Cluster ID = mention ID. +6. All computed pairwise similarities are stored — including those below THR — as mention links. +7. Candidate cluster discovery (`genCand`) uses mention links regardless of THR, then ranks by cluster-level similarity score. +8. Output is always pruned to top-N cluster references. +9. A mention belongs to exactly one cluster at any point in time. +10. No global reclustering: cluster state is updated incrementally per resolution request. +11. Comparison Function is fixed per entity type. +12. Data management must be efficient: computations that can be performed at the database level must be done there; excessive data fetching into application memory must be avoided. diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..0a21d94 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,140 @@ +# SonarCloud Configuration for Entity Resolution Engine (ERE) +# =========================================================== +# This file configures quality gates and analysis for SonarCloud. +# See: https://docs.sonarcloud.io/ + +#----------------------------------------------------------------------------- +# Project Identity +#----------------------------------------------------------------------------- + +# Must be unique in SonarCloud instance +sonar.projectKey=meaningfy-ws_entity-resolution-engine-basic +sonar.organization=meaningfy-ws + +# Display name and version +sonar.projectName=Entity Resolution Engine (ERE) +sonar.projectVersion=1.0.0 + +#----------------------------------------------------------------------------- +# Code Analysis Paths +#----------------------------------------------------------------------------- + +# Source code location (relative to sonar-project.properties) +sonar.sources=src/ere +sonar.tests=test + +# Source encoding +sonar.sourceEncoding=UTF-8 + +# Python version (must match pyproject.toml requires-python) +sonar.python.version=3.12 + +#----------------------------------------------------------------------------- +# Coverage & Test Report Paths +#----------------------------------------------------------------------------- + +# Coverage report (generated by pytest-cov via tox) +sonar.python.coverage.reportPaths=coverage.xml + +# Test results report (if using XML format) +sonar.python.xunit.reportPath=test-results.xml + +# Pylint report (optional, for additional insights) +sonar.python.pylint.reportPath=pylint-report.txt + +#----------------------------------------------------------------------------- +# Exclusions (don't analyze these) +#----------------------------------------------------------------------------- + +# Exclude test files from coverage metrics +sonar.coverage.exclusions=test/**/*,setup.py,**/__init__.py + +# Exclude test files from duplication detection +sonar.cpd.exclusions=test/**/* + +# Exclude documentation and config files from analysis +sonar.exclusions=docs/**/*,*.md,src/infra/**/*,src/demo/**/* + +#----------------------------------------------------------------------------- +# SOLID Principles & Clean Code Quality Gates +#----------------------------------------------------------------------------- + +# Single Responsibility Principle (SRP) +# Cognitive complexity per function (max 15 is recommended) +sonar.python.S3776.threshold=15 + +# Cyclomatic complexity per function (max 10 is good practice) +sonar.python.S1541.threshold=10 + +# Max lines per function (enforce small, focused functions) +sonar.python.S104.max=50 + +# Max lines per class (enforce focused classes) +sonar.python.S1188.max=500 + +# Open/Closed Principle (OCP) +# Discourage too many conditional statements (suggests need for polymorphism) +sonar.python.S1066.max=3 + +# Liskov Substitution Principle (LSP) +# Limit inheritance depth to avoid deep hierarchies +sonar.python.S110.max=4 + +# Don't Repeat Yourself (DRY) - Related to SOLID +# Minimum duplicate lines to trigger an issue +sonar.cpd.python.minimumLines=3 + +# Minimum duplicate tokens +sonar.cpd.python.minimumTokens=50 + +#----------------------------------------------------------------------------- +# Quality Gate Configuration +# +# Note: These conditions must also be configured in SonarCloud UI under: +# Organization Settings → Quality Gates → Create "ERE SOLID Gate" +# +# Create custom quality gate with these conditions on New Code: +# - Critical Issues: is greater than 0 → FAIL +# - Blocker Issues: is greater than 0 → FAIL +# - Security Hotspots Reviewed: is less than 100% → FAIL +# - Coverage: is less than 80% → FAIL +# - Duplicated Lines: is greater than 3% → FAIL +# - Code Smells: is greater than 0 → FAIL (optional) +# +#----------------------------------------------------------------------------- + +# Wait for quality gate result (useful in CI) +sonar.qualitygate.wait=true +sonar.qualitygate.timeout=300 + +# Branch analysis configuration +sonar.branch.autoconfig.disabled=false + +#----------------------------------------------------------------------------- +# Maintainability & Code Quality Thresholds +# +# Rating scale: +# A = tech debt ratio <= 5% +# B = tech debt ratio 6-10% +# C = tech debt ratio 11-20% +# +#----------------------------------------------------------------------------- + +# Enforce at least B rating +sonar.maintainability.rating.threshold=B + +# New code should have zero code smells (potential issues) +sonar.newCode.codeSmells=0 + +# Overall complexity threshold for functions +sonar.complexity.threshold=10 + +#----------------------------------------------------------------------------- +# Reporting +#----------------------------------------------------------------------------- + +# Generate reports for historical tracking +sonar.report.export.path=sonar-report + +# Verbose logging (helpful for debugging) +sonar.verbose=false diff --git a/src/VERSION b/src/VERSION new file mode 100644 index 0000000..61cb4de --- /dev/null +++ b/src/VERSION @@ -0,0 +1 @@ +1.1.0-rc.4 diff --git a/src/config/README.md b/src/config/README.md new file mode 100644 index 0000000..3ce3235 --- /dev/null +++ b/src/config/README.md @@ -0,0 +1,209 @@ +# Entity resolver Configuration + +The Entity Resolver is the core component of the Basic ERE (Entity Resolution Engine) service. +It is responsible for identifying and linking entities across different data sources, +ensuring consistency and accuracy in entity identification and consolidation. + +This page provides configuration details and guidelines for the Entity Resolver component. + + +Configuration files control the entity resolution algorithm behavior, including similarity matching, blocking rules, thresholds, and statistical priors. This directory contains two primary configuration files. + +--- + +## Overview + +### resolver.yaml +The main configuration file for the entity resolver. Defines: +- **Entity fields** to extract from RDF (legal name, address components) +- **Database settings** (DuckDB type and location) +- **Clustering thresholds** (when a mention joins an existing cluster) +- **Output limits** (max candidate clusters per resolution) +- **Blocking rules** (which mention pairs to compare) +- **Statistical models** (Splink comparisons, cold-start priors, EM training) + +### rdf_mapping.yaml +Maps RDF entity types to extraction rules. Defines: +- **Supported entity types** (e.g., ORGANISATION) +- **RDF type discriminator** (which RDF class identifies an organization) +- **Field property paths** (how to traverse RDF to extract attributes) + +The entity fields defined in `resolver.yaml` must match the field names in `rdf_mapping.yaml`. + +--- + +## Environment Variables + +ERE is configured at runtime through environment variables. The service reads directly from the process environment; it does not load `.env` files itself. When running via Docker Compose, the `env_file` directive in `compose.dev.yaml` applies `src/infra/.env` to the container. When running the service directly, export the variables in your shell beforehand. + +### Configuration groups + +**Logging** — Controls verbosity of the ERE service log output. `ERE_LOG_LEVEL` accepts standard Python logging level strings (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`) plus the custom `TRACE` level (below `DEBUG`) defined in `src/ere/utils/logging.py`. + +**Queues** — Redis list keys used to exchange messages with ERS. `ERSYS_REQUEST_QUEUE` is the inbound queue ERE reads resolution requests from; `ERSYS_RESPONSE_QUEUE` is the queue ERE writes results back to. Both must match the corresponding values set on the ERS side. + +**Redis** — Connection settings for the Redis message broker. The four connection variables (`REDIS_HOST`, `REDIS_PORT`, `REDIS_DB`, `REDIS_PASSWORD`) must point to the same Redis instance used by ERS. Set `REDIS_TLS=true` to require a TLS-encrypted connection (e.g. AWS ElastiCache with in-transit encryption). + +**Storage** — Paths to the DuckDB database and the YAML configuration files that drive entity resolution behaviour. When unset, `RESOLVER_CONFIG_PATH` and `RDF_MAPPING_PATH` fall back to the bundled files baked into the Docker image at `/app/config/`. `DUCKDB_PATH` is optional — when unset, the path defined inside `resolver.yaml` is used. + +### Variable reference + +| Name | Group | Description | Default | Mandatory | +| :--- | :--- | :--- | :--- | :---: | +| `DUCKDB_PATH` | Storage | Path to the DuckDB database file. Leave unset to use the path defined in `resolver.yaml`. | *(from resolver.yaml)* | No | +| `ERE_LOG_LEVEL` | Logging | Python logging level for the ERE service. Accepts `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`, and the custom `TRACE` level. | `INFO` | No | +| `ERSYS_REQUEST_QUEUE` | Queues | Redis list key ERE reads inbound resolution requests from. Must match the ERS-side queue name. | `ere_requests` | No | +| `ERSYS_RESPONSE_QUEUE` | Queues | Redis list key ERE writes resolution responses to. Must match the ERS-side queue name. | `ere_responses` | No | +| `RDF_MAPPING_PATH` | Storage | Path to the RDF field mapping config YAML. Defines namespace bindings and field extraction rules for each entity type. When unset, falls back to the bundled file at `/app/config/rdf_mapping.yaml` inside the Docker image. | *(bundled `/app/config/rdf_mapping.yaml`)* | No | +| `REDIS_DB` | Redis | Redis database index. | `0` | No | +| `REDIS_HOST` | Redis | Redis server hostname or endpoint. | `localhost` | No | +| `REDIS_PASSWORD` | Redis | Redis authentication password. Leave empty if Redis AUTH is not configured. | | No | +| `REDIS_PORT` | Redis | Redis server port. | `6379` | No | +| `REDIS_TLS` | Redis | Enable TLS-encrypted connections to Redis. Set to `true` when the Redis endpoint requires TLS (e.g. AWS ElastiCache with in-transit encryption). | `false` | No | +| `RESOLVER_CONFIG_PATH` | Storage | Path to the Splink resolver config YAML. Defines comparisons, blocking rules, and similarity thresholds. When unset, falls back to the bundled file at `/app/config/resolver.yaml` inside the Docker image. | *(bundled `/app/config/resolver.yaml`)* | No | + +--- + +## Configuration Parameters + +| Parameter | Type | Default | Purpose | +|-----------|------|---------|---------| +| **entity_fields** | list | `[legal_name, country_code, nuts_code, post_code, post_name, thoroughfare]` | RDF attributes to extract and use for similarity computation | +| **duckdb.type** | string | `persistent` | Database mode: `persistent` (file-based) or `in-memory` (test/ephemeral) | +| **duckdb.path** | string | `data/app.duckdb` | Database file location (only for persistent mode; overridden by DUCKDB_PATH env var) | +| **cache_strategy** | string | `tf_incremental` | Search space caching: `tf_incremental` (term-frequency incremental) | +| **threshold** | float (0.0–1.0) | `0.20` | Minimum match probability for cluster assignment. Lower = more sensitive (higher recall, lower precision); higher = more selective | +| **top_n** | int | `100` | Maximum cluster candidates returned per mention (pruning limit) | +| **match_weight_threshold** | float | `-10` | Pre-filter on Splink match weight; `-10` captures below-threshold links needed for full candidate output | +| **auto_train_threshold** | int | `50` | Mention count at which to trigger background EM training (0 = disabled) | +| **probability_two_random_records_match** | float (0.0–1.0) | `0.003` | Fellegi-Sunter prior λ: baseline probability any two records match (affects all m/u probability ratios) | + +--- + +## Splink Comparisons + +The `splink.comparisons` section defines similarity functions and their thresholds. Each comparison produces gamma levels (discrete similarity buckets). + +| Field | Type | Thresholds | Purpose | +|-------|------|-----------|---------| +| **legal_name** | jaro_winkler | [0.9, 0.8] | Primary identifier; primary signal for match determination | +| **country_code** | exact_match | — | Blocking rule only (not used in comparison); preserves EM flexibility | +| **nuts_code** | exact_match | — | EU regional code; exact match or missing data | +| **post_code** | jaro_winkler | [0.95, 0.85] | Postal/ZIP code; typo-tolerant with high thresholds | +| **post_name** | jaro_winkler | [0.90, 0.80] | City name; captures spelling variants and abbreviations | +| **thoroughfare** | jaro_winkler | [0.95, 0.85] | Street address; highly specific, typos uncommon | + +**Interpretation:** Each threshold defines a gamma level. For example, `legal_name` with thresholds `[0.9, 0.8]` produces three levels: +- Gamma 2: JW ≥ 0.9 (highest match) +- Gamma 1: 0.8 ≤ JW < 0.9 (medium match) +- Gamma 0: JW < 0.8 (no match) + +--- + +## Blocking Rules + +Pairs are compared only if **at least one** blocking rule matches. This reduces computation significantly. + +**Current configuration:** +```yaml +blocking_rules: + - country_code # Primary: same country (strict) + - [country_code, nuts_code] # Secondary: same country AND same EU region +``` + +**Semantics:** +- Rule 1: Pair must have matching country codes +- Rule 2: Pair must have matching country codes **AND** matching NUTS codes (if both present) +- At least one rule must fire for comparison to occur + +**Effect:** Drastically reduces comparison volume while preserving global comparisons within country. + +--- + +## Cold-Start Priors + +Before EM training, Splink uses cold-start m/u probabilities. These are empirically tuned defaults: + +- **m_probability**: Likelihood of observing this gamma level **given the records match** +- **u_probability**: Likelihood of observing this gamma level **given the records are independent** (random pair) + +Example (legal_name): +```yaml +m_probabilities: [0.9, 0.6, 0.025, 0.005] # Gamma levels 2, 1, 0, (implicit no-match) +u_probabilities: [0.00001, 0.0004, 0.004, 0.99559] +``` + +- If records match, high JW (gamma 2) is very likely (m=0.9) +- If records are random, high JW is very unlikely (u=0.00001) +- Likelihood ratio: 0.9 / 0.00001 = 90,000× evidence for match + +**Note:** Once EM training completes (at `auto_train_threshold`), these are replaced by empirically learned parameters. + +--- + +## Fine-Tuning the Resolver + +### Precision vs. Recall + +- **Increase recall** (catch more matches): Lower `threshold` or lower `m_probabilities` for weak signals +- **Increase precision** (reduce false positives): Raise `threshold` or raise `u_probabilities` + +### Field Contribution + +Fields with higher m/u ratios have stronger influence. To emphasize address over name: +- Increase `m_probabilities` for address fields (post_code, thoroughfare) +- Decrease `m_probabilities` for weaker signals (post_name) + +### Blocking Granularity + +- **Tighter blocking** (fewer comparisons): Add more rules, require more fields to match +- **Looser blocking** (more comparisons, slower): Fewer rules, match-any semantics + +Example: To enable cross-country matches within same organization parent: +```yaml +blocking_rules: + - legal_name # Only compare if legal names are very similar +``` + +### EM Training + +Once `auto_train_threshold` is reached, background EM estimation updates m/u parameters based on your data. This is more accurate than cold-start but requires representative data (ideally ~500+ mentions). + +To disable: Set `auto_train_threshold: 0` + +--- + +## References + +- **Splink documentation**: [Splink — Entity resolution at scale](https://moj-analytical-services.github.io/splink/) + - Blocking rules: https://moj-analytical-services.github.io/splink/blocking.html + - Comparisons: https://moj-analytical-services.github.io/splink/comparison_library.html + - EM training: https://moj-analytical-services.github.io/splink/em_help.html + +- **Fellegi-Sunter model**: [The Fellegi-Sunter model in Splink](https://moj-analytical-services.github.io/splink/theory/fellegi_sunter.html) + +- **ERE algorithm**: See `../../docs/algorithm.md` for detailed explanation of the online greedy clustering approach. + +--- + +## Troubleshooting + +**Too many false positives (precision too low):** +- Increase `threshold` (e.g., 0.20 → 0.35) +- Increase `u_probabilities` for weak signals (less evidence needed) +- Tighten blocking rules (fewer comparisons, more selective) + +**Missing matches (recall too low):** +- Decrease `threshold` (e.g., 0.20 → 0.10) +- Decrease `m_probabilities` for strong signals (more generous) +- Loosen blocking rules (more comparisons, more chances to match) + +**Slow performance:** +- Reduce `entity_fields` (fewer attributes to compare) +- Tighten blocking rules (fewer pairs to evaluate) +- Decrease `match_weight_threshold` to filter more low-confidence pairs before storing + +**Training not converging:** +- Increase `auto_train_threshold` (collect more data before training) +- Manually inspect cluster quality to ensure ground truth is reasonable +- Consider adjusting cold-start priors as fallback diff --git a/src/config/rdf_mapping.yaml b/src/config/rdf_mapping.yaml new file mode 100644 index 0000000..4b856ed --- /dev/null +++ b/src/config/rdf_mapping.yaml @@ -0,0 +1,20 @@ +# Namespace prefix registry - used by rdf_mapper.py to resolve prefixed names in field paths +namespaces: + epo: "http://data.europa.eu/a4g/ontology#" + org: "http://www.w3.org/ns/org#" + locn: "http://www.w3.org/ns/locn#" + cccev: "http://data.europa.eu/m8g/" + +# Entity type mappings: entity_type_string -> rdf_type + field property paths +# Property paths use / as separator for multi-hop traversal. +# Field names must match entity_fields in resolver.yaml (legal_name, country_code). +entity_types: + ORGANISATION: + rdf_type: "org:Organization" + fields: + legal_name: "epo:hasLegalName" + country_code: "cccev:registeredAddress/epo:hasCountryCode" + nuts_code: "cccev:registeredAddress/epo:hasNutsCode" + post_code: "cccev:registeredAddress/locn:postCode" + post_name: "cccev:registeredAddress/locn:postName" + thoroughfare: "cccev:registeredAddress/locn:thoroughfare" diff --git a/src/config/resolver.yaml b/src/config/resolver.yaml new file mode 100644 index 0000000..66ba0d8 --- /dev/null +++ b/src/config/resolver.yaml @@ -0,0 +1,163 @@ +# Entity Resolver configuration — Extended blocking (address fields) +# Supports Jaro-Winkler similarity with geographic granularity via NUTS, PostCode, PostName, Thoroughfare. +# +# Entity fields: names must match fields in rdf_mapping.yaml entity_types.ORGANISATION.fields +entity_fields: + - legal_name + - country_code + - nuts_code + - post_code + - post_name + - thoroughfare + +# DuckDB database configuration +duckdb: + # type: in-memory # Options: "in-memory" or "persistent" + type: persistent +# path: data/app.duckdb # Default path for persistent mode (overridden by DUCKDB_PATH env var) + +cache_strategy: tf_incremental + +# Cluster assignment threshold: requires match_probability >= threshold for cluster join. +# Address-enriched model is expected to be more confident; starting at 0.20. +# Adjust downward if precision is too low; upward if recall is insufficient. +threshold: 0.20 + +# Maximum cluster references returned per resolve_request() call. +top_n: 100 + +# Lower bound on match weight passed to find_matches_to_new_records(). +# -10 captures below-threshold links needed for full candidate output. +match_weight_threshold: -10 + +# Automatic training threshold: trigger non-blocking EM at N mentions. +auto_train_threshold: 50 + +splink: + # Prior: Fellegi-Sunter λ (probability any two records match). + # With address fields, expect slightly higher match rate (finer granularity helps). + # Using 0.003 (vs 0.0022 for name-only) to account for address signal. + probability_two_random_records_match: 0.003 + + # Comparisons: identity functions and similarity scoring for pairwise evaluation. + # NOTE: country_code used only in blocking rules, not comparisons (to preserve EM training). + # Address fields complement legal_name matching for disambiguation and confidence. + comparisons: + + # Primary identifier: legal name with Jaro-Winkler thresholds + # Unchanged from baseline: 0.9 (very high similarity), 0.8 (quite similar), else (low) + - type: jaro_winkler + field: legal_name + thresholds: [0.9, 0.8] + + # Supporting signals (lower confidence than legal name, but disambiguate) + + # NUTS code (Nomenclature of Territorial Units for Statistics) + # Exact match only: same NUTS = same region, no NUTS = missing data. + # Most EU organizations in procurement have NUTS; non-EU lack it. + # Confidence: Match implies same country+region (but not unique identifier). + - type: exact_match + field: nuts_code + + # Post Code (postal / ZIP code) + # Jaro-Winkler with high thresholds for typo tolerance + - type: jaro_winkler + field: post_code + thresholds: [0.95, 0.85] + + # Post Name (city/locality name, e.g., "Frankfurt am Main") + # Jaro-Winkler at [0.90, 0.80]: captures abbreviations, accents, spelling variations + # 0.90: high confidence (e.g., "München" vs "Munich" should match, or with accents) + # 0.80: moderate confidence (e.g., "St. John's" vs "St Johns", abbreviation variations) + # Caveat: multiple companies in same city; not alone sufficient for match. + - type: jaro_winkler + field: post_name + thresholds: [0.90, 0.80] + + # Thoroughfare (street address: road name + house number) + # Jaro-Winkler at [0.95, 0.85]: very high threshold due to specificity + # 0.95: near-identical streets (captures digit transpositions: "4 Main" vs "5 Main") + # 0.85: captures common abbreviations ("Street" vs "St.", "Avenue" vs "Ave") + # Rationale: Street addresses are highly specific; typos are unusual but possible. + # Organizations may move offices, so don't rely on this alone. + - type: jaro_winkler + field: thoroughfare + thresholds: [0.95, 0.85] + + # Country code: exact match only (baseline blocking rule support). + # NOTE: Used in blocking only; comparison is a no-op (all same-country pairs). + - type: exact_match + field: country_code + + # Blocking rules: pairs are compared only if at least ONE rule fires. + # Expressed as field names; multi-field rules use a list. + # + # Design: country-level primary blocking, NUTS-level secondary for EU. + blocking_rules: + # Primary: country code (strict rule: must match country) + - country_code + + # Secondary (EU-specific): country + NUTS code blocking for finer granularity + # Enables disambiguation of large countries (e.g., Germany's 290+ regions). + # Falls back gracefully: if NUTS missing, country-only rule fires. + # Only applies when both records have NUTS (common for EU procurement data). + - [country_code, nuts_code] + + # Cold-start default m/u probabilities (used before EM training). + # Each comparison field gets distributions for each similarity level. + # Once EM training completes, trained parameters overwrite these. + cold_start: + comparisons: + + legal_name: + # JaroWinkler [0.9, 0.8]: high / medium / low similarity + # m_prob: likelihood of match at each similarity tier (empirically tuned) + # u_prob: likelihood in random records (opposite population) + m_probabilities: [0.9, 0.6, 0.025, 0.005] + u_probabilities: [0.00001, 0.0004, 0.004, 0.99559] + + country_code: + # ExactMatch: match / no-match + # Near-deterministic: matching country codes strongly imply same country. + m_probabilities: [0.99, 0.01] + u_probabilities: [0.10, 0.90] + + nuts_code: + # ExactMatch: match / no-match + # Strong signal: same NUTS region = same EU administrative region. + # However, some organizations have operations across multiple NUTS (parent + branches). + # m_prob=0.92: "likely same location" but not identity. + # u_prob=0.08: in random records, small chance of NUTS collision across large geographic areas. + m_probabilities: [0.92, 0.08] + u_probabilities: [0.05, 0.95] + + post_code: + # Jaro-Winkler [0.95, 0.85]: very high / high / low similarity + # m_prob: 0.85 (95% match), 0.40 (85% match), 0.02 (low) + # - 0.95 JW: nearly identical postal codes + # - 0.85 JW: postal codes with minor variations (digit transposition, typo) + # - else: different postal zone or missing data + # u_prob: 0.02 (95% match - rare collision), 0.08 (85% match), 0.90 (low) + m_probabilities: [0.85, 0.40, 0.02, 0.005] + u_probabilities: [0.02, 0.08, 0.08, 0.82] + + post_name: + # JaroWinkler [0.90, 0.80]: high / moderate / low similarity + # Moderate confidence: city names are less unique than addresses. + # Multiple organizations can be in same city. + # m_prob: 0.65 (90% match), 0.25 (80% match), 0.01 (low) + # u_prob: 0.05 (90% match), 0.15 (80% match), 0.80 (low) + m_probabilities: [0.65, 0.25, 0.01, 0.005] + u_probabilities: [0.05, 0.15, 0.15, 0.65] + + thoroughfare: + # JaroWinkler [0.95, 0.85]: very high / high / low similarity + # Very strong signal: street addresses are highly specific. + # Same street + building = likely same organization (or landlord info). + # m_prob: 0.85 (95% match), 0.50 (85% match), 0.02 (low) + # - 95% JW match: almost certainly same office location + # - 85% JW match: likely same street but possibly different building/unit + # - low: different address or missing data + # u_prob: 0.01 (95% match - street collision rare), 0.08 (85% match), 0.91 (low) + m_probabilities: [0.85, 0.50, 0.02, 0.005] + u_probabilities: [0.01, 0.08, 0.08, 0.83] diff --git a/src/config/resolver_compound.yaml b/src/config/resolver_compound.yaml new file mode 100644 index 0000000..47ff9d9 --- /dev/null +++ b/src/config/resolver_compound.yaml @@ -0,0 +1,25 @@ +# Entity Resolver configuration — Compound blocking (country_code AND city) +# Blocks pairs unless both country_code AND city match. +# Creates tight, city-level blocks within countries. +# Trade-off: fewer comparisons (faster) but may miss cross-city variants. + +cache_strategy: tf_incremental + +threshold: 0.5 + +top_n: 100 + +match_weight_threshold: -10 + +splink: + probability_two_random_records_match: 0.3 + + comparisons: + - type: jaro_winkler + field: legal_name + thresholds: [0.9, 0.8] + + # Compound blocking rule: a pair is compared only if both country_code AND city match. + # This is expressed as a list with two fields. + blocking_rules: + - [country_code, city] diff --git a/src/config/resolver_multirule.yaml b/src/config/resolver_multirule.yaml new file mode 100644 index 0000000..c8395c9 --- /dev/null +++ b/src/config/resolver_multirule.yaml @@ -0,0 +1,28 @@ +# Entity Resolver configuration — Multi-rule blocking (country OR city OR name) +# Three independent blocking rules evaluated as OR (union). +# A pair is included if any rule fires: same country, OR same city, OR exact name match. +# Trade-off: more comparisons (slower) but higher recall for diverse datasets. + +cache_strategy: tf_incremental + +threshold: 0.5 + +top_n: 100 + +match_weight_threshold: -10 + +splink: + probability_two_random_records_match: 0.3 + + comparisons: + - type: jaro_winkler + field: legal_name + thresholds: [0.9, 0.8] + + # Multi-rule blocking: three independent rules, evaluated as UNION ALL. + # A pair is included if any rule fires (country_code match, OR city match, OR exact legal_name match). + # Splink deduplicates the results internally. + blocking_rules: + - country_code + - city + - legal_name diff --git a/src/demo/README.md b/src/demo/README.md new file mode 100644 index 0000000..304612a --- /dev/null +++ b/src/demo/README.md @@ -0,0 +1,257 @@ +# ERE Demo - Indirect Redis Client + +This demo demonstrates the Entity Resolution Engine (ERE) as an indirect client communicating through Redis queues. + +## Overview + +The demo: +- Connects to Redis (checking connectivity first) +- Creates 6 synthetic entity mentions +- Sends them as `EntityMentionResolutionRequest` messages to the request queue +- Listens for `EntityMentionResolutionResponse` messages from the response queue +- Logs all interactions with timestamps + +The demo treats ERE as a black box service accessible only through Redis message queues. This is useful for: +- Testing the queue-based infrastructure in isolation +- Demonstrating service-to-service communication patterns + + +## Configuration + +Configuration is loaded from `infra/.env` (or environment variables): + +| Variable | Default | Purpose | +|----------|---------|---------| +| `REDIS_HOST` | `redis` | Redis hostname (use `localhost` for local testing) | +| `REDIS_PORT` | `6379` | Redis port | +| `REDIS_DB` | `0` | Redis database number | +| `REDIS_PASSWORD` | `changeme` | Redis password | +| `ERSYS_REQUEST_QUEUE` | `ere_requests` | Queue name for incoming requests | +| `ERSYS_RESPONSE_QUEUE` | `ere_responses` | Queue name for outgoing responses | + +The script tries the configured host first, then falls back to `localhost` if the host is `redis` (Docker), making it work both locally and in Docker. + +## Prerequisites + +1. **Redis must be running** on the configured host/port +2. **ERE service must be running** (or at least the queue worker must be processing messages) +3. **Project dependencies installed** via Poetry: `poetry install` + +## Running the Demo + +### 1. With Docker Compose (recommended) + +Start the full stack including Redis and ERE: + +```bash +make infra-rebuild +``` + +Wait for services to be ready (check logs): + +```bash +make infra-logs +``` + +### 2. Locally (development) + +If you're running Redis locally (e.g., Docker container on `localhost:6379`): + +```bash +# Ensure Redis is running +redis-cli ping # should return "PONG" + +# Run the demo +cd /home/greg/PROJECTS/ERS/ere-basic +python3 src/demo/demo.py +``` + +Or with Poetry: + +```bash +poetry run python3 src/demo/demo.py +``` + +**Runtime**: Approximately 5-35 seconds (5s sending + up to 30s waiting for responses). +The demo sends messages with 1-second delays between them, then waits for responses. + +### Using Different Datasets + +By default, the demo loads `src/demo/data/org-tiny.json`. Specify a different dataset with the `--data` parameter: + +```bash +# Use mentions dataset +poetry run python3 src/demo/demo.py --data src/demo/data/mentions_100b.json + +# Use larger dataset +poetry run python3 src/demo/demo.py --data src/demo/data/org-mid.json +``` + +Available datasets in `src/demo/data/`: +- `org-tiny.json` (default) — 8 organization mentions, 2 clusters +- `org-small.json` — Small (100 mentions) organization dataset +- `org-mid.json` — Mid-size (1000 mentions) organization dataset + +## Example Output + +The demo logs all interactions with timestamps and provides a clustering summary at the end: + +``` +2026-03-01 12:34:56 [INFO] Loading configuration... +2026-03-01 12:34:56 [INFO] Redis config: host=localhost, port=6379, db=0 +2026-03-01 12:34:56 [INFO] Queue names: request=ere_requests, response=ere_responses +2026-03-01 12:34:56 [INFO] Checking Redis connectivity... +2026-03-01 12:34:56 [INFO] ✓ Redis is available +2026-03-01 12:34:56 [INFO] Clearing request and response queues... +2026-03-01 12:34:56 [INFO] Sending 8 entity mentions... +2026-03-01 12:34:56 [INFO] → Sent request m1: Stadt Osnabrück [Mention 1] +2026-03-01 12:34:57 [INFO] → Sent request m2: Stadt Osnabrück — Fachdienst Öffentliche Aufträge [Mention 2] +... +2026-03-01 12:34:56 [INFO] Listening for responses... +2026-03-01 12:34:56 [INFO] ✓ Response received for m1: +2026-03-01 12:34:56 [INFO] Type: EntityMentionResolutionResponse +2026-03-01 12:34:56 [INFO] Timestamp: 2026-03-01T12:34:56.123456+00:00 +2026-03-01 12:34:56 [INFO] Candidates: +2026-03-01 12:34:56 [INFO] 1. Cluster 8cf6eabbf0edb0fe58fb0c346a7fc3c78ef4939518b1a6f349548c2d6a9953c2: confidence=0.95, similarity=0.95 +... +2026-03-01 12:35:00 [INFO] Demo complete. Received 8/8 responses. + +================================================================================ +CLUSTERING SUMMARY +================================================================================ + +8cf6eabbf0edb0fe58fb0c346a7fc3c78ef4939518b1a6f349548c2d6a9953c2 (3 members): + m1 | Stadt Osnabrück + m2 | Stadt Osnabrück — Fachdienst Öffentliche Aufträge + m5 | Stadt Osnabrück, Zentrale + +914d738331f965d12ca7a0bb964473ce53876d308862b4f46e242de4a3ff6348 (3 members): + m3 | Conseil départemental Haute-Garonne + m4 | Conseil départemental Haute-Garonne Service Public + m6 | Conseil Haute-Garonne + +================================================================================ +2026-03-01 12:35:00 [INFO] ✓ All responses received successfully! +``` + +The demo logs: +- **Request tracking**: Each sent mention with descriptive details +- **Response logging**: Received cluster candidates with confidence/similarity scores +- **Clustering summary**: Final cluster assignments with member organizations (by default, saved to `src/demo/log/`) +- **Extended logging**: Trace-level logging for detailed resolution diagnostics + +## Demo Data + +Datasets are stored in `src/demo/data/` (JSON format with RDF Turtle content). + +### Dataset Correspondence to Stress Tests + +Demo JSON datasets map to CSV datasets in `test/stress/data/` for reproducible benchmarking. + +## Message Format + +### Request (EntityMentionResolutionRequest) + +```json +{ + "type": "EntityMentionResolutionRequest", + "entity_mention": { + "identifiedBy": { + "request_id": "m1", + "source_id": "DEMO", + "entity_type": "ORGANISATION" + }, + "content": "@prefix org: ...", + "content_type": "text/turtle" + }, + "timestamp": "2026-03-01T12:34:56.123456+00:00", + "ere_request_id": "m1:01" +} +``` + +### Response (EntityMentionResolutionResponse) + +```json +{ + "type": "EntityMentionResolutionResponse", + "entity_mention_id": { + "request_id": "m1", + "source_id": "DEMO", + "entity_type": "ORGANISATION" + }, + "candidates": [ + { + "cluster_id": "m1", + "confidence_score": 0.0, + "similarity_score": 0.0 + } + ], + "timestamp": "2026-03-01T12:34:56.234567+00:00", + "ere_request_id": "m1:01" +} +``` + +## Troubleshooting + +### "Redis unavailable" error + +**Check Redis connectivity:** +```bash +redis-cli -h localhost -p 6379 ping +``` + +If it returns `PONG`, Redis is running. If not: + +- **Docker**: `docker run -d -p 6379:6379 redis:latest` +- **Local Redis**: `brew install redis && brew services start redis` (macOS) +- **Docker Compose**: Ensure the service is running: `make infra-up` + +### Timeout waiting for responses + +**Possible causes:** +- ERE service is not running (no worker to process requests) +- Request queue name doesn't match ERE's configured queue name +- ERE worker crashed or stopped processing + +**Check ERE logs:** +```bash +make infra-logs +``` + +### Password authentication fails + +**Edit Redis connection parameters:** + +Option 1: Modify `infra/.env`: +```bash +REDIS_PASSWORD=your_password +``` + +Option 2: Set environment variable: +```bash +export REDIS_PASSWORD=your_password +python3 src/demo/demo.py +``` + +## Design Notes + +- **No direct Python API**: The demo uses Redis as the sole communication channel +- **Message logging**: Every request sent and response received is logged with timestamp +- **Connectivity check**: The demo verifies Redis is accessible before sending messages +- **Queue cleanup**: Request and response queues are cleared at the start of the demo +- **Timeout handling**: The demo waits up to 30 seconds for responses, then reports the count received +- **Docker fallback**: If the configured Redis host is "redis" (Docker), the demo tries localhost as a fallback for local development + +## Logging + +The demo logs all activity to: +- **Console**: INFO-level messages (requests, responses, clustering summary) +- **Log file**: `src/demo/log/demo_YYYYMMDD-HHMM--DATASETNAME.log` with TRACE-level diagnostics + - Trace logs include detailed resolution diagnostics (field extraction, similarity scoring, etc.) + - Clustering summary included at the end of each log file + +Configure logging via environment variable: +```bash +export LOG_LEVEL=TRACE # TRACE, DEBUG, INFO, WARNING, ERROR +python3 src/demo/demo.py +``` diff --git a/src/demo/__init__.py b/src/demo/__init__.py new file mode 100644 index 0000000..f6b9566 --- /dev/null +++ b/src/demo/__init__.py @@ -0,0 +1 @@ +"""ERE Demo - Indirect Redis Client for Entity Resolution Engine.""" diff --git a/src/demo/data/org-mid.json b/src/demo/data/org-mid.json new file mode 100644 index 0000000..09f8592 --- /dev/null +++ b/src/demo/data/org-mid.json @@ -0,0 +1,11006 @@ +{ + "name": "1000 Organizations Test Dataset (Mid-Scale Address Fields)", + "description": "1000 organizations from 29 countries with complete address data. Extracted from TED procurement records.", + "mentions": [ + { + "request_id": "d000001", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SNAGA, družba za ravnanje z odpadki in druge komunalne storitve, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Nasipna ulica 64" + }, + { + "request_id": "d000002", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Zavod Republike Slovenije za transfuzijsko medicino", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Šlajmerjeva ulica 6" + }, + { + "request_id": "d000003", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universitair Ziekenhuis Gent", + "country_code": "BEL", + "nuts_code": "BE234", + "post_code": "9000", + "post_name": "Gent", + "thoroughfare": "Corneel Heymanslaan 10" + }, + { + "request_id": "d000004", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Markt Eggolsheim", + "country_code": "DEU", + "nuts_code": "DE248", + "post_code": "91330", + "post_name": "Eggolsheim", + "thoroughfare": "Hauptstraße 27" + }, + { + "request_id": "d000005", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bright Professionals bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Haarlem", + "thoroughfare": null + }, + { + "request_id": "d000006", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Eurohelp Consult", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "200217", + "post_name": "Craiova", + "thoroughfare": "Str. Pictor Obedeanu Oscar nr. 13" + }, + { + "request_id": "d000007", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ville d'Antibes Juan-les-Pins", + "country_code": "FRA", + "nuts_code": "FRL03", + "post_code": "06606", + "post_name": "Antibes Cedex", + "thoroughfare": "Direction de la commande publique, bâtiment «Orange bleu», 4e étage, 11 boulevard Chancel, BP 2205" + }, + { + "request_id": "d000008", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Reta - prevozi Marko Krže s.p.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1310", + "post_name": "Ribnica", + "thoroughfare": "Žlebič 38" + }, + { + "request_id": "d000009", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Iași", + "thoroughfare": "Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000010", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Česká republika – Ministerstvo vnitra", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": null, + "post_name": "Praha 7", + "thoroughfare": null + }, + { + "request_id": "d000011", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gmina Nowy Tomyśl", + "country_code": "POL", + "nuts_code": "PL", + "post_code": "64-300", + "post_name": "Nowy Tomyśl", + "thoroughfare": "Poznańska 33" + }, + { + "request_id": "d000012", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hispano Igualadina, S. L.", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08700", + "post_name": "Igualada", + "thoroughfare": "C/ Mestre Montaner, 50" + }, + { + "request_id": "d000013", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sicurezza e ambiente srl", + "country_code": "ITA", + "nuts_code": "ITI43", + "post_code": null, + "post_name": "Roma", + "thoroughfare": null + }, + { + "request_id": "d000014", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Osnabrück — Fachdienst Öffentliche Aufträge", + "country_code": "DEU", + "nuts_code": "DE944", + "post_code": "49074", + "post_name": "Osnabrück", + "thoroughfare": "Bierstraße 2" + }, + { + "request_id": "d000015", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medicina trgovina d.o.o.", + "country_code": "HRV", + "nuts_code": "HR", + "post_code": "10257", + "post_name": "Brezovica", + "thoroughfare": "Zeleni brijeg 1C" + }, + { + "request_id": "d000016", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Full Body Insight, S. L.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "46520", + "post_name": "Sagunto (Valencia)", + "thoroughfare": "Avenida 9 d´Octubre, 106, entresuelo, despacho 9" + }, + { + "request_id": "d000017", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vermögen und Bau Baden-Württemberg Amt Karlsruhe", + "country_code": "DEU", + "nuts_code": "DE122", + "post_code": "76131", + "post_name": "Karlsruhe", + "thoroughfare": "Engesserstraße 1" + }, + { + "request_id": "d000018", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "OMV Petrom Marketing", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "013329", + "post_name": "Bucureşti", + "thoroughfare": "Str. Coralilor nr. 22, sector 1" + }, + { + "request_id": "d000019", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bpifrance Assurance Export", + "country_code": "FRA", + "nuts_code": "FR107", + "post_code": "94710", + "post_name": "Maisons-Alfort Cedex", + "thoroughfare": "27-31 avenue du Général-Leclerc" + }, + { + "request_id": "d000020", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Weiss Dienstleistungen GmbH", + "country_code": "DEU", + "nuts_code": "DE21H", + "post_code": null, + "post_name": "Planegg", + "thoroughfare": null + }, + { + "request_id": "d000021", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fakultní nemocnice v Motole", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "150 06", + "post_name": "Praha 5", + "thoroughfare": "V Úvalu 84" + }, + { + "request_id": "d000022", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tinmar Energy S.A.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "014476", + "post_name": "București", + "thoroughfare": "Str. Floreasca nr. 246C" + }, + { + "request_id": "d000023", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Albert Ziegler GmbH", + "country_code": "DEU", + "nuts_code": "DE11C", + "post_code": null, + "post_name": "Giengen", + "thoroughfare": null + }, + { + "request_id": "d000024", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Deloitte expertises Européennes et politiques publiques", + "country_code": "FRA", + "nuts_code": "FRL04", + "post_code": "13002", + "post_name": "Marseille", + "thoroughfare": "immeuble Castel Office, boulevard Jacques Saadé" + }, + { + "request_id": "d000025", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "EMM Life Science AB", + "country_code": "SWE", + "nuts_code": "SE110", + "post_code": "129 39", + "post_name": "Hägersten", + "thoroughfare": "EMM Life Science AB, Mamsell Ullas Väg 3" + }, + { + "request_id": "d000026", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Österreichische Bundesforste AG", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "3002", + "post_name": "Purkersdorf", + "thoroughfare": "Pummergasse 10-12" + }, + { + "request_id": "d000027", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ville de Lens", + "country_code": "FRA", + "nuts_code": "FRE12", + "post_code": "62300", + "post_name": "Lens", + "thoroughfare": "17 bis place Jean Jaurès" + }, + { + "request_id": "d000028", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Archiwum Narodowe w Krakowie", + "country_code": "POL", + "nuts_code": "PL213", + "post_code": "30-960", + "post_name": "Kraków", + "thoroughfare": "ul. Sienna 16" + }, + { + "request_id": "d000029", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "InnovationSPIN Lemgo GmbH", + "country_code": "DEU", + "nuts_code": "DEA45", + "post_code": "32657", + "post_name": "Lemgo", + "thoroughfare": "Johannes-Schuchen-Straße 4" + }, + { + "request_id": "d000030", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UMO Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL", + "post_code": "05-220", + "post_name": "Zielonka", + "thoroughfare": "ul. Henryka Sienkiewicza 61" + }, + { + "request_id": "d000031", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kemofarmacija, veletrgovina za oskrbo zdravstva, d.d.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Cesta na Brdo 100" + }, + { + "request_id": "d000032", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Transportes Urbanos de Sevilla, S. A. M.", + "country_code": "ESP", + "nuts_code": "ES618", + "post_code": "41007", + "post_name": "Sevilla", + "thoroughfare": "Avenida Andalucía, 11" + }, + { + "request_id": "d000033", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "RSG", + "country_code": "FRA", + "nuts_code": "FRY30", + "post_code": "97300", + "post_name": "Cayenne", + "thoroughfare": "8 rue des Bourdins, ZI Collery 1" + }, + { + "request_id": "d000034", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CEZ Vânzare S.A.", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "200769", + "post_name": "Craiova", + "thoroughfare": "Str. Severinului nr. 97" + }, + { + "request_id": "d000035", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "VTT Technical Research Centre of Finland Ltd", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "02044", + "post_name": "Espoo", + "thoroughfare": "PO Box 1000, VTT" + }, + { + "request_id": "d000036", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tinmar Energy S.A.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "014476", + "post_name": "București", + "thoroughfare": "Str. Floreasca nr. 246C" + }, + { + "request_id": "d000037", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vergabe und Beschaffungszentrum Dortmund", + "country_code": "DEU", + "nuts_code": "DEA52", + "post_code": "44135", + "post_name": "Dortmund", + "thoroughfare": "Viktoriastraße 15" + }, + { + "request_id": "d000038", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Les repas sant2", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "69340", + "post_name": "Francheville", + "thoroughfare": null + }, + { + "request_id": "d000039", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universiteit Twente", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "7500 AE", + "post_name": "Enschede", + "thoroughfare": "Postbus 217" + }, + { + "request_id": "d000040", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "L3P Architekten ETH FH SIA, AG", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "8158", + "post_name": "Regensberg", + "thoroughfare": "Unterburg, 33" + }, + { + "request_id": "d000041", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Strungariu & CO Rigams LM SNC", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "707027", + "post_name": "Iași", + "thoroughfare": "Str. Carpați nr. 5" + }, + { + "request_id": "d000042", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Iași", + "thoroughfare": "Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000043", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Conseil départemental Haute-Garonne", + "country_code": "FRA", + "nuts_code": "FRJ23", + "post_code": "31090", + "post_name": "Toulouse Cedex 9", + "thoroughfare": "1 boulevard de la Marquette" + }, + { + "request_id": "d000044", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Uppsala Innovation Centre AB", + "country_code": "SWE", + "nuts_code": "SE121", + "post_code": null, + "post_name": "Uppsala", + "thoroughfare": null + }, + { + "request_id": "d000045", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SARL HBM Architectes (titulaire)", + "country_code": "FRA", + "nuts_code": "FRJ22", + "post_code": "12000", + "post_name": "Rodez", + "thoroughfare": "37 rue Béteille" + }, + { + "request_id": "d000046", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ned Com", + "country_code": "ROU", + "nuts_code": "RO223", + "post_code": "905700", + "post_name": "Constanța", + "thoroughfare": "Str. Vârfu cu Dor nr. 26" + }, + { + "request_id": "d000047", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dirección General — Osakidetza", + "country_code": "ESP", + "nuts_code": "ES21", + "post_code": "01006", + "post_name": "Vitoria-Gasteiz", + "thoroughfare": "C/ Álava, 45" + }, + { + "request_id": "d000048", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle", + "country_code": "DEU", + "nuts_code": "DED41", + "post_code": "09111", + "post_name": "Chemnitz", + "thoroughfare": "Friedensplatz 1" + }, + { + "request_id": "d000049", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Merit Medical Systems AB", + "country_code": "SWE", + "nuts_code": "SE110", + "post_code": "114 79", + "post_name": "Stockholm", + "thoroughfare": "Box 1485" + }, + { + "request_id": "d000050", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SARL clinic auto: point's", + "country_code": "FRA", + "nuts_code": "FRK22", + "post_code": "07200", + "post_name": "Aubenas", + "thoroughfare": "ZA Moulon" + }, + { + "request_id": "d000051", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Staatsbetrieb Sächsisches Immobilien- und Baumanagement, Zentrale, SSC VVM, Außenstelle Dresden 1, Zentrale Vergabestelle", + "country_code": "DEU", + "nuts_code": "DED2", + "post_code": "01099", + "post_name": "Dresden", + "thoroughfare": "Königsbrücker Str. 80" + }, + { + "request_id": "d000052", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Syddansk Universitet", + "country_code": "DNK", + "nuts_code": "DK0", + "post_code": "5230", + "post_name": "Odense M", + "thoroughfare": "Udbudskontoret" + }, + { + "request_id": "d000053", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Markt Berchtesgaden", + "country_code": "DEU", + "nuts_code": "DE215", + "post_code": "83471", + "post_name": "Berchtesgaden", + "thoroughfare": "Rathausplatz 1" + }, + { + "request_id": "d000054", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Ignitis“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": null, + "post_name": "Vilnius", + "thoroughfare": null + }, + { + "request_id": "d000055", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Verovškova ulica 70" + }, + { + "request_id": "d000056", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Johanniter-Unfall-Hilfe e.V.", + "country_code": "DEU", + "nuts_code": "DEA11", + "post_code": "40233", + "post_name": "Düsseldorf", + "thoroughfare": "Erkrather Str. 245" + }, + { + "request_id": "d000057", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kiinteistö Oy Biomedicum Helsinki", + "country_code": "FIN", + "nuts_code": "FI1B", + "post_code": "FI-00290", + "post_name": "Helsinki", + "thoroughfare": "Haartmaninkatu 8" + }, + { + "request_id": "d000058", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SCHLÜTER+THOMSEN Ingenieurgesellschaft mbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DEF04", + "post_code": "24537", + "post_name": "Neumünster", + "thoroughfare": "Rendsburger Straße 162" + }, + { + "request_id": "d000059", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AIG Europe, S. A., Sucursal España", + "country_code": "ESP", + "nuts_code": "ES120", + "post_code": null, + "post_name": "Madrid", + "thoroughfare": null + }, + { + "request_id": "d000060", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeinde Hallwang", + "country_code": "AUT", + "nuts_code": "AT323", + "post_code": "5300", + "post_name": "Hallwang", + "thoroughfare": "Dorfstraße 45" + }, + { + "request_id": "d000061", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "S.C. Nisara Impex S.R.L", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "505600", + "post_name": "Săcele", + "thoroughfare": "Str. Gen. I. Dragalina nr. 21 A" + }, + { + "request_id": "d000062", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Phinelec", + "country_code": "FRA", + "nuts_code": "FRL", + "post_code": "13015", + "post_name": "Marseille", + "thoroughfare": "21 rue André Hallar" + }, + { + "request_id": "d000063", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vejle Kommune", + "country_code": "DNK", + "nuts_code": "DK032", + "post_code": "7100", + "post_name": "Vejle", + "thoroughfare": "Skolegade 1" + }, + { + "request_id": "d000064", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SDU", + "country_code": "DNK", + "nuts_code": "DK", + "post_code": null, + "post_name": "Odense M", + "thoroughfare": null + }, + { + "request_id": "d000065", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Schenker Deutschland AG", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "40472", + "post_name": "Düsseldorf", + "thoroughfare": null + }, + { + "request_id": "d000066", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Espoon kaupunki", + "country_code": "FIN", + "nuts_code": "FI1B1", + "post_code": "FI-02070", + "post_name": "Espoo", + "thoroughfare": "PL 640" + }, + { + "request_id": "d000067", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Protección y Electrónica del Sur, S. L.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "41500", + "post_name": "Alcalá de Guadaíra (Sevilla)", + "thoroughfare": "C/ Equidad, 16, polígono industrial Cabeza Hermosa" + }, + { + "request_id": "d000068", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CAP sciences CCSTI", + "country_code": "FRA", + "nuts_code": "FRI12", + "post_code": "33300", + "post_name": "Bordeaux", + "thoroughfare": "hangar 20 quai Bacalan" + }, + { + "request_id": "d000069", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Talend Germany GmbH", + "country_code": "DEU", + "nuts_code": "DEA22", + "post_code": "53113", + "post_name": "Bonn", + "thoroughfare": "Baunscheidstr. 17" + }, + { + "request_id": "d000070", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Secretaría General de la Fundación Internacional y para Iberoamérica de Administración Políticas Públicas", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": "28040", + "post_name": "Madrid", + "thoroughfare": "C/ Beatriz de Bobadilla, 18, 4.ª planta" + }, + { + "request_id": "d000071", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Distrito de Arganzuela", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": "28045", + "post_name": "Madrid", + "thoroughfare": "Paseo de la Chopera, 10" + }, + { + "request_id": "d000072", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Società cattolica di assicurazioni — soc. coop.", + "country_code": "ITA", + "nuts_code": "ITH31", + "post_code": null, + "post_name": "Verona", + "thoroughfare": null + }, + { + "request_id": "d000073", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ginger CEBTP", + "country_code": "FRA", + "nuts_code": "FRE12", + "post_code": "62400", + "post_name": "Béthune", + "thoroughfare": "technoparc Futura" + }, + { + "request_id": "d000074", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bundesministerium für Kunst, Kultur, öffentlichen Dienst und Sport", + "country_code": "AUT", + "nuts_code": "AT13", + "post_code": "1030", + "post_name": "Wien", + "thoroughfare": "Radetzkystraße 2" + }, + { + "request_id": "d000075", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dirmed", + "country_code": "FRA", + "nuts_code": "FRL04", + "post_code": "13331", + "post_name": "Marseille Cedex 03", + "thoroughfare": "16 rue Antoine Zattara — CS 70248" + }, + { + "request_id": "d000076", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "imp GmbH", + "country_code": "DEU", + "nuts_code": "DEA5", + "post_code": "59823", + "post_name": "Arnsberg", + "thoroughfare": "im Neyl 18" + }, + { + "request_id": "d000077", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Leipzig, Amt für Jugend, Familie und Bildung", + "country_code": "DEU", + "nuts_code": "DED51", + "post_code": "04159", + "post_name": "Leipzig", + "thoroughfare": "Georg-Schumann-Straße 357" + }, + { + "request_id": "d000078", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Europharma Ltd", + "country_code": "MLT", + "nuts_code": "MT", + "post_code": "BKR-9076", + "post_name": "Birkirkara [Birkirkara]", + "thoroughfare": "Catalunya Buildings Psaila Street" + }, + { + "request_id": "d000079", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Excelentísimo Ayuntamiento de Ciudad Real", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "13001", + "post_name": "Ciudad Real", + "thoroughfare": "Plaza Mayor, 1" + }, + { + "request_id": "d000080", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nifor Limited", + "country_code": "ARE", + "nuts_code": null, + "post_code": "11111", + "post_name": "Abu Dhabi", + "thoroughfare": "Incubator Building Ground Floor Masdar City" + }, + { + "request_id": "d000081", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Przedsiębiorstwo Usług Komunalnych Eko Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL62", + "post_code": "14-200", + "post_name": "Iława", + "thoroughfare": null + }, + { + "request_id": "d000082", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FastWeb SpA", + "country_code": "ITA", + "nuts_code": "ITC4C", + "post_code": null, + "post_name": "Milano (MI)", + "thoroughfare": null + }, + { + "request_id": "d000083", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ArGe Bio", + "country_code": "DEU", + "nuts_code": "DE239", + "post_code": null, + "post_name": "Neunburg", + "thoroughfare": null + }, + { + "request_id": "d000084", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medias International, trgovanje in trženje z medicinskim materialom d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Leskoškova cesta 9D" + }, + { + "request_id": "d000085", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SGAMI Sud-Ouest", + "country_code": "FRA", + "nuts_code": "FRI", + "post_code": "33041", + "post_name": "Bordeaux", + "thoroughfare": "89 cours Dupré de Saint-Maur" + }, + { + "request_id": "d000086", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Löwen Medien Service GmbH", + "country_code": "DEU", + "nuts_code": "DE911", + "post_code": "38104", + "post_name": "Braunschweig", + "thoroughfare": null + }, + { + "request_id": "d000087", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CRS Laboratories Oy", + "country_code": "FIN", + "nuts_code": "FI1D9", + "post_code": null, + "post_name": "Kempele", + "thoroughfare": null + }, + { + "request_id": "d000088", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Antea Group", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": null, + "post_name": "Rillieux-la-Pape", + "thoroughfare": null + }, + { + "request_id": "d000089", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CEZ Vânzare S.A.", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "200769", + "post_name": "Craiova", + "thoroughfare": "Str. Severinului nr. 97" + }, + { + "request_id": "d000090", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mecánicas Bolea, S. A.", + "country_code": "ESP", + "nuts_code": "ES62", + "post_code": "30353", + "post_name": "Cartagena", + "thoroughfare": null + }, + { + "request_id": "d000091", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "O-K-TEH d.o.o.", + "country_code": "HRV", + "nuts_code": "HR050", + "post_code": "10090", + "post_name": "Zagreb", + "thoroughfare": "Vučak 16a" + }, + { + "request_id": "d000092", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Global Mobility Moving AB", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "753 23", + "post_name": "Uppsala", + "thoroughfare": "Danmarksgatan 47" + }, + { + "request_id": "d000093", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Arch.Design, s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ064", + "post_code": "616 00", + "post_name": "Brno", + "thoroughfare": "Sochorova 3178/23, Žabovřesky" + }, + { + "request_id": "d000094", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vertis Environmental Finance", + "country_code": "BEL", + "nuts_code": "BE", + "post_code": "1050", + "post_name": "Brussel", + "thoroughfare": "Louizalaan 475" + }, + { + "request_id": "d000095", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ředitelství silnic a dálnic ČR", + "country_code": "CZE", + "nuts_code": "CZ01", + "post_code": "140 00", + "post_name": "Praha 4", + "thoroughfare": "Na Pankráci 546/56" + }, + { + "request_id": "d000096", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CMC Byggadministration Aktiebolag", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "414 62", + "post_name": "Göteborg", + "thoroughfare": "Djurgårdsgatan 9" + }, + { + "request_id": "d000097", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Salisbury Plain Academies", + "country_code": "GBR", + "nuts_code": "UKK15", + "post_code": "SP4 8HH", + "post_name": "Salisbury", + "thoroughfare": "Avon Valley College, Durrington, Salisbury, SP4 8HH" + }, + { + "request_id": "d000098", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Total Service, a.s.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "170 00", + "post_name": "Praha 7-Holešovice", + "thoroughfare": "U Uranie 954/18" + }, + { + "request_id": "d000099", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pharmamed-Mado, družba za trgovino s profesionalno medicinsko opremo in pripomočki, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Leskoškova cesta 9E" + }, + { + "request_id": "d000100", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Teknologian tutkimuskeskus VTT Oy", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-02044", + "post_name": "VTT", + "thoroughfare": "PL 1000" + }, + { + "request_id": "d000101", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tegral GmbH", + "country_code": "DEU", + "nuts_code": "DEC04", + "post_code": null, + "post_name": "Überherrn", + "thoroughfare": null + }, + { + "request_id": "d000102", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix Telecom S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "020331", + "post_name": "Bucureşti", + "thoroughfare": "Str. Fabrica de Glucoză nr. 11D" + }, + { + "request_id": "d000103", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spesa Ingeniería, S. A.", + "country_code": "ESP", + "nuts_code": "ES243", + "post_code": "50004", + "post_name": "Zaragoza", + "thoroughfare": "Avenida César Augusto, 3, 10.º C" + }, + { + "request_id": "d000104", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "St. Martini Krankenhaus in Duderstadt", + "country_code": "DEU", + "nuts_code": "DE929", + "post_code": "37115", + "post_name": "Duderstadt", + "thoroughfare": "Göttinger Straße 34" + }, + { + "request_id": "d000105", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ramboll Finland Oy", + "country_code": "FIN", + "nuts_code": "FI1B1", + "post_code": null, + "post_name": "Espoo", + "thoroughfare": null + }, + { + "request_id": "d000106", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Przedsiębiorstwo Wodociągów i Kanalizacji Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL633", + "post_code": "81-311 Gdynia", + "post_name": "Gdynia", + "thoroughfare": "Witomińska 29" + }, + { + "request_id": "d000107", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Agencia de Ciberseguretat de Catalunya", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08908", + "post_name": "L'Hospitalet de Llobregat", + "thoroughfare": "C/ Salvador Espriu, 45-51" + }, + { + "request_id": "d000108", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AVERS spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "141 00", + "post_name": "Praha 4–Michle", + "thoroughfare": "Michelská 240/49" + }, + { + "request_id": "d000109", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadibau GmbH - Gesellschaft für den Staatsbediensteten Wohnungsbau in Bayern mbH", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "80804", + "post_name": "München", + "thoroughfare": "Mottlstr. 1" + }, + { + "request_id": "d000110", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "Ștei", + "thoroughfare": "Str. Andrei Mureșanu nr. AN6" + }, + { + "request_id": "d000111", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javni zavod Mladi zmaji - Center za kakovostno preživljanje prostega časa mladih", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Resljeva cesta 18" + }, + { + "request_id": "d000112", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Departamento de Salud de Sagunto — Dirección Económica-Gerencia", + "country_code": "ESP", + "nuts_code": "ES523", + "post_code": "46520", + "post_name": "Sagunto", + "thoroughfare": "Avenida Ramón i Cajal, s/n" + }, + { + "request_id": "d000113", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Synergie", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75016", + "post_name": "Paris", + "thoroughfare": "11 avenue du Colonel-Bonnet" + }, + { + "request_id": "d000114", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landratsamt Esslingen, Amt für Kreisimmobilien und Hochbau, Amt 54", + "country_code": "DEU", + "nuts_code": "DE113", + "post_code": "73728", + "post_name": "Esslingen", + "thoroughfare": "Pulverwiesen 11" + }, + { + "request_id": "d000115", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-50161", + "post_name": "Kaunas", + "thoroughfare": "Eivenių g. 2" + }, + { + "request_id": "d000116", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Rogaland Fylkeskommune", + "country_code": "NOR", + "nuts_code": "NO0A1", + "post_code": "4012", + "post_name": "Stavanger", + "thoroughfare": "Bergelandsgården 30" + }, + { + "request_id": "d000117", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Eesti Töötukassa", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "11412", + "post_name": "Tallinn", + "thoroughfare": "Lasnamäe tn 2" + }, + { + "request_id": "d000118", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Santomed S.R.L.", + "country_code": "ROU", + "nuts_code": "RO424", + "post_code": "300210", + "post_name": "Timișoara", + "thoroughfare": "Str. Liviu Rebreanu nr. 25" + }, + { + "request_id": "d000119", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medway International GmbH", + "country_code": "DEU", + "nuts_code": "DE600", + "post_code": "20095", + "post_name": "Hamburg", + "thoroughfare": "Schopenstehl 15" + }, + { + "request_id": "d000120", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Baxter Polska Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL", + "post_code": "00-380", + "post_name": "Warszawa", + "thoroughfare": "ul. Kruczkowskiego 8" + }, + { + "request_id": "d000121", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mazars SA", + "country_code": "FRA", + "nuts_code": "FR105", + "post_code": "92400", + "post_name": "Courbevoie", + "thoroughfare": "61 rue Henri Regnault" + }, + { + "request_id": "d000122", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Coor Norrland Lokalvård AB", + "country_code": "SWE", + "nuts_code": "SE332", + "post_code": "856 33", + "post_name": "Sundsvall", + "thoroughfare": "Heffners Allé 52" + }, + { + "request_id": "d000123", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bouygues Bâtiment Île-de-France SAS", + "country_code": "FRA", + "nuts_code": "FR10", + "post_code": "78061", + "post_name": "Saint-Quentin-en-Yvelines", + "thoroughfare": "1 avenue Eugène Freyssinet, Guyancourt" + }, + { + "request_id": "d000124", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Conseil departemental des Vosges", + "country_code": "FRA", + "nuts_code": "FRF34", + "post_code": "88088", + "post_name": "Épinal Cedex 9", + "thoroughfare": "8 rue de la Préfecture" + }, + { + "request_id": "d000125", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AED les Ateliers d'Ascalon", + "country_code": "FRA", + "nuts_code": "FRE21", + "post_code": "02350", + "post_name": "Liesse-Notre-Dame", + "thoroughfare": "68 rue de l'Abbé-Duployé" + }, + { + "request_id": "d000126", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Abena-Helpi prodaja medicinskih in drugih pripomočkov d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1236", + "post_name": "Trzin", + "thoroughfare": "Dobrave 7B" + }, + { + "request_id": "d000127", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "WSP Sverige AB", + "country_code": "SWE", + "nuts_code": "SE224", + "post_code": "121 88", + "post_name": "Stockholm-Globen", + "thoroughfare": null + }, + { + "request_id": "d000128", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mairie de Liévin", + "country_code": "FRA", + "nuts_code": "FRE12", + "post_code": "62800", + "post_name": "Liévin", + "thoroughfare": "45 rue E Vaillant" + }, + { + "request_id": "d000129", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "La formidable Armada", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69001", + "post_name": "Lyon", + "thoroughfare": "16 rue René-Leynaud" + }, + { + "request_id": "d000130", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landkreis Göttingen", + "country_code": "DEU", + "nuts_code": "DE91C", + "post_code": "37083", + "post_name": "Göttingen", + "thoroughfare": "Reinhäuser Landstraße 4" + }, + { + "request_id": "d000131", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Agenția Națională de Administrare Fiscală", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "050741", + "post_name": "Bucureşti", + "thoroughfare": "Str. Apolodor nr. 17" + }, + { + "request_id": "d000132", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Z + M Partner, spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ080", + "post_code": "702 00", + "post_name": "Ostrava", + "thoroughfare": "Valchařská 3261/17, Moravská Ostrava" + }, + { + "request_id": "d000133", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Inter Koop družba za trgovino in proizvodnjo d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Zrkovska cesta 97" + }, + { + "request_id": "d000134", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Interserve Facilities Services, S. A. U.", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": null, + "post_name": "Madrid", + "thoroughfare": null + }, + { + "request_id": "d000135", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Framed, trgovina in storitve, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1236", + "post_name": "Trzin", + "thoroughfare": "Borovec 18" + }, + { + "request_id": "d000136", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Glissando", + "country_code": "ROU", + "nuts_code": "RO424", + "post_code": "300167", + "post_name": "Timișoara", + "thoroughfare": "Str. Gării nr. 15" + }, + { + "request_id": "d000137", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Instytut Hematologii i Transfuzjologii", + "country_code": "POL", + "nuts_code": "PL911", + "post_code": "02-776", + "post_name": "Warszawa", + "thoroughfare": "ul. Indiry Gandhi 14" + }, + { + "request_id": "d000138", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Espoon kaupunki", + "country_code": "FIN", + "nuts_code": "FI1B1", + "post_code": null, + "post_name": "Espoo", + "thoroughfare": null + }, + { + "request_id": "d000139", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Schäfer Trennwandsysteme GmbH", + "country_code": "DEU", + "nuts_code": "DEB1B", + "post_code": "56593", + "post_name": "Horhausen", + "thoroughfare": "Industriepark 37" + }, + { + "request_id": "d000140", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Silnice LK a.s.", + "country_code": "CZE", + "nuts_code": "CZ051", + "post_code": "466 05", + "post_name": "Jablonec nad Nisou", + "thoroughfare": "Československé armády 4805/24" + }, + { + "request_id": "d000141", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Takeda Pharmaceuticals Czech Republic s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ01", + "post_code": "120 00", + "post_name": "Praha 2", + "thoroughfare": "Škrétova 490/12" + }, + { + "request_id": "d000142", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mathem i Sverige AB", + "country_code": "SWE", + "nuts_code": "SE2", + "post_code": "114 59", + "post_name": "Stockholm", + "thoroughfare": "Östermalmsgatan 87D" + }, + { + "request_id": "d000143", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vereniging van Vlaamse Huisvestingsmaatschappijen", + "country_code": "BEL", + "nuts_code": "BE211", + "post_code": "2020", + "post_name": "Antwerpen", + "thoroughfare": "Evert Larockstraat 6" + }, + { + "request_id": "d000144", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Municipiul Reșița", + "country_code": "ROU", + "nuts_code": "RO422", + "post_code": "320084", + "post_name": "Reșița", + "thoroughfare": "Str. 1 Decembrie 1918 nr. 1A" + }, + { + "request_id": "d000145", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Thinkproject Conclude GmbH", + "country_code": "DEU", + "nuts_code": "DEA1A", + "post_code": null, + "post_name": "Wuppertal", + "thoroughfare": null + }, + { + "request_id": "d000146", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Malermester Tommy Mørk AS", + "country_code": "NOR", + "nuts_code": "NO092", + "post_code": "4626", + "post_name": "Kristiansand S", + "thoroughfare": "Kartheia 5" + }, + { + "request_id": "d000147", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Joensuun Yrityskiinteistöt Oy", + "country_code": "FIN", + "nuts_code": "FI1D3", + "post_code": null, + "post_name": "Joensuu", + "thoroughfare": null + }, + { + "request_id": "d000148", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vilex '94. Ipari-, Szolgáltató- és Kereskedelmi Kft.", + "country_code": "HUN", + "nuts_code": "HU", + "post_code": "4100", + "post_name": "Berettyóújfalu", + "thoroughfare": "Széchenyi utca 74." + }, + { + "request_id": "d000149", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Arpiem Aviation", + "country_code": "ROU", + "nuts_code": "RO322", + "post_code": "075100", + "post_name": "Otopeni", + "thoroughfare": "Calea Bucureștilor nr. 224E" + }, + { + "request_id": "d000150", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Občina Šoštanj", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "3325", + "post_name": "Šoštanj", + "thoroughfare": "Trg svobode 12" + }, + { + "request_id": "d000151", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ute mark & miljö i Örebro AB", + "country_code": "SWE", + "nuts_code": "SE", + "post_code": "702 27", + "post_name": "Örebro", + "thoroughfare": "Nastagatan 22" + }, + { + "request_id": "d000152", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Správa silnic Moravskoslezského kraje, příspěvková organizace", + "country_code": "CZE", + "nuts_code": "CZ080", + "post_code": "702 23", + "post_name": "Ostrava", + "thoroughfare": "Úprkova 795/1" + }, + { + "request_id": "d000153", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Teampro Strategy Consulting", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "024054", + "post_name": "București", + "thoroughfare": "Str. Dimitrie Onciu nr. 18, sector 2" + }, + { + "request_id": "d000154", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "R4 Korjausurakointi Tampere Oy", + "country_code": "FIN", + "nuts_code": "FI197", + "post_code": "FI-33800", + "post_name": "Tampere", + "thoroughfare": "Viinikankatu 49" + }, + { + "request_id": "d000155", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lamor Corporation Oy", + "country_code": "FIN", + "nuts_code": "FI1B1", + "post_code": null, + "post_name": "Porvoo", + "thoroughfare": null + }, + { + "request_id": "d000156", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Minnucci Associati srl", + "country_code": "ITA", + "nuts_code": "ITI43", + "post_code": "00061", + "post_name": "Anguillara Sabazia", + "thoroughfare": "via Comunale di San Francesco 768" + }, + { + "request_id": "d000157", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Distribuție Energie Oltenia S.A.", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "200769", + "post_name": "Craiova", + "thoroughfare": "Calea Severinului nr. 97, parter, et. 2, 3, 4" + }, + { + "request_id": "d000158", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Matka-Kyllönen Oy", + "country_code": "FIN", + "nuts_code": "FI1D8", + "post_code": "FI-88900", + "post_name": "Kuhmo", + "thoroughfare": "Kainuuntie 84" + }, + { + "request_id": "d000159", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Farid industrie SpA", + "country_code": "ITA", + "nuts_code": "ITC11", + "post_code": null, + "post_name": "Vinovo", + "thoroughfare": null + }, + { + "request_id": "d000160", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Terra-Log Mélyépítő Kft.", + "country_code": "HUN", + "nuts_code": "HU110", + "post_code": "1124", + "post_name": "Budapest", + "thoroughfare": "Bürök utca 34–36." + }, + { + "request_id": "d000161", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Delo Časopisno založniško podjetje d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Dunajska cesta 5" + }, + { + "request_id": "d000162", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Københavns Kommune", + "country_code": "DNK", + "nuts_code": "DK011", + "post_code": "2200", + "post_name": "København", + "thoroughfare": "Sjællandsgade 40" + }, + { + "request_id": "d000163", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "L3P Architekten ETH FH SIA, AG", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "8158", + "post_name": "Regensberg", + "thoroughfare": "Unterburg, 33" + }, + { + "request_id": "d000164", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Atlantic Vert", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "44412", + "post_name": "Rezé", + "thoroughfare": null + }, + { + "request_id": "d000165", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Société Alpbus Fournier", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "74800", + "post_name": "Saint-Pierre-en-Faucigny", + "thoroughfare": "32 rue des Vanneaux — ZAE des Jourdies" + }, + { + "request_id": "d000166", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Unipolsai assicurazioni SpA", + "country_code": "ITA", + "nuts_code": "ITH55", + "post_code": null, + "post_name": "Bologna", + "thoroughfare": null + }, + { + "request_id": "d000167", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Elektro Redeker e. K.", + "country_code": "DEU", + "nuts_code": "DEA36", + "post_code": null, + "post_name": "Recklinghausen", + "thoroughfare": null + }, + { + "request_id": "d000168", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Electro Standard S.R.L.", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600332", + "post_name": "Bacău", + "thoroughfare": "Str. Mărăști nr. 18" + }, + { + "request_id": "d000169", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Maxto ITS Sp. z o.o., Sp. k.", + "country_code": "POL", + "nuts_code": "PL", + "post_code": "32-085", + "post_name": "Modlniczka", + "thoroughfare": "ul. Willowa 87" + }, + { + "request_id": "d000170", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Malerei Hosp KG", + "country_code": "AUT", + "nuts_code": "AT332", + "post_code": "6020", + "post_name": "Innsbruck", + "thoroughfare": "Ampferer Straße 60" + }, + { + "request_id": "d000171", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "BWI GmbH", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "80637", + "post_name": "München", + "thoroughfare": "Dachauer Str 128" + }, + { + "request_id": "d000172", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kreisverwaltung Mayen-Koblenz", + "country_code": "DEU", + "nuts_code": "DEB17", + "post_code": "56068", + "post_name": "Koblenz", + "thoroughfare": "Bahnhofstr. 9" + }, + { + "request_id": "d000173", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Les résidences de l'Orléanais — OPH d'Orléans Métropole", + "country_code": "FRA", + "nuts_code": "FRB06", + "post_code": "45081", + "post_name": "Orléans", + "thoroughfare": "16 avenue de la Mouillère" + }, + { + "request_id": "d000174", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ever Pharma GmbH", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": null, + "post_name": "Gröbenzell", + "thoroughfare": null + }, + { + "request_id": "d000175", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lernen fördern e. V.", + "country_code": "DEU", + "nuts_code": "DEA37", + "post_code": "49477", + "post_name": "Ibbenbüren", + "thoroughfare": null + }, + { + "request_id": "d000176", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vrtec Hansa Christiana Andersena", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Rašiška ulica 7" + }, + { + "request_id": "d000177", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Clinic Municipal „Dr. Gavril Curteanu”", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": "410469", + "post_name": "Oradea", + "thoroughfare": "Str. Corneliu Coposu nr. 12" + }, + { + "request_id": "d000178", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Karanta Medical trgovska družba d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Poljanski nasip 6" + }, + { + "request_id": "d000179", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centro Hospitalar Universitário de Lisboa Norte, E. P. E.", + "country_code": "PRT", + "nuts_code": "PT170", + "post_code": "1649-035", + "post_name": "Lisboa", + "thoroughfare": "Lisboa" + }, + { + "request_id": "d000180", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Rádio e Televisão de Portugal, S. A.", + "country_code": "PRT", + "nuts_code": "PT170", + "post_code": "1849-030", + "post_name": "Lisboa", + "thoroughfare": "Avenida Marechal Gomes da Costa, 37" + }, + { + "request_id": "d000181", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "VERSAMED Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL841", + "post_code": "15-703", + "post_name": "Białystok", + "thoroughfare": null + }, + { + "request_id": "d000182", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Wil, Departement Bau, Umwelt und Verkehr Stadtplanung", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "9552", + "post_name": "Bronschhofen", + "thoroughfare": "Hauptstraße 20" + }, + { + "request_id": "d000183", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB „Lietuvos geležinkeliai“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000184", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Weatherford Atlas GIP S.A.", + "country_code": "ROU", + "nuts_code": "RO316", + "post_code": "100189", + "post_name": "Ploiești", + "thoroughfare": "Str. Clopoței nr. 2A" + }, + { + "request_id": "d000185", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Byggmester Oddleif Henriksen AS", + "country_code": "NOR", + "nuts_code": "NO092", + "post_code": "4656", + "post_name": "Hamresanden", + "thoroughfare": "Krittveien 44" + }, + { + "request_id": "d000186", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Microsound Kereskedelmi és Szolgáltató Kft.", + "country_code": "HUN", + "nuts_code": "HU110", + "post_code": "1037", + "post_name": "Budapest", + "thoroughfare": "Kunigunda útja 39." + }, + { + "request_id": "d000187", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SARL cabinet Bec", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": null, + "post_name": "Mareuil-les-Meaux", + "thoroughfare": null + }, + { + "request_id": "d000188", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "TREBOR DRUM CONSTRUCT SRL", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": "410265", + "post_name": "Oradea", + "thoroughfare": "Strada Erofte Grigore, Nr. 1B" + }, + { + "request_id": "d000189", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Argenta Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL418", + "post_code": "60-401", + "post_name": "Poznań", + "thoroughfare": "Polska 114" + }, + { + "request_id": "d000190", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Juuan kunta", + "country_code": "FIN", + "nuts_code": "FI1D3", + "post_code": null, + "post_name": "Juuka", + "thoroughfare": null + }, + { + "request_id": "d000191", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Uithoorn", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "1423 AJ", + "post_name": "Uithoorn", + "thoroughfare": "Laan van Meerwijk 16" + }, + { + "request_id": "d000192", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Iturri Portugal Indústria e Segurança, S. A.", + "country_code": "PRT", + "nuts_code": "PT170", + "post_code": null, + "post_name": "Palmela", + "thoroughfare": null + }, + { + "request_id": "d000193", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Crayon Deutschland GmbH", + "country_code": "DEU", + "nuts_code": "DE21H", + "post_code": "82008", + "post_name": "Unterhaching", + "thoroughfare": "Inselkammerstraße 12" + }, + { + "request_id": "d000194", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ornithologische Gesellschaft Baden-Württemberg e. V.", + "country_code": "DEU", + "nuts_code": "DE14", + "post_code": "72072", + "post_name": "Tübingen", + "thoroughfare": null + }, + { + "request_id": "d000195", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Servelect S.R.L.", + "country_code": "ROU", + "nuts_code": "RO113", + "post_code": "400573", + "post_name": "Cluj-Napoca", + "thoroughfare": "Str. Teleorman nr. 23, sector: -, județ Cluj, localitate: Cluj-Napoca, cod poștal: 400573" + }, + { + "request_id": "d000196", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FBSerwis Dolny Śląsk Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL515", + "post_code": "57-410", + "post_name": "Ścinawka Średnia", + "thoroughfare": "Ścinawka Dolna 86" + }, + { + "request_id": "d000197", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hrvatski zavod za transfuzijsku medicinu", + "country_code": "HRV", + "nuts_code": "HR", + "post_code": "10000", + "post_name": "Zagreb", + "thoroughfare": "Petrova 3" + }, + { + "request_id": "d000198", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SWECO Structures AB", + "country_code": "SWE", + "nuts_code": "SE224", + "post_code": "100 26", + "post_name": "Stockholm", + "thoroughfare": "Box 34044" + }, + { + "request_id": "d000199", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Järfälla kommun", + "country_code": "SWE", + "nuts_code": "SE110", + "post_code": "177 80", + "post_name": "Järfälla", + "thoroughfare": "i.u" + }, + { + "request_id": "d000200", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Iași", + "thoroughfare": "Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000201", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Krypton Chemists Ltd", + "country_code": "MLT", + "nuts_code": "MT", + "post_code": null, + "post_name": "Naxxar [In-Naxxar]", + "thoroughfare": "Cantrija Complex, Triq It-Targa, Maghtab," + }, + { + "request_id": "d000202", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pluridet Comexim S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "052082", + "post_name": "București", + "thoroughfare": "Str. Dr. Alexandru Locusteanu nr. 2" + }, + { + "request_id": "d000203", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "APRR Direction Infrastructure Patrimoine Environnement", + "country_code": "FRA", + "nuts_code": "FRC11", + "post_code": "21850", + "post_name": "Saint-Apollinaire", + "thoroughfare": "36 rue du Docteur Schmitt" + }, + { + "request_id": "d000204", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "PAI INVEST nv", + "country_code": "BEL", + "nuts_code": "BE211", + "post_code": "2030", + "post_name": "Antwerpen", + "thoroughfare": "Zaha HAdidplein 1" + }, + { + "request_id": "d000205", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ethias nv", + "country_code": "BEL", + "nuts_code": "BE224", + "post_code": "3500", + "post_name": "Hasselt", + "thoroughfare": "Prins-Bisschopssingel 73" + }, + { + "request_id": "d000206", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Salto Ingénierie", + "country_code": "FRA", + "nuts_code": "FRK14", + "post_code": "63510", + "post_name": "Aulnat", + "thoroughfare": "13 bis rue du Commandant Fayolle" + }, + { + "request_id": "d000207", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Osnovna šola Fram", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2313", + "post_name": "Fram", + "thoroughfare": "Turnerjeva ulica 120" + }, + { + "request_id": "d000208", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Incom SpA", + "country_code": "ITA", + "nuts_code": "ITI13", + "post_code": "51018", + "post_name": "Pieve a Nievole", + "thoroughfare": "via Roma 47" + }, + { + "request_id": "d000209", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IKK classic", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "01099", + "post_name": "Dresden", + "thoroughfare": "Tannenstraße 4 b" + }, + { + "request_id": "d000210", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ajuntament de Barcelona — Distrito de Sant Andreu", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08030", + "post_name": "Barcelona", + "thoroughfare": "Plaza Orfila, 1" + }, + { + "request_id": "d000211", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Ignitis“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": null, + "post_name": "Vilnius", + "thoroughfare": null + }, + { + "request_id": "d000212", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nemocnice Pardubického kraje, a.s.", + "country_code": "CZE", + "nuts_code": "CZ053", + "post_code": "532 03", + "post_name": "Pardubice", + "thoroughfare": "Kyjevská 44" + }, + { + "request_id": "d000213", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Varsinais-Suomen sairaanhoitopiirin kuntayhtymä", + "country_code": "FIN", + "nuts_code": "FI1C1", + "post_code": "FI-20520", + "post_name": "Turku", + "thoroughfare": "Kiinamyllynkatu 4-8" + }, + { + "request_id": "d000214", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Substrate HD nom commercial Volta Medical", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "13006", + "post_name": "Marseille", + "thoroughfare": "65 avenue Jules Cantini" + }, + { + "request_id": "d000215", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universität Stuttgart", + "country_code": "DEU", + "nuts_code": "DE111", + "post_code": "70174", + "post_name": "Stuttgart", + "thoroughfare": "Keplerstr. 7" + }, + { + "request_id": "d000216", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Județean de Urgență Zalău", + "country_code": "ROU", + "nuts_code": "RO116", + "post_code": "450129", + "post_name": "Zalău", + "thoroughfare": "Str. Simion Bărnuţiu nr. 67" + }, + { + "request_id": "d000217", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "WISAG Gebäudereinigung Süd-West GmbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DEC01", + "post_code": "66121", + "post_name": "Saarbrücken", + "thoroughfare": "Am Halberg 10" + }, + { + "request_id": "d000218", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Direcția Generală de Asistență Socială și Protecția Copilului Brașov", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500091", + "post_name": "Brașov", + "thoroughfare": "Str. Iuliu Maniu nr. 6" + }, + { + "request_id": "d000219", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Județean de Urgență Vâlcea", + "country_code": "ROU", + "nuts_code": "RO415", + "post_code": "240011", + "post_name": "Râmnicu Vâlcea", + "thoroughfare": "Calea lui Traian nr. 201" + }, + { + "request_id": "d000220", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sarl ABC Architecture — mandataire", + "country_code": "FRA", + "nuts_code": "FRJ23", + "post_code": "31200", + "post_name": "Toulouse", + "thoroughfare": "46-48 rue André Vasseur" + }, + { + "request_id": "d000221", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Groupama Antilles Guyane", + "country_code": "FRA", + "nuts_code": "FRY20", + "post_code": "97200", + "post_name": "Fort-de-France", + "thoroughfare": "pôle technologie de Kerlys — route de Saint-Christophe — bâtiment E — BP 559" + }, + { + "request_id": "d000222", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medical intertrade d.o.o.", + "country_code": "HRV", + "nuts_code": "HR065", + "post_code": "10431", + "post_name": "Sveta Nedelja", + "thoroughfare": "Dr.Franje Tuđmana 3" + }, + { + "request_id": "d000223", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "documentus Deutschland GmbH", + "country_code": "DEU", + "nuts_code": "DE600", + "post_code": null, + "post_name": "Hamburg", + "thoroughfare": null + }, + { + "request_id": "d000224", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CIDIU SpA", + "country_code": "ITA", + "nuts_code": "ITC11", + "post_code": "10093", + "post_name": "Collegno (TO)", + "thoroughfare": "via Torino 9" + }, + { + "request_id": "d000225", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Agence Cantarane", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "94200", + "post_name": "Ivry-sur-Seine", + "thoroughfare": "41 rue Barbès" + }, + { + "request_id": "d000226", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landratsamt Rhein-Neckar-Kreis", + "country_code": "DEU", + "nuts_code": "DE128", + "post_code": "69115", + "post_name": "Heidelberg", + "thoroughfare": "Kurfürsten-Anlage 38-40" + }, + { + "request_id": "d000227", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Excellent CD, spol. s r.o.", + "country_code": "SVK", + "nuts_code": "SK03", + "post_code": "960 01", + "post_name": "Zvolen", + "thoroughfare": "Š. Moyzesa 3" + }, + { + "request_id": "d000228", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Linköping Science Park AB", + "country_code": "SWE", + "nuts_code": "SE123", + "post_code": null, + "post_name": "Linköping", + "thoroughfare": null + }, + { + "request_id": "d000229", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Västra Götalandsregionen", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "462 80", + "post_name": "Vänersborg", + "thoroughfare": "Östergatan 1" + }, + { + "request_id": "d000230", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Arpiem Aviation", + "country_code": "ROU", + "nuts_code": "RO322", + "post_code": "075100", + "post_name": "Otopeni", + "thoroughfare": "Calea Bucureștilor nr. 224E" + }, + { + "request_id": "d000231", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hemsö Fastighets AB", + "country_code": "SWE", + "nuts_code": "SE121", + "post_code": "104 51", + "post_name": "Stockholm", + "thoroughfare": "Box 24281" + }, + { + "request_id": "d000232", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tratec Teknikken A/S", + "country_code": "NOR", + "nuts_code": "NO092", + "post_code": "4550", + "post_name": "Farsund", + "thoroughfare": "Lundevågveien 3 c" + }, + { + "request_id": "d000233", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Univerza v Mariboru", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Slomškov trg 15" + }, + { + "request_id": "d000234", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Siemens SAS", + "country_code": "FRA", + "nuts_code": "FRF33", + "post_code": "57084", + "post_name": "Metz", + "thoroughfare": "6 rue Marie de Coëtlosquet" + }, + { + "request_id": "d000235", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Baza de Aprovizionare, Gospodărire și Reparații", + "country_code": "ROU", + "nuts_code": "RO32", + "post_code": "077120", + "post_name": "Jilava", + "thoroughfare": "Str. Sabarului nr. 1" + }, + { + "request_id": "d000236", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universitatea de Științe Agricole și Medicină Veterinară a Banatului „Regele Mihai I al României” Timișoara", + "country_code": "ROU", + "nuts_code": "RO424", + "post_code": "300645", + "post_name": "Timișoara", + "thoroughfare": "Calea Aradului nr. 119" + }, + { + "request_id": "d000237", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Saarland, vertreten durch das Ministerium der Justiz, dieses vertreten durch den Präsidenten des Amtsgerichts Saarbrücken", + "country_code": "DEU", + "nuts_code": "DEC01", + "post_code": "66119", + "post_name": "Saarbrücken", + "thoroughfare": "Franz-Josef-Röder-Straße 13" + }, + { + "request_id": "d000238", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SN Perfect", + "country_code": "FRA", + "nuts_code": "FR106", + "post_code": "77290", + "post_name": "Mitry-Mory", + "thoroughfare": "11 rue Henri Becquerel" + }, + { + "request_id": "d000239", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Compagnons Saint-Jacques", + "country_code": "FRA", + "nuts_code": "FRI12", + "post_code": "33370", + "post_name": "Tresses", + "thoroughfare": null + }, + { + "request_id": "d000240", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Länsstyrelsen i Kronobergs län", + "country_code": "SWE", + "nuts_code": "SE212", + "post_code": "351 86", + "post_name": "Växjö", + "thoroughfare": null + }, + { + "request_id": "d000241", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Peragro Přísečná, s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ031", + "post_code": "381 01", + "post_name": "Český Krumlov", + "thoroughfare": "Přísečná 85" + }, + { + "request_id": "d000242", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Merianto Install Oy", + "country_code": "FIN", + "nuts_code": "FI1B1", + "post_code": null, + "post_name": "Helsinki", + "thoroughfare": null + }, + { + "request_id": "d000243", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Presidencia de la Diputación Provincial de Cuenca", + "country_code": "ESP", + "nuts_code": "ES423", + "post_code": "16001", + "post_name": "Cuenca", + "thoroughfare": "C/ Aguirre, 1" + }, + { + "request_id": "d000244", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SAS BSMG-les techniciens des fluides", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "94100", + "post_name": "St-Maur-des-Fossés", + "thoroughfare": "95 avenue Foch" + }, + { + "request_id": "d000245", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "aib Bauplanung Nord GmbH", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "18055", + "post_name": "Rostock", + "thoroughfare": "Rosa-Luxemburg-Straße 14" + }, + { + "request_id": "d000246", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Usługi Leśne Adrian Nidecki", + "country_code": "POL", + "nuts_code": "PL84", + "post_code": "16-100", + "post_name": "Sokółka", + "thoroughfare": "Kuryły 5" + }, + { + "request_id": "d000247", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "APEC-Antwerp/Flanders Port Training center", + "country_code": "BEL", + "nuts_code": "BE21", + "post_code": "2030", + "post_name": "Antwerpen", + "thoroughfare": "Zaha Hadidplein 1" + }, + { + "request_id": "d000248", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landeshauptstadt Dresden, GB Stadtentwicklung, Bau, Verkehr und Liegenschaften, Amt f. Hochbau u. Immobilienverwaltung", + "country_code": "DEU", + "nuts_code": "DED21", + "post_code": "01001", + "post_name": "Dresden", + "thoroughfare": "Postfach 120020" + }, + { + "request_id": "d000249", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sessile", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "77140", + "post_name": "Nemours", + "thoroughfare": "ZAC des Hauteurs du Loing, 27 chemin des Mazes" + }, + { + "request_id": "d000250", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Evolco LT“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-50384", + "post_name": "Kaunas", + "thoroughfare": "V. Krėvės pr. 94-201" + }, + { + "request_id": "d000251", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IMMA", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75015", + "post_name": "Paris", + "thoroughfare": "17 avenue Félix Faure" + }, + { + "request_id": "d000252", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landeshauptstadt Düsseldorf, Der Oberbürgermeister, Stadtentwässerungsbetrieb", + "country_code": "DEU", + "nuts_code": "DEA11", + "post_code": "40225", + "post_name": "Düsseldorf", + "thoroughfare": "Auf'm Hennekamp 47" + }, + { + "request_id": "d000253", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SNRB SAS", + "country_code": "FRA", + "nuts_code": "FR108", + "post_code": "95120", + "post_name": "Ermont", + "thoroughfare": "23 rue du Plessis" + }, + { + "request_id": "d000254", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AXA assicurazioni SpA", + "country_code": "ITA", + "nuts_code": "ITC4C", + "post_code": null, + "post_name": "Milano", + "thoroughfare": null + }, + { + "request_id": "d000255", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pohjois-Pohjanmaan elinkeino-, liikenne- ja ympäristökeskus", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": null, + "post_name": "Oulu", + "thoroughfare": null + }, + { + "request_id": "d000256", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Thermo Fisher Diagnostics AB", + "country_code": "SWE", + "nuts_code": "SE121", + "post_code": "751 37", + "post_name": "Uppsala", + "thoroughfare": "c/o Phadia AB, Box 6460" + }, + { + "request_id": "d000257", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mediclim S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "030671", + "post_name": "București", + "thoroughfare": "Str. Matei Basarab nr. 47" + }, + { + "request_id": "d000258", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Piramal Critical Care Deutschland GmbH", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": null, + "post_name": "München", + "thoroughfare": null + }, + { + "request_id": "d000259", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Val de Garonne agglomération", + "country_code": "FRA", + "nuts_code": "FRI14", + "post_code": "47213", + "post_name": "Marmande Cedex", + "thoroughfare": "place du Marché — CS 70305" + }, + { + "request_id": "d000260", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Zuidplas", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Nieuwerkerk aan den IJssel", + "thoroughfare": null + }, + { + "request_id": "d000261", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Oktal Pharma d.o.o.", + "country_code": "HRV", + "nuts_code": "HR050", + "post_code": "10020", + "post_name": "Zagreb", + "thoroughfare": "Utinjska 40" + }, + { + "request_id": "d000262", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Turun kaupunki / Hyvinvointitoimiala", + "country_code": "FIN", + "nuts_code": "FI1C1", + "post_code": "FI-20101", + "post_name": "Turku", + "thoroughfare": "PL 630 (käyntiosoite: Linnankatu 31, 2. krs)" + }, + { + "request_id": "d000263", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medline international France", + "country_code": "FRA", + "nuts_code": "FR103", + "post_code": "78960", + "post_name": "Voisins-le-Bretonneux", + "thoroughfare": "parc d'Affaires — le Val Saint-Ouen 2 rue René Caudron" + }, + { + "request_id": "d000264", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Suministros Autoferr, S. L.", + "country_code": "ESP", + "nuts_code": "ES43", + "post_code": "10800", + "post_name": "Coria", + "thoroughfare": "C/ García Morato, 22" + }, + { + "request_id": "d000265", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Media Buy Marseille", + "country_code": "FRA", + "nuts_code": "FRL04", + "post_code": "13008", + "post_name": "Marseille", + "thoroughfare": "rue Florac" + }, + { + "request_id": "d000266", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CHU de Montpellier", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "34295", + "post_name": "Montpellier Cedex 5", + "thoroughfare": "191 avenue du Doyen-Gaston-Giraud" + }, + { + "request_id": "d000267", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Schneck Schaal Braun Ingenieurgesellschaft Bauen mbH", + "country_code": "DEU", + "nuts_code": "DE142", + "post_code": "72070", + "post_name": "Tübingen", + "thoroughfare": null + }, + { + "request_id": "d000268", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "H. Isserstedt GmbH", + "country_code": "DEU", + "nuts_code": "DEA53", + "post_code": null, + "post_name": "Hagen", + "thoroughfare": null + }, + { + "request_id": "d000269", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AOK PLUS — Die Gesundheitskasse für Sachsen und Thüringen", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": "99084", + "post_name": "Erfurt", + "thoroughfare": "Augustinerstraße 38" + }, + { + "request_id": "d000270", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ATS-Telcom Praha, a.s.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "106 00", + "post_name": "Praha", + "thoroughfare": "Nad elektrárnou 1526 45" + }, + { + "request_id": "d000271", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Trinidad Wiseman OÜ", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "12618", + "post_name": "Tallinn", + "thoroughfare": "Akadeemia tee 21/4" + }, + { + "request_id": "d000272", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Offenbach am Main", + "country_code": "DEU", + "nuts_code": "DE713", + "post_code": "63065", + "post_name": "Offenbach am Main", + "thoroughfare": "Berliner Str. 100" + }, + { + "request_id": "d000273", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Johnson & Johnson, prodaja medicinskih in farmacevtskih izdelkov, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Šmartinska cesta 53" + }, + { + "request_id": "d000274", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landkreis Kassel — Der Kreisausschuss —", + "country_code": "DEU", + "nuts_code": "DE734", + "post_code": "34024", + "post_name": "Kassel", + "thoroughfare": "Postfach 10 24 20" + }, + { + "request_id": "d000275", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Provincie Zuid-Holland", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "2596 AW", + "post_name": "Den Haag", + "thoroughfare": "Zuid-Hollandplein 1" + }, + { + "request_id": "d000276", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Houten", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3995 DW", + "post_name": "Houten", + "thoroughfare": "Onderdoor 25" + }, + { + "request_id": "d000277", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "TFMS", + "country_code": "FRA", + "nuts_code": "FRL04", + "post_code": "13680", + "post_name": "Lançon", + "thoroughfare": "347 allée des Combes" + }, + { + "request_id": "d000278", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier intercommunal Nord Ardennes", + "country_code": "FRA", + "nuts_code": "FRF21", + "post_code": "08011", + "post_name": "Charleville-Mézières Cedex", + "thoroughfare": "45 avenue de Manchester, BP 10900" + }, + { + "request_id": "d000279", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tartu Ülikool", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "50090", + "post_name": "Tartu linn", + "thoroughfare": "Ülikooli tn 18" + }, + { + "request_id": "d000280", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kraftanlagen Hamburg GmbH", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "22547", + "post_name": "Hamburg", + "thoroughfare": "Fangdieckstraße 68" + }, + { + "request_id": "d000281", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dravske elektrarne Maribor d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Obrežna ulica 170" + }, + { + "request_id": "d000282", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Regierungspräsidium Freiburg — Abteilung Umwelt — Referat 53.3 IRP", + "country_code": "DEU", + "nuts_code": "DE131", + "post_code": "79114", + "post_name": "Freiburg i. Br.", + "thoroughfare": "Bissierstraße 7" + }, + { + "request_id": "d000283", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SACE", + "country_code": "ITA", + "nuts_code": "IT", + "post_code": "00187", + "post_name": "Roma", + "thoroughfare": "piazza Poli 37" + }, + { + "request_id": "d000284", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SIJ, podjetje za proizvodnjo in ekonomske storitve z marketingom, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1230", + "post_name": "Domžale", + "thoroughfare": "Krumperška ulica 11" + }, + { + "request_id": "d000285", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Comune di Caserta", + "country_code": "ITA", + "nuts_code": "ITF31", + "post_code": null, + "post_name": "Caserta", + "thoroughfare": null + }, + { + "request_id": "d000286", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bikeleasing-Service GmbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DE734", + "post_code": "34246", + "post_name": "Vellmar", + "thoroughfare": "Bewdley-Platz 18" + }, + { + "request_id": "d000287", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ELZY, spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": "377 01", + "post_name": "Jindřichův Hradec", + "thoroughfare": "Jarošovská 433" + }, + { + "request_id": "d000288", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fritsch Chiari und Partner ZT GmbH", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "1030", + "post_name": "Wien", + "thoroughfare": "Marxergasse 1B" + }, + { + "request_id": "d000289", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AKTIVA ČIŠČENJE d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1236", + "post_name": "Trzin", + "thoroughfare": "Ljubljanska cesta 12F" + }, + { + "request_id": "d000290", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hans Barmettler & Co. AG", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "5054", + "post_name": "Mooslerau", + "thoroughfare": "Gwärbi 325" + }, + { + "request_id": "d000291", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lidköpings kommun", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "531 88", + "post_name": "Lidköping", + "thoroughfare": "Skaragatan 8" + }, + { + "request_id": "d000292", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Eudes Architecture", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "51000", + "post_name": "Châlons-en-Champagne", + "thoroughfare": null + }, + { + "request_id": "d000293", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "A. Zapalskio IĮ „Azas“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-35100", + "post_name": "Panevėžys", + "thoroughfare": "Tiekimo g. 2A" + }, + { + "request_id": "d000294", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universiteit Utrecht", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3584 CS", + "post_name": "Utrecht", + "thoroughfare": "Heidelberglaan 8" + }, + { + "request_id": "d000295", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Elektro Primorska podjetje za distribucijo električne energije, d.d.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "5000", + "post_name": "Nova Gorica", + "thoroughfare": "Erjavčeva ulica 22" + }, + { + "request_id": "d000296", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Communauté d'agglomération du Soissonnais", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "02880", + "post_name": "Cuffies", + "thoroughfare": "11 avenue François Mitterrand, Les Terrasses du Mail" + }, + { + "request_id": "d000297", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landesbetrieb Bau- und Liegenschaftsmanagement Sachsen-Anhalt (BLSA), Zentrale Vergabestelle (ZVS)", + "country_code": "DEU", + "nuts_code": "DEE03", + "post_code": "39014", + "post_name": "Magdeburg", + "thoroughfare": "PF 3964 (Tessenowstraße 1, 39114 Magdeburg)" + }, + { + "request_id": "d000298", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "KDS", + "country_code": "FRA", + "nuts_code": "FRI23", + "post_code": "87220", + "post_name": "Feytiat", + "thoroughfare": "1 allée Mouloudji" + }, + { + "request_id": "d000299", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Agence de services et de paiement", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "87040", + "post_name": "Limoges", + "thoroughfare": "2 rue du Maupas" + }, + { + "request_id": "d000300", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Paris — Vallée de la Marne", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "77207", + "post_name": "Marne-la-Vallée Cedex", + "thoroughfare": "5 cours de l'Arche Guédon à Torcy" + }, + { + "request_id": "d000301", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Chalmers Tekniska Högskola Aktiebolag", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "412 96", + "post_name": "Göteborg", + "thoroughfare": "Arvid Hedvalls backe 4" + }, + { + "request_id": "d000302", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Rhein-Sieg-Kreis", + "country_code": "DEU", + "nuts_code": "DEA2C", + "post_code": "53721", + "post_name": "Siegburg", + "thoroughfare": "Kaiser-Wilhelm-Platz 1" + }, + { + "request_id": "d000303", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Göteborgs Stads Bostads AB", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "402 21", + "post_name": "Göteborg", + "thoroughfare": "Box 5044" + }, + { + "request_id": "d000304", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "O2 Czech Republic, a.s.", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": "140 22", + "post_name": "Praha 4 - Michle", + "thoroughfare": "Za Brumlovkou 266/2" + }, + { + "request_id": "d000305", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nemocnice Na Homolce", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "150 30", + "post_name": "Praha 5", + "thoroughfare": "Roentgenova 37/2" + }, + { + "request_id": "d000306", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "adesso SE", + "country_code": "DEU", + "nuts_code": "DEA52", + "post_code": "44269", + "post_name": "Dortmund", + "thoroughfare": "Adessoplatz 1" + }, + { + "request_id": "d000307", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universitätsklinikum Tübingen", + "country_code": "DEU", + "nuts_code": "DE142", + "post_code": "72076", + "post_name": "Tübingen", + "thoroughfare": "Geissweg 3" + }, + { + "request_id": "d000308", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SMACL assurances", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "79031", + "post_name": "Niort Cedex 9", + "thoroughfare": "141 avenue Salvador Allende" + }, + { + "request_id": "d000309", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Univerzitetni klinični center Maribor", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Ljubljanska ulica 5" + }, + { + "request_id": "d000310", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "France Travaux (mandataire)", + "country_code": "FRA", + "nuts_code": "FR107", + "post_code": "94460", + "post_name": "Valenton", + "thoroughfare": "13 et 13 bis rue du Bois Cerdon" + }, + { + "request_id": "d000311", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ČEPRO, a.s.", + "country_code": "CZE", + "nuts_code": "CZ0", + "post_code": "170 00", + "post_name": "Praha 7", + "thoroughfare": "Dělnická 213/12" + }, + { + "request_id": "d000312", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sor Libchavy spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": "561 16", + "post_name": "Libchavy", + "thoroughfare": "Dolní Libchavy 48" + }, + { + "request_id": "d000313", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeinnützige Salzburger Landeskliniken Betriebsgesellschaft mbH", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "5020", + "post_name": "Salzburg", + "thoroughfare": "Müllner Hauptstr. 48" + }, + { + "request_id": "d000314", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Carpintería de Madera Hermanos Valdivia, S. L.", + "country_code": "ESP", + "nuts_code": "ES704", + "post_code": "35600", + "post_name": "Puerto del Rosario", + "thoroughfare": "C/ Hernán Cortés, 30" + }, + { + "request_id": "d000315", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hochschule Offenburg", + "country_code": "DEU", + "nuts_code": "DE134", + "post_code": "77652", + "post_name": "Offenburg", + "thoroughfare": "Badstr. 24" + }, + { + "request_id": "d000316", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "RSN Gebäudereinigung und Dienste GmbH", + "country_code": "DEU", + "nuts_code": "DEE03", + "post_code": "39128", + "post_name": "Magdeburg", + "thoroughfare": "An der Steinkuhle 1" + }, + { + "request_id": "d000317", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SDEA Alsace Moselle", + "country_code": "FRA", + "nuts_code": "FRF1", + "post_code": "67013", + "post_name": "Strasbourg Cedex", + "thoroughfare": "1 rue de Rome — CS 10020" + }, + { + "request_id": "d000318", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Saarpfalz-Kreis", + "country_code": "DEU", + "nuts_code": "DEC05", + "post_code": "66424", + "post_name": "Homburg", + "thoroughfare": "Am Forum 1" + }, + { + "request_id": "d000319", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "Ștei", + "thoroughfare": "Str. Andrei Mureșanu nr. AN6" + }, + { + "request_id": "d000320", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Wien – Wiener Wohnen", + "country_code": "AUT", + "nuts_code": "AT130", + "post_code": "1030", + "post_name": "Wien", + "thoroughfare": "Rosa-Fischer-Gasse 2" + }, + { + "request_id": "d000321", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Weatherford Atlas GIP S.A.", + "country_code": "ROU", + "nuts_code": "RO", + "post_code": "100189", + "post_name": "Ploiești", + "thoroughfare": "Str. Clopotei nr. 2A" + }, + { + "request_id": "d000322", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Presidencia de la Sociedad de Infraestructuras y Equipamientos Penitenciarios y de la Seguridad del Estado, S. M. E., S. A.", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": "28001", + "post_name": "Madrid", + "thoroughfare": "C/ Claudio Coello, 31, 5.ª planta" + }, + { + "request_id": "d000323", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "OMV Petrom S.A.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "013329", + "post_name": "Bucureşti", + "thoroughfare": "Str. Coralilor nr. 22" + }, + { + "request_id": "d000324", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stichting Meridiaan College katholieke scholengemeenschap voor voortgezet onderwijs", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3813 VD", + "post_name": "Amersfoort", + "thoroughfare": "Hooglandseweg-Noord 55" + }, + { + "request_id": "d000325", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dunántúli Regionális Vízmű Zártkörűen Működő Részvénytársaság", + "country_code": "HUN", + "nuts_code": "HU232", + "post_code": "8600", + "post_name": "Siófok", + "thoroughfare": "Tanácsház utca 7." + }, + { + "request_id": "d000326", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ATAUB", + "country_code": "FRA", + "nuts_code": "FRD22", + "post_code": "76230", + "post_name": "Bois Guillaume", + "thoroughfare": "606 chemin de la Bretèque — BP 6" + }, + { + "request_id": "d000327", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeinde Birkenfeld", + "country_code": "DEU", + "nuts_code": "DE12B", + "post_code": "75217", + "post_name": "Birkenfeld", + "thoroughfare": "Marktplatz 6" + }, + { + "request_id": "d000328", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "müller.schurr architekten", + "country_code": "DEU", + "nuts_code": "DE27B", + "post_code": "87616", + "post_name": "Marktoberdorf", + "thoroughfare": "Birkenweg 11" + }, + { + "request_id": "d000329", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sopra Steria", + "country_code": "FRA", + "nuts_code": "FRK28", + "post_code": "74940", + "post_name": "Annecy-le-Vieux", + "thoroughfare": "3 rue du Pré Faucon" + }, + { + "request_id": "d000330", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Luna Glanz GmbH & Co.KG", + "country_code": "DEU", + "nuts_code": "DE21H", + "post_code": null, + "post_name": "München", + "thoroughfare": null + }, + { + "request_id": "d000331", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CS Planungs- und Ingenieurgesellschaft mbH", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "10997", + "post_name": "Berlin", + "thoroughfare": "Köpernicker Straße 145" + }, + { + "request_id": "d000332", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IKK classic", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "01099", + "post_name": "Dresden", + "thoroughfare": "Tannenstraße 4b" + }, + { + "request_id": "d000333", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landeshauptstadt Stuttgart, Haupt- und Personalamt, Abt. Allgemeiner Service, Zentraler Einkauf", + "country_code": "DEU", + "nuts_code": "DE111", + "post_code": "70173", + "post_name": "Stuttgart", + "thoroughfare": "Eberhardstr. 61" + }, + { + "request_id": "d000334", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "S.C. J'Info Tours S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "010458", + "post_name": "București", + "thoroughfare": "Str. Jules Michelet nr. 1" + }, + { + "request_id": "d000335", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FastWeb SpA", + "country_code": "ITA", + "nuts_code": "ITC4C", + "post_code": null, + "post_name": "Milano (MI)", + "thoroughfare": null + }, + { + "request_id": "d000336", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tura-Terv Mérnökiroda Kft.", + "country_code": "HUN", + "nuts_code": "HU", + "post_code": "1145", + "post_name": "Budapest", + "thoroughfare": "Gyarmat utca 30." + }, + { + "request_id": "d000337", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Unipolrental SpA", + "country_code": "ITA", + "nuts_code": "ITH53", + "post_code": "42121", + "post_name": "Reggio Emilia", + "thoroughfare": "via G. B. Vico 10/C" + }, + { + "request_id": "d000338", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Freie Universität Berlin Abteilung II: Finanzen, Einkauf und Stellenwirtschaft Referat II C — Zentraler Einkauf", + "country_code": "DEU", + "nuts_code": "DE30", + "post_code": "14195", + "post_name": "Berlin", + "thoroughfare": "Thielallee 38" + }, + { + "request_id": "d000339", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AMJ Turku Audio Oy", + "country_code": "FIN", + "nuts_code": "FI1C1", + "post_code": null, + "post_name": "Lieto", + "thoroughfare": null + }, + { + "request_id": "d000340", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "COMPAREX AG a SoftwareONE Company", + "country_code": "DEU", + "nuts_code": "DED51", + "post_code": "04329", + "post_name": "Leipzig", + "thoroughfare": "Blochstraße 1" + }, + { + "request_id": "d000341", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Commissariat à l'énergie atomique et aux énergies alternatives", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "91191", + "post_name": "Gif-sur-Yvette Cedex", + "thoroughfare": "CEA Paris-Saclay — Bâtiment 482 — PC n° 70" + }, + { + "request_id": "d000342", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Das Land Hessen vertreten durch die Hessische Zentrale für Datenverarbeitung", + "country_code": "DEU", + "nuts_code": "DE714", + "post_code": "65185", + "post_name": "Wiesbaden", + "thoroughfare": "Mainzer Straße 29" + }, + { + "request_id": "d000343", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "USG People Business Solutions nv", + "country_code": "BEL", + "nuts_code": "BE", + "post_code": "2000", + "post_name": "Antwerpen", + "thoroughfare": "Frankrijklei 101" + }, + { + "request_id": "d000344", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Karlstads Energi Aktiebolag", + "country_code": "SWE", + "nuts_code": "SE", + "post_code": "654 60", + "post_name": "Karlstad", + "thoroughfare": "Hedvägen 20" + }, + { + "request_id": "d000345", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "PreZero Service Centrum Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL712", + "post_code": "99-300", + "post_name": "Kutno", + "thoroughfare": "ul. Łąkoszyńska 127" + }, + { + "request_id": "d000346", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "NIF Nemzeti Infrastruktúra Fejlesztő zártkörűen működő Részvénytársaság", + "country_code": "HUN", + "nuts_code": "HU", + "post_code": "1134", + "post_name": "Budapest", + "thoroughfare": "Váci út 45." + }, + { + "request_id": "d000347", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SAN.KO.M., trgovina, proizvodnja in kooperacija, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Ježica 17" + }, + { + "request_id": "d000348", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bundesagentur für Arbeit Regionales Einkaufszentrum NRW", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "40474", + "post_name": "Düsseldorf", + "thoroughfare": "Josef-Gockeln-Str. 7" + }, + { + "request_id": "d000349", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Arabella-Versandbuchhandlung GmbH", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "80937", + "post_name": "München", + "thoroughfare": null + }, + { + "request_id": "d000350", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "WSP Finland Oy", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-00520", + "post_name": "Helsinki", + "thoroughfare": "Pasilan Asema-aukio 1" + }, + { + "request_id": "d000351", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Kiwa Inspecta“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": null, + "post_name": "Vilnius", + "thoroughfare": null + }, + { + "request_id": "d000352", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Jensen Ingrisch Recke Architekten und Stadtplaner PartGmbB", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": null, + "post_name": "München", + "thoroughfare": null + }, + { + "request_id": "d000353", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DRI upravljanje investicij, Družba za razvoj infrastrukture, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI041", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Kotnikova ulica 40" + }, + { + "request_id": "d000354", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Paderborn", + "country_code": "DEU", + "nuts_code": "DEA47", + "post_code": "33102", + "post_name": "Paderborn", + "thoroughfare": "Am Hoppenhof 33" + }, + { + "request_id": "d000355", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landeshauptstadt Düsseldorf, Der Oberbürgermeister, Rechtsamt", + "country_code": "DEU", + "nuts_code": "DEA11", + "post_code": "40227", + "post_name": "Düsseldorf", + "thoroughfare": "Willi-Becker-Allee 10" + }, + { + "request_id": "d000356", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "EyeQ Instruments AG", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "8606", + "post_name": "Greifensee", + "thoroughfare": "Seilerwis 3" + }, + { + "request_id": "d000357", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vertex Pharmaceutical Ireland Limited", + "country_code": "IRL", + "nuts_code": "IE", + "post_code": "D02 EK84", + "post_name": "Dublin 2", + "thoroughfare": "28-32, Pembroke Street Upper" + }, + { + "request_id": "d000358", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Clinic Județean de Urgență „Sf. Apostol Andrei”", + "country_code": "ROU", + "nuts_code": "RO223", + "post_code": "900591", + "post_name": "Constanța", + "thoroughfare": "Str. Tomis nr. 145" + }, + { + "request_id": "d000359", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "RDW en Politie", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "2711 ER", + "post_name": "Zoetermeer", + "thoroughfare": "Europaweg 205" + }, + { + "request_id": "d000360", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CCAS", + "country_code": "FRA", + "nuts_code": "FRE22", + "post_code": "60803", + "post_name": "Crepy-en-Valois", + "thoroughfare": "hôtel de ville" + }, + { + "request_id": "d000361", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medizin & Service GmbH", + "country_code": "DEU", + "nuts_code": "DED4", + "post_code": null, + "post_name": "Chemnitz", + "thoroughfare": null + }, + { + "request_id": "d000362", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nimar", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "545300", + "post_name": "Reghin", + "thoroughfare": "Str. Gării nr. 78/A" + }, + { + "request_id": "d000363", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mutua de Accidentes de Canarias, Mutua Colaboradora con la Seguridad Social número 272", + "country_code": "ESP", + "nuts_code": "ES70", + "post_code": "38003", + "post_name": "Santa Cruz de Tenerife", + "thoroughfare": "C/ Robayna, 2" + }, + { + "request_id": "d000364", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Synergie 4", + "country_code": "FRA", + "nuts_code": "FR10", + "post_code": "91029", + "post_name": "Évry", + "thoroughfare": "ZAC du Bois Chaland — 10 rue du Bois Chaland — CE 2904 Lisses" + }, + { + "request_id": "d000365", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeindeverband Bezirkskrankenhaus Schwaz", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "6130", + "post_name": "Schwaz", + "thoroughfare": "Swarovskistrasse 1-3" + }, + { + "request_id": "d000366", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kur- und Touristikunternehmen der Stadt Bad Salzungen (kAöR)", + "country_code": "DEU", + "nuts_code": "DEG0P", + "post_code": "36433", + "post_name": "Bad Salzungen", + "thoroughfare": "Am Flößrasen 1" + }, + { + "request_id": "d000367", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "E.ON Észak-dunántúli Áramhálózati Zrt.", + "country_code": "HUN", + "nuts_code": "HU221", + "post_code": "9027", + "post_name": "Győr", + "thoroughfare": "Kandó Kálmán utca 11–13." + }, + { + "request_id": "d000368", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Újpesti Torna Egylet", + "country_code": "HUN", + "nuts_code": "HU110", + "post_code": "1044", + "post_name": "Budapest", + "thoroughfare": "Megyeri út 13." + }, + { + "request_id": "d000369", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sweco Polska sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL415", + "post_code": "60-829", + "post_name": "Poznań", + "thoroughfare": "ul. Franklina Roosevelta 22" + }, + { + "request_id": "d000370", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "York Farm", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "011158", + "post_name": "București", + "thoroughfare": "Str. Scărlătescu nr. 17-19, sector 1" + }, + { + "request_id": "d000371", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dach- und Gartengestaltung Stoewahs GmbH", + "country_code": "DEU", + "nuts_code": "DE218", + "post_code": "85586 Poing", + "post_name": "Westring 41", + "thoroughfare": null + }, + { + "request_id": "d000372", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Abbott Medical Sweden AB", + "country_code": "SWE", + "nuts_code": "SE11", + "post_code": "164 07", + "post_name": "Kista", + "thoroughfare": "Box 7051" + }, + { + "request_id": "d000373", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "HSY Helsingin seudun ympäristöpalvelut -kuntayhtymä", + "country_code": "FIN", + "nuts_code": "FI1B", + "post_code": "FI-00240", + "post_name": "Helsinki", + "thoroughfare": "Ilmalantori 1" + }, + { + "request_id": "d000374", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Junta de Gobierno de la Diputación Provincial de León", + "country_code": "ESP", + "nuts_code": "ES413", + "post_code": "24002", + "post_name": "León", + "thoroughfare": "Plaza de San Marcelo, 6" + }, + { + "request_id": "d000375", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "La communauté d'Agglomération de Châlons-en-Champagne", + "country_code": "FRA", + "nuts_code": "FRF23", + "post_code": "51000", + "post_name": "Châlons-en-Champagne", + "thoroughfare": "hôtel de ville, place Foch" + }, + { + "request_id": "d000376", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Elektro Compagnoni AG", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "8052", + "post_name": "Zürich", + "thoroughfare": "Ettenfeldstraße 18" + }, + { + "request_id": "d000377", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Costacos Com S.R.L.", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500108", + "post_name": "Brașov", + "thoroughfare": "Str. Valea Tei nr. 31A" + }, + { + "request_id": "d000378", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sykehusinnkjøp HF", + "country_code": "NOR", + "nuts_code": "NO", + "post_code": "9811", + "post_name": "Vadsø", + "thoroughfare": "Postboks 40" + }, + { + "request_id": "d000379", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Česká republika – Ministerstvo vnitra", + "country_code": "CZE", + "nuts_code": "CZ0", + "post_code": "170 34", + "post_name": "Praha 7", + "thoroughfare": "Nad Štolou 936/3" + }, + { + "request_id": "d000380", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Eiffage Route Sud-Ouest", + "country_code": "FRA", + "nuts_code": "FRG01", + "post_code": "44156", + "post_name": "Ancénis Cedex", + "thoroughfare": "ZAC de l'Aufresne — BP 30235" + }, + { + "request_id": "d000381", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Th. Geyer GmbH & Co. KG Niederlassung Berlin", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "10553", + "post_name": "Berlin", + "thoroughfare": "Huttenstr. 34-35" + }, + { + "request_id": "d000382", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Rotterdam", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3002 AN", + "post_name": "Rotterdam", + "thoroughfare": "Wilhelminakade 179" + }, + { + "request_id": "d000383", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Slovenské elektrárne, a.s.", + "country_code": "SVK", + "nuts_code": "SK", + "post_code": "821 09", + "post_name": "Bratislava", + "thoroughfare": "Mlynské nivy 47" + }, + { + "request_id": "d000384", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "NHS Lanarkshire", + "country_code": "GBR", + "nuts_code": "UKM8", + "post_code": "G71 8BB", + "post_name": "Bothwell", + "thoroughfare": "Board Headquarters, Kirkfield Cottage, Fallside Road" + }, + { + "request_id": "d000385", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Asclepios S.A.", + "country_code": "POL", + "nuts_code": "PL514", + "post_code": "50-502", + "post_name": "Wrocław", + "thoroughfare": "ul. Hubska 44" + }, + { + "request_id": "d000386", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "eSzydłowski Łukasz Szydłowski", + "country_code": "POL", + "nuts_code": "PL", + "post_code": "49-353", + "post_name": "Brzeg", + "thoroughfare": "Piekarska 1" + }, + { + "request_id": "d000387", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helseapps AS", + "country_code": "NOR", + "nuts_code": "NO074", + "post_code": "9406", + "post_name": "Harstad", + "thoroughfare": null + }, + { + "request_id": "d000388", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Schwender Energie- u. Gebäudetechnik GmbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DE24B", + "post_code": "95349", + "post_name": "Thurnau", + "thoroughfare": "Limmersdorfer Str. 3" + }, + { + "request_id": "d000389", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "NEOTECH", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "030235", + "post_name": "București", + "thoroughfare": "Str. Botev Hristo nr. 10, sector 3" + }, + { + "request_id": "d000390", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeindeverband Bezirkskrankenhaus Schwaz", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "6130", + "post_name": "Schwaz", + "thoroughfare": "Swarovskistrasse 1-3" + }, + { + "request_id": "d000391", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Verovškova ulica 70" + }, + { + "request_id": "d000392", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Municipiul Timișoara", + "country_code": "ROU", + "nuts_code": "RO424", + "post_code": "300030", + "post_name": "Timișoara", + "thoroughfare": "Bulevardul C.D. Loga nr. 1" + }, + { + "request_id": "d000393", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Frasinul", + "country_code": "ROU", + "nuts_code": "RO112", + "post_code": "427131", + "post_name": "Maieru", + "thoroughfare": "Str. Principală nr. 59" + }, + { + "request_id": "d000394", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Consejería de Economía, Hacienda y Administración Digital", + "country_code": "ESP", + "nuts_code": "ES620", + "post_code": null, + "post_name": "Murcia", + "thoroughfare": null + }, + { + "request_id": "d000395", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ALFA farm s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "180 00", + "post_name": "Praha 8", + "thoroughfare": "Vojenova 2481/11, Libeň" + }, + { + "request_id": "d000396", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "pmp Projekt GmbH", + "country_code": "DEU", + "nuts_code": "DE600", + "post_code": "22765", + "post_name": "Hamburg", + "thoroughfare": "Max - Brauer - Allee 79" + }, + { + "request_id": "d000397", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CBK Madeira — Corretores de Seguros, S. A.", + "country_code": "PRT", + "nuts_code": "PT300", + "post_code": "9000-066", + "post_name": "Funchal", + "thoroughfare": "Rua da Sé, 40" + }, + { + "request_id": "d000398", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Euromat", + "country_code": "FRA", + "nuts_code": "FRM", + "post_code": "20250", + "post_name": "Corte", + "thoroughfare": "RT50 — zone Artisanale" + }, + { + "request_id": "d000399", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Cicanord", + "country_code": "FRA", + "nuts_code": "FRE11", + "post_code": "59130", + "post_name": "La Madeleine", + "thoroughfare": "37 avenue des Fleurs" + }, + { + "request_id": "d000400", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "REA Reinhart Engert Albert Beratende Ingenieure GmbH", + "country_code": "DEU", + "nuts_code": "DE263", + "post_code": "97076", + "post_name": "Würzburg", + "thoroughfare": "Urlaubstraße 1" + }, + { + "request_id": "d000401", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "JMF Metallbautechnik GmbH", + "country_code": "DEU", + "nuts_code": "DEG0B", + "post_code": "98631", + "post_name": "Jüchsen", + "thoroughfare": null + }, + { + "request_id": "d000402", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tornion Krunni Oy", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-95401", + "post_name": "Tornio", + "thoroughfare": null + }, + { + "request_id": "d000403", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbrăveni", + "thoroughfare": "Str. Gării nr. 3" + }, + { + "request_id": "d000404", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AOK Baden-Württemberg", + "country_code": "DEU", + "nuts_code": "DE1", + "post_code": "70191", + "post_name": "Stuttgart", + "thoroughfare": "Presselstraße 19" + }, + { + "request_id": "d000405", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Iași", + "thoroughfare": "Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000406", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stad Roeselare", + "country_code": "BEL", + "nuts_code": "BE256", + "post_code": "8800", + "post_name": "Roeselare", + "thoroughfare": "Botermarkt 2" + }, + { + "request_id": "d000407", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ISOTECH A.F.F. GmbH", + "country_code": "DEU", + "nuts_code": "DE132", + "post_code": "79286", + "post_name": "Glottertal", + "thoroughfare": "In den Engematten 8" + }, + { + "request_id": "d000408", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "RWE Generation SE", + "country_code": "DEU", + "nuts_code": "DEA13", + "post_code": "45141", + "post_name": "Essen", + "thoroughfare": "RWE Platz 3" + }, + { + "request_id": "d000409", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ayuntamiento de Langreo", + "country_code": "ESP", + "nuts_code": "ES120", + "post_code": null, + "post_name": "Principado de Asturias", + "thoroughfare": null + }, + { + "request_id": "d000410", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Smart Informatics s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "120 00", + "post_name": "Praha 2", + "thoroughfare": "Karlovo náměstí 285/19" + }, + { + "request_id": "d000411", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wirtschaftsbetrieb Hagen (AöR)", + "country_code": "DEU", + "nuts_code": "DEA53", + "post_code": "58091", + "post_name": "Hagen", + "thoroughfare": "Eilper Str. 132-136" + }, + { + "request_id": "d000412", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Österreichisches Rotes Kreuz, Landesverband Burgenland", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "7000", + "post_name": "Eisenstadt", + "thoroughfare": "Henri Dunant-Straße 4" + }, + { + "request_id": "d000413", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "KS services (Mandataire)", + "country_code": "FRA", + "nuts_code": "FRF11", + "post_code": "67200", + "post_name": "Strasbourg", + "thoroughfare": "KS services 91 route des Romains" + }, + { + "request_id": "d000414", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SAS Plançon Bariat", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "35130", + "post_name": "La Guerche-de-Bretagne", + "thoroughfare": null + }, + { + "request_id": "d000415", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Delegación del Gobierno de la Junta de Andalucía en Granada", + "country_code": "ESP", + "nuts_code": "ES614", + "post_code": "18071", + "post_name": "Granada", + "thoroughfare": "C/ Gran Vía de Colón, 56" + }, + { + "request_id": "d000416", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "GatewayBaltic Ltd", + "country_code": "LVA", + "nuts_code": "LV", + "post_code": "LV-1010", + "post_name": "Riga", + "thoroughfare": "Elizabetes iela 51" + }, + { + "request_id": "d000417", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Técnicas y Sistemas de Conservación, S. A.", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08023", + "post_name": "Barcelona", + "thoroughfare": "C/ Solanes, 2, bxs." + }, + { + "request_id": "d000418", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Kaag en Braassem", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Roelofarendsveen", + "thoroughfare": null + }, + { + "request_id": "d000419", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CTM — Logística, Mudanças e Transportes, Lda.", + "country_code": "PRT", + "nuts_code": "PTZZZ", + "post_code": "6200-027", + "post_name": "Covilhã", + "thoroughfare": "Parque Industrial, lote 5" + }, + { + "request_id": "d000420", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CA Val d'Europe Agglomération", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "77701", + "post_name": "Marne-la-Vallée Cedex 4", + "thoroughfare": "Château de Chessy, BP 40, Chessy" + }, + { + "request_id": "d000421", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Česká republika – Ministerstvo vnitra", + "country_code": "CZE", + "nuts_code": "CZ0", + "post_code": "170 34", + "post_name": "Praha 7", + "thoroughfare": "Nad Štolou 936/3" + }, + { + "request_id": "d000422", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Assium", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "51110", + "post_name": "Isles-sur-Suippe", + "thoroughfare": null + }, + { + "request_id": "d000423", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Animal pensant", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75013", + "post_name": "Paris", + "thoroughfare": "10 quai d'Austerlitz Bateau Playtime" + }, + { + "request_id": "d000424", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tentours turistična agencija, d.o.o., Ljubljanska 85, Domžale", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1230", + "post_name": "Domžale", + "thoroughfare": "Ljubljanska cesta 85" + }, + { + "request_id": "d000425", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DREAL Bretagne", + "country_code": "FRA", + "nuts_code": "FRH", + "post_code": "35065", + "post_name": "Rennes Cedex", + "thoroughfare": "10 rue Maurice Fabre" + }, + { + "request_id": "d000426", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ingenieurbüro Pahl und Jacobsen", + "country_code": "DEU", + "nuts_code": "DEF05", + "post_code": "25746", + "post_name": "Heide", + "thoroughfare": "Schillerstraße 37" + }, + { + "request_id": "d000427", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FM Diffusion", + "country_code": "FRA", + "nuts_code": "FR103", + "post_code": "78400", + "post_name": "Chatou", + "thoroughfare": "24 avenue du Maréchal-Foch" + }, + { + "request_id": "d000428", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Ignitis grupės paslaugų centras“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-09311", + "post_name": "Vilnius", + "thoroughfare": "A. Juozapavičiaus g. 13" + }, + { + "request_id": "d000429", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "geiger&waltner landschaftsarchitekten GmbH", + "country_code": "DEU", + "nuts_code": "DE273", + "post_code": "87435", + "post_name": "Kempten (Allgäu)", + "thoroughfare": "Burghaldegasse 26" + }, + { + "request_id": "d000430", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Département de la Moselle", + "country_code": "FRA", + "nuts_code": "FRF33", + "post_code": "57036", + "post_name": "Metz", + "thoroughfare": "1 rue du Pont Moreau, CS 11096" + }, + { + "request_id": "d000431", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "INNI Group", + "country_code": "BEL", + "nuts_code": "BE", + "post_code": "8501", + "post_name": "Heule", + "thoroughfare": "Industrielaan 5" + }, + { + "request_id": "d000432", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CEA/Grenoble", + "country_code": "FRA", + "nuts_code": "FRK24", + "post_code": "38000", + "post_name": "Grenoble", + "thoroughfare": "17 rue des Martyrs" + }, + { + "request_id": "d000433", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Diputación Foral de Bizkaia — Departamento de Euskera, Cultura y Deporte", + "country_code": "ESP", + "nuts_code": "ES213", + "post_code": null, + "post_name": "Bilbao", + "thoroughfare": "Alameda Rekalde, 30, 48009 Bilbao (Bizkaia), Servicio de Acción Cultural — Sección de Programas Socioeducativos" + }, + { + "request_id": "d000434", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Județean de Urgență Bacău", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bacău", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000435", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Správa státních hmotných rezerv", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "150 00", + "post_name": "Praha", + "thoroughfare": "Šeříková 616/1" + }, + { + "request_id": "d000436", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Costacos Com S.R.L.", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500108", + "post_name": "Brașov", + "thoroughfare": "Str. Valea Tei nr. 31A" + }, + { + "request_id": "d000437", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Elkoplast CZ, s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ072", + "post_code": "760 01", + "post_name": "Zlín", + "thoroughfare": "Štefánikova 2664" + }, + { + "request_id": "d000438", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Terumo Sweden AB", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "426 71", + "post_name": "Västra Frölunda", + "thoroughfare": "Sven Källfelts Gata 18" + }, + { + "request_id": "d000439", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Labochema LT“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03151", + "post_name": "Vilnius", + "thoroughfare": "Vilkpėdės g. 22" + }, + { + "request_id": "d000440", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vehicle Conversion Specialist Ltd", + "country_code": "GBR", + "nuts_code": "UK", + "post_code": "HD2 1UB", + "post_name": "Huddersfield", + "thoroughfare": "Unit1, Ellis Hill, Leeds Road" + }, + { + "request_id": "d000441", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hammaslahden Taksi ja Tilausajo", + "country_code": "FIN", + "nuts_code": "FI1D3", + "post_code": "FI-82200", + "post_name": "Hammaslahti", + "thoroughfare": "Paavontie 8 c 3" + }, + { + "request_id": "d000442", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sia garden srl (mandataria) in RTI con AM 22 srl e Mavili srl (mandanti)", + "country_code": "ITA", + "nuts_code": "ITI43", + "post_code": null, + "post_name": "Roma", + "thoroughfare": null + }, + { + "request_id": "d000443", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sanolabor, podjetje za prodajo medicinskih, laboratorijskih in farmacevtskih proizvodov, d.d.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Leskoškova cesta 4" + }, + { + "request_id": "d000444", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Département de Seine-Maritime", + "country_code": "FRA", + "nuts_code": "FRD22", + "post_code": "76101", + "post_name": "Rouen Cedex", + "thoroughfare": "Hôtel du Département, quai Jean Moulin, CS 56101" + }, + { + "request_id": "d000445", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Commune de Brignoles", + "country_code": "FRA", + "nuts_code": "FRL05", + "post_code": "83170", + "post_name": "Brignoles", + "thoroughfare": "Hôtel de Ville — 9 place Carami" + }, + { + "request_id": "d000446", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Aktsiaselts Nõo Lihatööstus", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "61601", + "post_name": "Nõo vald", + "thoroughfare": "Voika tn 18" + }, + { + "request_id": "d000447", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IFAM Ingenieurbüro Fassade Ausbau München GmbH", + "country_code": "DEU", + "nuts_code": "DE21H", + "post_code": null, + "post_name": "85622 Feldkirchen", + "thoroughfare": null + }, + { + "request_id": "d000448", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CHUBB France", + "country_code": "FRA", + "nuts_code": "FRF31", + "post_code": "54320", + "post_name": "Maxéville", + "thoroughfare": "6 rue Alfred Kastler" + }, + { + "request_id": "d000449", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Steril România", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "041831", + "post_name": "București", + "thoroughfare": "Str. Metalurgiei nr. 3-5, sector 4" + }, + { + "request_id": "d000450", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Azienda napoletana mobilità SpA", + "country_code": "ITA", + "nuts_code": "ITF33", + "post_code": "80125", + "post_name": "Napoli", + "thoroughfare": "via G. Marino 1" + }, + { + "request_id": "d000451", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "MEDIS, farmacevtska družba, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1231", + "post_name": "Ljubljana - Črnuče", + "thoroughfare": "Brnčičeva ulica 1" + }, + { + "request_id": "d000452", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Reichmann Gebäudetechnik GmbH", + "country_code": "DEU", + "nuts_code": "DEG0G", + "post_code": null, + "post_name": "Bad Berka", + "thoroughfare": null + }, + { + "request_id": "d000453", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bundesministerium für Bildung und Forschung", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "11055", + "post_name": "Berlin", + "thoroughfare": "Dienstsitz Berlin" + }, + { + "request_id": "d000454", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Skanska Direkt AB", + "country_code": "SWE", + "nuts_code": "SE", + "post_code": "901 03", + "post_name": "Umeå", + "thoroughfare": "Box 93" + }, + { + "request_id": "d000455", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Direcția Generală de Asistență Socială și Protecția Copilului Brașov", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500091", + "post_name": "Brașov", + "thoroughfare": "Str. Iuliu Maniu nr. 6" + }, + { + "request_id": "d000456", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "GEIT Reimer Ingenieurbüro für TGA", + "country_code": "DEU", + "nuts_code": "DEF0C", + "post_code": "24848", + "post_name": "Kropp", + "thoroughfare": "Poststraße 12" + }, + { + "request_id": "d000457", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Alpha Ned 2000 Exim", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "010816", + "post_name": "București", + "thoroughfare": "Calea Griviței nr. 188, sector 1" + }, + { + "request_id": "d000458", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Finn og Albert Egeland AS", + "country_code": "NOR", + "nuts_code": "NO092", + "post_code": "4688", + "post_name": "Kristiansand S", + "thoroughfare": "Postboks 1592 Lundsiden" + }, + { + "request_id": "d000459", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Regia Națională a Pădurilor – Romsilva R.A.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "540052", + "post_name": "Târgu Mureș", + "thoroughfare": "Prin Direcția Silvică Mureș, Str. George Enescu nr. 6" + }, + { + "request_id": "d000460", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Association Compostri", + "country_code": "FRA", + "nuts_code": "FRG01", + "post_code": null, + "post_name": "Nantes", + "thoroughfare": null + }, + { + "request_id": "d000461", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fujitsu Technology Solutions GmbH", + "country_code": "DEU", + "nuts_code": "DEA11", + "post_code": "40472", + "post_name": "Düsseldorf", + "thoroughfare": "Gladbecker Str. 7" + }, + { + "request_id": "d000462", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Genesis Pharma Cyprus Ltd.", + "country_code": "CYP", + "nuts_code": "CY", + "post_code": "2025 Στρόβολος", + "post_name": "Λευκωσία", + "thoroughfare": "Αμφιπόλεως 2, 1ος όροφος" + }, + { + "request_id": "d000463", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Penitenciarul Brăila", + "country_code": "ROU", + "nuts_code": "RO221", + "post_code": "810110", + "post_name": "Brăila", + "thoroughfare": "Str. Carantina nr. 4A" + }, + { + "request_id": "d000464", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Banedanmark", + "country_code": "DNK", + "nuts_code": "DK", + "post_code": "1577", + "post_name": "København V", + "thoroughfare": "Carsten Niebuhrs Gade 43" + }, + { + "request_id": "d000465", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Clinic Județean de Urgență Craiova", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "200642", + "post_name": "Craiova", + "thoroughfare": "Str. Tabaci nr. 1" + }, + { + "request_id": "d000466", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "NCC Industry", + "country_code": "NOR", + "nuts_code": "NO", + "post_code": "0101", + "post_name": "Oslo", + "thoroughfare": "Postboks 93 Sentrum" + }, + { + "request_id": "d000467", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Costacos Com S.R.L.", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500108", + "post_name": "Brașov", + "thoroughfare": "Str. Valea Tei nr. 31A" + }, + { + "request_id": "d000468", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Staatliches Bau- und Liegenschaftsamt Rostock", + "country_code": "DEU", + "nuts_code": "DE803", + "post_code": "18055", + "post_name": "Rostock", + "thoroughfare": "Wallstraße 2" + }, + { + "request_id": "d000469", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Institut Català de la Salut — Hospital Universitari Vall d'Hebron", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08035", + "post_name": "Barcelona", + "thoroughfare": "Passeig Vall d'Hebron, 119-129" + }, + { + "request_id": "d000470", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Uninett Sigma2 AS", + "country_code": "NOR", + "nuts_code": "NO060", + "post_code": "7030", + "post_name": "Trondheim", + "thoroughfare": "Abels gate 5" + }, + { + "request_id": "d000471", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bert Peine + Wilhelm GmbH & Co.KG", + "country_code": "DEU", + "nuts_code": "DE21L", + "post_code": "82205", + "post_name": "Gilching-Argelsried", + "thoroughfare": "Münchner Str. 22" + }, + { + "request_id": "d000472", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "YIT Suomi Oy", + "country_code": "FIN", + "nuts_code": "FI1B", + "post_code": "FI-00620", + "post_name": "Helsinki", + "thoroughfare": "Panuntie 11" + }, + { + "request_id": "d000473", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medika d.d.", + "country_code": "HRV", + "nuts_code": "HR050", + "post_code": "10000", + "post_name": "Zagreb", + "thoroughfare": "Capraška 1" + }, + { + "request_id": "d000474", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kemijski inštitut", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Hajdrihova ulica 19" + }, + { + "request_id": "d000475", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Abbott Rapid Diagnostics Healthcare, S. L.", + "country_code": "ESP", + "nuts_code": "ES51", + "post_code": "08908", + "post_name": "Hospitalet de Llobregat", + "thoroughfare": "Plaza Europa, 9-11, 6.ª planta" + }, + { + "request_id": "d000476", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Carrières de l'Est — Établissement de Sainte-Magnance", + "country_code": "FRA", + "nuts_code": "FRC14", + "post_code": "89420", + "post_name": "Sainte-Magnance", + "thoroughfare": "72 rue d'Avallon" + }, + { + "request_id": "d000477", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Patronat Municipal del Museu", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08401", + "post_name": "Granollers", + "thoroughfare": "Plaça Porxada, 6" + }, + { + "request_id": "d000478", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mittetulundusühing Papaver", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "75331", + "post_name": "Rae vald", + "thoroughfare": "Saarma tee 6" + }, + { + "request_id": "d000479", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Associazione «L’Albero della Vita» onlus", + "country_code": "ITA", + "nuts_code": "ITG19", + "post_code": "96018", + "post_name": "Pachino", + "thoroughfare": "via Unità 6" + }, + { + "request_id": "d000480", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Oracle Portugal — Sistemas de Informação, Lda.", + "country_code": "PRT", + "nuts_code": "PTZZZ", + "post_code": "2740-268", + "post_name": "Porto Salvo", + "thoroughfare": "Lagoas Park, edifício 8" + }, + { + "request_id": "d000481", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bayerische Staatsforsten AöR", + "country_code": "DEU", + "nuts_code": "DE232", + "post_code": "93053", + "post_name": "Regensburg", + "thoroughfare": "Tillystraße 2" + }, + { + "request_id": "d000482", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Metall- und Ladenbau Jung GmbH & Co.KG", + "country_code": "DEU", + "nuts_code": "DE71E", + "post_code": "61200", + "post_name": "Wölfersheim", + "thoroughfare": "Licher Straße 41" + }, + { + "request_id": "d000483", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Harmek AB", + "country_code": "SWE", + "nuts_code": "SE231", + "post_code": "312 51", + "post_name": "Knäred", + "thoroughfare": "Lageredsvägen 2" + }, + { + "request_id": "d000484", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Immergis", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "34790", + "post_name": "Grabels", + "thoroughfare": "44 rue Antoine-Jérôme-Balard" + }, + { + "request_id": "d000485", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "TPL Systèmes", + "country_code": "FRA", + "nuts_code": "FRI11", + "post_code": "24200", + "post_name": "Sarlat-la-Canéda", + "thoroughfare": "ZAE du Périgord Noir" + }, + { + "request_id": "d000486", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Staatliches Bauamt München 1", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "81547", + "post_name": "München", + "thoroughfare": "https://my.vergabe.bayern.de" + }, + { + "request_id": "d000487", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Logirem", + "country_code": "FRA", + "nuts_code": "FRL04", + "post_code": "13003", + "post_name": "Marseille", + "thoroughfare": "111 BD national" + }, + { + "request_id": "d000488", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Deutsche Bundesbank, Beschaffungszentrum", + "country_code": "DEU", + "nuts_code": "DE712", + "post_code": "60329", + "post_name": "Frankfurt am Main", + "thoroughfare": "Taunusanlage 5" + }, + { + "request_id": "d000489", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Krausberg Eesti OÜ", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "10415", + "post_name": "Tallinn", + "thoroughfare": "Suur-Patarei tn 2" + }, + { + "request_id": "d000490", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Osaühing Arimee", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "80042", + "post_name": "Pärnu linn", + "thoroughfare": "Lao tn 8-10" + }, + { + "request_id": "d000491", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Schüßler-Plan Ingenieurgesellschaft mbH", + "country_code": "DEU", + "nuts_code": "DE712", + "post_code": "60314", + "post_name": "Frankfurt am Main", + "thoroughfare": "Lindleystraße 11" + }, + { + "request_id": "d000492", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Rudicar, S. L.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "24549", + "post_name": "Carracedelo", + "thoroughfare": "Polígono Industrial Las Malladas, nave 8" + }, + { + "request_id": "d000493", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kommunales Vergabezentrum Kreis Groß-Gerau für Kreis Groß-Gerau", + "country_code": "DEU", + "nuts_code": "DE717", + "post_code": "64521", + "post_name": "Groß-Gerau", + "thoroughfare": "Wilhelm-Seipp-Str. 4" + }, + { + "request_id": "d000494", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sitec Dienstleistungs GmbH", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": null, + "post_name": "Kerpen", + "thoroughfare": null + }, + { + "request_id": "d000495", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Distribuție Energie Oltenia S.A.", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "200769", + "post_name": "Craiova", + "thoroughfare": "Calea Severinului nr. 97, parter, et. 2, 3, 4" + }, + { + "request_id": "d000496", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "HSH Entreprenør AS", + "country_code": "NOR", + "nuts_code": "NO092", + "post_code": "4612", + "post_name": "Kristiansand S", + "thoroughfare": "Markens Gate 42" + }, + { + "request_id": "d000497", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "MEDICAL GRUP", + "country_code": "ROU", + "nuts_code": "RO113", + "post_code": "400689", + "post_name": "Cluj-Napoca", + "thoroughfare": "Strada Orastie, Nr. 10" + }, + { + "request_id": "d000498", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bouygues Énergies et Services SAS", + "country_code": "FRA", + "nuts_code": "FR10", + "post_code": "78180", + "post_name": "Montigny-le-Bretonneux", + "thoroughfare": "19 rue Stephenson" + }, + { + "request_id": "d000499", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Land Berlin, Anmietvermögen, vertreten durch die Berliner Immobilienmanagement GmbH", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "10178", + "post_name": "Berlin", + "thoroughfare": "Alexanderstraße 3" + }, + { + "request_id": "d000500", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lexon (GB) Ltd", + "country_code": "GBR", + "nuts_code": "UKG21", + "post_code": null, + "post_name": "Crumlin", + "thoroughfare": "6/7 Rush Drive" + }, + { + "request_id": "d000501", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pôle Habitat/Colmar Centre Alsace — OPH", + "country_code": "FRA", + "nuts_code": "FRF12", + "post_code": "68006", + "post_name": "Colmar Cedex", + "thoroughfare": "Office public de l'habitat — 27 avenue de l'Europe — BP 30334" + }, + { + "request_id": "d000502", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hrvatska elektroprivreda d.d.", + "country_code": "HRV", + "nuts_code": "HR", + "post_code": "10000", + "post_name": "Zagreb", + "thoroughfare": "Ulica grada Vukovara 37" + }, + { + "request_id": "d000503", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Krypton Chemists Ltd", + "country_code": "MLT", + "nuts_code": "MT", + "post_code": null, + "post_name": "Naxxar [In-Naxxar]", + "thoroughfare": "Cantrija Complex, Triq It-Targa, Maghtab," + }, + { + "request_id": "d000504", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pop Industry S.R.L.", + "country_code": "ROU", + "nuts_code": "RO414", + "post_code": "230070", + "post_name": "Slatina", + "thoroughfare": "Strada, Nr." + }, + { + "request_id": "d000505", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Konbini SAS", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75010", + "post_name": "Paris", + "thoroughfare": "48 avenue Claude Vellefaux" + }, + { + "request_id": "d000506", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Thales Deutschland GmbH", + "country_code": "DEU", + "nuts_code": "DE144", + "post_code": "89077", + "post_name": "Ulm", + "thoroughfare": "Söflinger Straße 100" + }, + { + "request_id": "d000507", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Alpha Ned 2000 Exim", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "010816", + "post_name": "București", + "thoroughfare": "Calea Griviței nr. 188, sector 1" + }, + { + "request_id": "d000508", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "WfrK — Werkstätten für raumbildende Konstruktion", + "country_code": "DEU", + "nuts_code": "DEA47", + "post_code": "33098", + "post_name": "Paderborn", + "thoroughfare": null + }, + { + "request_id": "d000509", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Salubris S.A.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700237", + "post_name": "Iași", + "thoroughfare": "Str. Națională nr. 43" + }, + { + "request_id": "d000510", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000511", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Klinički bolnički centar Osijek", + "country_code": "HRV", + "nuts_code": "HR", + "post_code": "31000", + "post_name": "Osijek", + "thoroughfare": "Josipa Huttlera 4" + }, + { + "request_id": "d000512", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "B. BRAUN MEDICAL", + "country_code": "BEL", + "nuts_code": "BE", + "post_code": "1831", + "post_name": "Diegem", + "thoroughfare": "Lambroekstraat 5b" + }, + { + "request_id": "d000513", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Rollladen & Insektenschutz Service", + "country_code": "DEU", + "nuts_code": "DE402", + "post_code": "03046", + "post_name": "Cottbus", + "thoroughfare": "Wernerstraße 27" + }, + { + "request_id": "d000514", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "180 degrés Ingénierie", + "country_code": "FRA", + "nuts_code": "FRI12", + "post_code": "33100", + "post_name": "Bordeaux", + "thoroughfare": "1 quai Deschamps" + }, + { + "request_id": "d000515", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Autobahnen- und Schnellstraßen-Finanzierungs-Aktiengesellschaft", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "1030", + "post_name": "Wien", + "thoroughfare": "z. H. ASFINAG Bau Management GmbH, Modecenterstraße 16" + }, + { + "request_id": "d000516", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Thüringer Ministerium für Bildung, Jugend und Sport", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": "99096", + "post_name": "Erfurt", + "thoroughfare": "Werner - Seelenbinder - Straße 7" + }, + { + "request_id": "d000517", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SATE", + "country_code": "FRA", + "nuts_code": "FRL04", + "post_code": "13011", + "post_name": "Marseille", + "thoroughfare": "116 BLD de la Pomme" + }, + { + "request_id": "d000518", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vingmed AB", + "country_code": "SWE", + "nuts_code": "SE11", + "post_code": "175 26", + "post_name": "Järfälla", + "thoroughfare": "Box 576" + }, + { + "request_id": "d000519", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Agence de services et de paiement", + "country_code": "FRA", + "nuts_code": "FRI23", + "post_code": "87040", + "post_name": "Limoges", + "thoroughfare": "2 rue du Maupas" + }, + { + "request_id": "d000520", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "R.D.R. SpA", + "country_code": "ITA", + "nuts_code": "IT", + "post_code": null, + "post_name": "Torre del Greco (NA)", + "thoroughfare": null + }, + { + "request_id": "d000521", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Augustinum gGmbH", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "801375", + "post_name": "München", + "thoroughfare": "Stiftsbogen 74" + }, + { + "request_id": "d000522", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hoogheemraadschap Hollands Noorderkwartier", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "1703 WC", + "post_name": "Heerhugowaard", + "thoroughfare": "Stationsplein 136" + }, + { + "request_id": "d000523", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "O2 Czech Republic, a.s.", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": "140 22", + "post_name": "Praha 4 - Michle", + "thoroughfare": "Za Brumlovkou 266/2" + }, + { + "request_id": "d000524", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Whistlejacket London", + "country_code": "GBR", + "nuts_code": "UK", + "post_code": "W1F 0PH", + "post_name": "London", + "thoroughfare": "8 Berwick Street" + }, + { + "request_id": "d000525", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Banco de España", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": "28014", + "post_name": "Madrid", + "thoroughfare": "C/ Alcalá, 48" + }, + { + "request_id": "d000526", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Alvalop Servicios XXI, S. L.", + "country_code": "ESP", + "nuts_code": "ES114", + "post_code": "36500", + "post_name": "Lalín", + "thoroughfare": "Avenida de Buenos Aires, 103" + }, + { + "request_id": "d000527", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tinoco Sistemas, S. L.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "41009", + "post_name": "Sevilla", + "thoroughfare": "C/ Fray Luis de Granada, 1" + }, + { + "request_id": "d000528", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ASFINAG Service GmbH", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "1030", + "post_name": "Wien", + "thoroughfare": "Modecenterstraße 16, 6.STock" + }, + { + "request_id": "d000529", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sana Klinikum Hof GmbH", + "country_code": "DEU", + "nuts_code": "DE244", + "post_code": "95032", + "post_name": "Hof / Saale", + "thoroughfare": "Eppenreuther Str. 9" + }, + { + "request_id": "d000530", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nevadasec Építményüzemeltetési és Biztonsági Korlátolt felelősségű társaság", + "country_code": "HUN", + "nuts_code": "HU110", + "post_code": "1133", + "post_name": "Budapest", + "thoroughfare": "Tutaj u. 6/A 3. em. 5." + }, + { + "request_id": "d000531", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Colas France", + "country_code": "FRA", + "nuts_code": "FRI32", + "post_code": "17139", + "post_name": "Dompierre-sur-Mer", + "thoroughfare": null + }, + { + "request_id": "d000532", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universitatea „Alexandru Ioan Cuza” Iași", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700506", + "post_name": "Iași", + "thoroughfare": "Str. Carol I nr. 11" + }, + { + "request_id": "d000533", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Labena trgovina, svetovanje in proizvodnja laboratorijske opreme d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Verovškova ulica 64" + }, + { + "request_id": "d000534", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Glaserei Udo Trögel", + "country_code": "DEU", + "nuts_code": "DED44", + "post_code": "08541", + "post_name": "Neuensalz", + "thoroughfare": "Hauptstr. 10a" + }, + { + "request_id": "d000535", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CCI de Vaucluse", + "country_code": "FRA", + "nuts_code": "FRL06", + "post_code": "84000", + "post_name": "Avignon", + "thoroughfare": "46 cours Jean Jaurès" + }, + { + "request_id": "d000536", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Chouffot SAS", + "country_code": "FRA", + "nuts_code": "FR104", + "post_code": "91540", + "post_name": "Fontenay-le-Vicomte", + "thoroughfare": "avenue Saint-Rémi" + }, + { + "request_id": "d000537", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "De LOCHTING vzw", + "country_code": "BEL", + "nuts_code": "BE", + "post_code": "8800", + "post_name": "Roeselare", + "thoroughfare": "Oude Stadenstraat 15" + }, + { + "request_id": "d000538", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Finnmap Infra Oy", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-00520", + "post_name": "Helsinki", + "thoroughfare": "Ratapihantie 11" + }, + { + "request_id": "d000539", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "HEWE Glas- und Metallbau GmbH", + "country_code": "DEU", + "nuts_code": "DE134", + "post_code": "77933", + "post_name": "Lahr", + "thoroughfare": "Archimedesstr. 3" + }, + { + "request_id": "d000540", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Deutsche Forschungsgemeinschaft", + "country_code": "DEU", + "nuts_code": "DEA22", + "post_code": "53175", + "post_name": "Bonn", + "thoroughfare": "Kennedyallee 40" + }, + { + "request_id": "d000541", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AENA, S. M. E., S. A.", + "country_code": "ESP", + "nuts_code": "ES30", + "post_code": "28017", + "post_name": "Madrid", + "thoroughfare": "Avenida de la Hispanidad, s/n" + }, + { + "request_id": "d000542", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dirección General de la Mutual Midat Cyclops, Mutua Colaboradora con la Seguridad Social número 1", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08029", + "post_name": "Barcelona", + "thoroughfare": "Avenida Josep Tarradellas, 14-18" + }, + { + "request_id": "d000543", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Associação de Agricultores do Sul (ACOS)", + "country_code": "PRT", + "nuts_code": "PT", + "post_code": "7801-904", + "post_name": "Beja", + "thoroughfare": "Rua Cidade de São Paulo, apartado 296" + }, + { + "request_id": "d000544", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Otto Stöckl Elektroinstallationen GmbH", + "country_code": "AUT", + "nuts_code": "AT", + "post_code": "1030", + "post_name": "Wien", + "thoroughfare": "Steingasse 23" + }, + { + "request_id": "d000545", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "XL Insurance Company SE", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75017", + "post_name": "Paris", + "thoroughfare": "61 rue Mstislav Rostropovitch" + }, + { + "request_id": "d000546", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Atalian Propreté PACA", + "country_code": "FRA", + "nuts_code": "FRL04", + "post_code": "13100", + "post_name": "Aix-en-Provence", + "thoroughfare": "190 rue Nicolas-Ledoux" + }, + { + "request_id": "d000547", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Department of Contracts", + "country_code": "MLT", + "nuts_code": "MT", + "post_code": "FRN 1600", + "post_name": "Floriana", + "thoroughfare": "Notre Dame Ravelin" + }, + { + "request_id": "d000548", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ProRail bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3511 EP", + "post_name": "Utrecht", + "thoroughfare": "Moreelsepark 3" + }, + { + "request_id": "d000549", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helsingin ja Uudenmaan sairaanhoitopiirin kuntayhtymä / HUS Logistiikka", + "country_code": "FIN", + "nuts_code": "FI1", + "post_code": "FI-01770", + "post_name": "Vantaa", + "thoroughfare": "Uutistie 5" + }, + { + "request_id": "d000550", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Croonwolter&dros bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3002 AB", + "post_name": "Rotterdam", + "thoroughfare": "Postbus 6073" + }, + { + "request_id": "d000551", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ratatek Oy", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-01900", + "post_name": "Nurmijärvi", + "thoroughfare": "Alhonniiituntie 4" + }, + { + "request_id": "d000552", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Ludwigsburg", + "country_code": "DEU", + "nuts_code": "DE115", + "post_code": "71638", + "post_name": "Ludwigsburg", + "thoroughfare": "Wilhelmstraße 11" + }, + { + "request_id": "d000553", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ministerie van Defensie", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "2511 CB", + "post_name": "Den Haag", + "thoroughfare": "Kalvermarkt 32" + }, + { + "request_id": "d000554", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier universitaire de Poitiers", + "country_code": "FRA", + "nuts_code": "FRI34", + "post_code": "86021", + "post_name": "Poitiers", + "thoroughfare": "2 rue de la Milétrie, CS 90577" + }, + { + "request_id": "d000555", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Urtica Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL51", + "post_code": "54-613", + "post_name": "Wrocław", + "thoroughfare": "ul. Krzemieniecka 120" + }, + { + "request_id": "d000556", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Junta de Gobierno del Ayuntamiento de Murcia", + "country_code": "ESP", + "nuts_code": "ES620", + "post_code": "30004", + "post_name": "Murcia", + "thoroughfare": "Glorieta de España, 1" + }, + { + "request_id": "d000557", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Soresic SA", + "country_code": "BEL", + "nuts_code": "BE32B", + "post_code": "6000", + "post_name": "Charleroi", + "thoroughfare": "Boulevard Mayence 1" + }, + { + "request_id": "d000558", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Broadstory", + "country_code": "FRA", + "nuts_code": "FR1", + "post_code": "75011", + "post_name": "Paris", + "thoroughfare": null + }, + { + "request_id": "d000559", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Cogeci", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69517", + "post_name": "Vaulx-en-Velin", + "thoroughfare": "10 avenue des Canuts" + }, + { + "request_id": "d000560", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Ob Dravi 2A" + }, + { + "request_id": "d000561", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Forskningsfondens Ejendomsselskab A/S (FEAS)", + "country_code": "DNK", + "nuts_code": "DK042", + "post_code": "8200", + "post_name": "Aarhus N", + "thoroughfare": "Finlandsgade 14" + }, + { + "request_id": "d000562", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Norrlands Bil Tunga Fordon AB", + "country_code": "SWE", + "nuts_code": "SE332", + "post_code": "931 61", + "post_name": "Skellefteå", + "thoroughfare": "Tjärnvägen 5" + }, + { + "request_id": "d000563", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ruhrbahn GmbH", + "country_code": "DEU", + "nuts_code": "DEA13", + "post_code": "45130", + "post_name": "Essen", + "thoroughfare": "Zweigertstr. 34" + }, + { + "request_id": "d000564", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Intus Workforce Solutions bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3972 NG", + "post_name": "Driebergen-Rijsenburg", + "thoroughfare": "Princenhof Park 12" + }, + { + "request_id": "d000565", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Samenvijf bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Amsterdam", + "thoroughfare": null + }, + { + "request_id": "d000566", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tulli", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-00520", + "post_name": "Helsinki", + "thoroughfare": "Opastinsilta 12" + }, + { + "request_id": "d000567", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "EJIE — Sociedad Informática del Gobierno Vasco", + "country_code": "ESP", + "nuts_code": "ES21", + "post_code": null, + "post_name": "Vitoria-Gasteiz", + "thoroughfare": "Avenida del Mediterráneo, 14, 01010 Vitoria-Gasteiz" + }, + { + "request_id": "d000568", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Cars Philibert", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69300", + "post_name": "Caluire-et-Cuire", + "thoroughfare": "24 avenue Barthélémy Thimonnier" + }, + { + "request_id": "d000569", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Verovškova ulica 70" + }, + { + "request_id": "d000570", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Västra Götalandsregionen", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "462 80", + "post_name": "Vänersborg", + "thoroughfare": "Östergatan 1" + }, + { + "request_id": "d000571", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lidköpings kommun", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "531 88", + "post_name": "Lidköping", + "thoroughfare": "Skaragatan 8" + }, + { + "request_id": "d000572", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Westland", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "2671 VW", + "post_name": "Naaldwijk", + "thoroughfare": "Verdilaan 7" + }, + { + "request_id": "d000573", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javni zavod Mladi zmaji - Center za kakovostno preživljanje prostega časa mladih", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Resljeva cesta 18" + }, + { + "request_id": "d000574", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "KTO engineering GbR", + "country_code": "DEU", + "nuts_code": "DE27C", + "post_code": "87730", + "post_name": "Bad Grönebach", + "thoroughfare": "Pappenheimerstraße 4" + }, + { + "request_id": "d000575", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Siemens SAS", + "country_code": "FRA", + "nuts_code": "FRF33", + "post_code": "57084", + "post_name": "Metz", + "thoroughfare": "6 rue Marie de Coëtlosquet" + }, + { + "request_id": "d000576", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Brandner Unterallgäu UG", + "country_code": "DEU", + "nuts_code": "DE27C", + "post_code": null, + "post_name": "Babenhausen", + "thoroughfare": null + }, + { + "request_id": "d000577", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Integral de Vigilancia y Control, S. L.", + "country_code": "ESP", + "nuts_code": "ES213", + "post_code": null, + "post_name": "Santurtzi", + "thoroughfare": null + }, + { + "request_id": "d000578", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ortostuudio OÜ", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "76505", + "post_name": "Saue vald", + "thoroughfare": "Sooja tn 1" + }, + { + "request_id": "d000579", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "José Damián Alonso Robayna (Áridos Alonso)", + "country_code": "ESP", + "nuts_code": "ES704", + "post_code": "35600", + "post_name": "Puerto del Rosario", + "thoroughfare": "C/ Tajinaste, 28" + }, + { + "request_id": "d000580", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG", + "country_code": "DEU", + "nuts_code": "DE942", + "post_code": "27751", + "post_name": "Delmenhorst", + "thoroughfare": "Nordenhamer Str. 65" + }, + { + "request_id": "d000581", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Akbal Bau GmbH", + "country_code": "DEU", + "nuts_code": "DE21B", + "post_code": "44809", + "post_name": "Bochum", + "thoroughfare": "Berggate 69" + }, + { + "request_id": "d000582", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Institut Jožef Stefan", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Jamova cesta 39" + }, + { + "request_id": "d000583", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SPL Perpignan Méditerranée", + "country_code": "FRA", + "nuts_code": "FRJ15", + "post_code": "66000", + "post_name": "Perpignan", + "thoroughfare": "35 boulevard Saint-Assiscle Bât C" + }, + { + "request_id": "d000584", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Iserba", + "country_code": "FRA", + "nuts_code": "FRK21", + "post_code": "01704", + "post_name": "Beynost", + "thoroughfare": "303 rue du Chat Botté — CS 10412" + }, + { + "request_id": "d000585", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Scop SA Savoirsplus", + "country_code": "FRA", + "nuts_code": "FRG02", + "post_code": "49320", + "post_name": "Brissac-Loire-Aubance", + "thoroughfare": "18 boulevard des Fontenelles" + }, + { + "request_id": "d000586", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ayuntamiento de Vitoria-Gasteiz", + "country_code": "ESP", + "nuts_code": "ES211", + "post_code": null, + "post_name": "Vitoria-Gasteiz", + "thoroughfare": "C/ Pintor Teodoro Dublang, 25, bajo, 01008 Vitoria-Gasteiz (Álava-Araba)" + }, + { + "request_id": "d000587", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Communauté d'agglomération Porte de l'Isère", + "country_code": "FRA", + "nuts_code": "FRK24", + "post_code": "38081", + "post_name": "L'Isle-d'Abeau", + "thoroughfare": "Service «Achats Marchés publics», 17 avenue du Bourg" + }, + { + "request_id": "d000588", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Santomed S.R.L.", + "country_code": "ROU", + "nuts_code": "RO424", + "post_code": "300210", + "post_name": "Timișoara", + "thoroughfare": "Str. Liviu Rebreanu nr. 25" + }, + { + "request_id": "d000589", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Arca Mondo Chim S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "050801", + "post_name": "București", + "thoroughfare": "Str. Baltagului nr. 5, sector 5" + }, + { + "request_id": "d000590", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Menigo Foodservice AB", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "721 28", + "post_name": "Västerås", + "thoroughfare": "Box 1120" + }, + { + "request_id": "d000591", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Huddinge kommun", + "country_code": "SWE", + "nuts_code": "SE", + "post_code": "141 61", + "post_name": "Huddinge", + "thoroughfare": "Kommunalvägen 28" + }, + { + "request_id": "d000592", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Município de Lisboa", + "country_code": "PRT", + "nuts_code": "PT170", + "post_code": "1749-099", + "post_name": "Lisboa", + "thoroughfare": "Campo Grande, 25, 9.º A" + }, + { + "request_id": "d000593", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Deutsche Rentenversicherung Knappschaft-Bahn-See", + "country_code": "DEU", + "nuts_code": "DEA51", + "post_code": "44799", + "post_name": "Bochum", + "thoroughfare": "Wasserstr.215" + }, + { + "request_id": "d000594", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Atelier Architecture Perraudin", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69001", + "post_name": "Lyon", + "thoroughfare": "16 rue Imbert Colomès" + }, + { + "request_id": "d000595", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Software Imagination & Vision", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "013685", + "post_name": "București", + "thoroughfare": "Str. Bucureşti-Ploieşti nr. 73-81, sector 1" + }, + { + "request_id": "d000596", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medicina Analit Consumibles Mac, S. A.", + "country_code": "ESP", + "nuts_code": "ES213", + "post_code": null, + "post_name": "Sondika (Bizkaia)", + "thoroughfare": null + }, + { + "request_id": "d000597", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sveriges Lantbruksuniversitet", + "country_code": "SWE", + "nuts_code": "SE121", + "post_code": "750 07", + "post_name": "Uppsala", + "thoroughfare": "Box 7086" + }, + { + "request_id": "d000598", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Uppsala kommun", + "country_code": "SWE", + "nuts_code": "SE121", + "post_code": "753 75", + "post_name": "Uppsala", + "thoroughfare": "Uppsala kommun Kommunledningskontoret" + }, + { + "request_id": "d000599", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Union CO", + "country_code": "ROU", + "nuts_code": "RO113", + "post_code": "400552", + "post_name": "Cluj-Napoca", + "thoroughfare": "Str. Miron Costin nr. 12A" + }, + { + "request_id": "d000600", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Cooperative Eureden", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "29206", + "post_name": "Landerneau", + "thoroughfare": null + }, + { + "request_id": "d000601", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Woonwijzerwinkel", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "3089 JA", + "post_name": "Rotterdam", + "thoroughfare": "Directiekade 2" + }, + { + "request_id": "d000602", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Országos Mentőszolgálat", + "country_code": "HUN", + "nuts_code": "HU", + "post_code": "1055", + "post_name": "Budapest", + "thoroughfare": "Markó utca 22." + }, + { + "request_id": "d000603", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Société Easter Eggs", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "75014", + "post_name": "Paris", + "thoroughfare": "44-46 rue de l'Ouest" + }, + { + "request_id": "d000604", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Umeå kommun", + "country_code": "SWE", + "nuts_code": "SE", + "post_code": "901 84", + "post_name": "Umeå", + "thoroughfare": "Upphandlingsbyrån" + }, + { + "request_id": "d000605", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "KKS Architektur + Gestaltung", + "country_code": "DEU", + "nuts_code": "DED21", + "post_code": "01099", + "post_name": "Dresden", + "thoroughfare": "Louisenstraße 9" + }, + { + "request_id": "d000606", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Cardinal Health Sweden 512 AB", + "country_code": "SWE", + "nuts_code": "SE11", + "post_code": "113 29", + "post_name": "Stockholm", + "thoroughfare": "Norrtullsgatan 6" + }, + { + "request_id": "d000607", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ITD solutions SpA", + "country_code": "ITA", + "nuts_code": "ITC4C", + "post_code": "20124", + "post_name": "Milano", + "thoroughfare": "via Galileo Galilei 7" + }, + { + "request_id": "d000608", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Serviciul de Telecomunicații Speciale", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "060044", + "post_name": "Bucureşti", + "thoroughfare": "Str. Independenţei nr. 323A" + }, + { + "request_id": "d000609", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "OSAGE bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Utrecht", + "thoroughfare": null + }, + { + "request_id": "d000610", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "evia innovation GmbH", + "country_code": "DEU", + "nuts_code": "DE111", + "post_code": "70565", + "post_name": "Stuttgart", + "thoroughfare": "Am Wallgraben 100" + }, + { + "request_id": "d000611", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Barresi Axion boutique", + "country_code": "FRA", + "nuts_code": "FRE", + "post_code": "62118", + "post_name": "Biache-Saint-Vaast", + "thoroughfare": "3 rue pasteur \"Les Usines\"" + }, + { + "request_id": "d000612", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Comune di Pachino", + "country_code": "ITA", + "nuts_code": "ITG19", + "post_code": "96018", + "post_name": "Pachino (SR)", + "thoroughfare": "via XXV Luglio" + }, + { + "request_id": "d000613", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hiscox SA — Hiscox France", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75002", + "post_name": "Paris", + "thoroughfare": "38 avenue de l'Opéra" + }, + { + "request_id": "d000614", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Swiss Post Solutions GmbH", + "country_code": "DEU", + "nuts_code": "DE241", + "post_code": null, + "post_name": "Bamberg", + "thoroughfare": null + }, + { + "request_id": "d000615", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Beschaffungsamt des Bundesministeriums des Innern", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "53023", + "post_name": "Bonn", + "thoroughfare": "Postfach 41 01 55" + }, + { + "request_id": "d000616", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Netz AG (Bukr 16)", + "country_code": "DEU", + "nuts_code": "DE712", + "post_code": "60327", + "post_name": "Frankfurt am Main", + "thoroughfare": "Adam-Riese-Straße 11-13" + }, + { + "request_id": "d000617", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Clece, S. A.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "28050", + "post_name": "Madrid", + "thoroughfare": "Avenida Manoteras, 46 bis" + }, + { + "request_id": "d000618", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Björnsen Beratende Ingenieure GmbH", + "country_code": "DEU", + "nuts_code": "DEB1", + "post_code": "56070", + "post_name": "Koblenz", + "thoroughfare": "Maria Trost 3" + }, + { + "request_id": "d000619", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DZS, založništvo in trgovina, d.d.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Dalmatinova ulica 2" + }, + { + "request_id": "d000620", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Bocholt", + "country_code": "DEU", + "nuts_code": "DEA34", + "post_code": "46395", + "post_name": "Bocholt", + "thoroughfare": "Kaiser-Wilhelm-Straße 52-58" + }, + { + "request_id": "d000621", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "B & B service sas di Budri Paolo & C sas (capogruppo)", + "country_code": "ITA", + "nuts_code": "ITC48", + "post_code": "27058", + "post_name": "Voghera", + "thoroughfare": "via Emilio Sturla 35" + }, + { + "request_id": "d000622", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javno podjetje Energetika Ljubljana d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Verovškova ulica 62" + }, + { + "request_id": "d000623", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "costituendo R.T.I. KPMG advisory SpA — INFO.C.E.R. srl", + "country_code": "ITA", + "nuts_code": "ITI4", + "post_code": null, + "post_name": "Roma", + "thoroughfare": null + }, + { + "request_id": "d000624", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Knowlimits s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": "155 00", + "post_name": "Praha 5", + "thoroughfare": "Píškova 1948/16" + }, + { + "request_id": "d000625", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FILANTROPIA ORTODOXA ALBA IULIA FILIALA DANES", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "547200", + "post_name": "Danes", + "thoroughfare": "Strada PRINCIPALA, Nr. 92" + }, + { + "request_id": "d000626", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tentours turistična agencija, d.o.o., Ljubljanska 85, Domžale", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1230", + "post_name": "Domžale", + "thoroughfare": "Ljubljanska cesta 85" + }, + { + "request_id": "d000627", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SKR stav, s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ064", + "post_code": "614 00", + "post_name": "Brno", + "thoroughfare": "Nováčkova 233/18" + }, + { + "request_id": "d000628", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Industrias F. Botella, S. L.", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": null, + "post_name": "Barcelona", + "thoroughfare": null + }, + { + "request_id": "d000629", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Augustinum gGmbH", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "801375", + "post_name": "München", + "thoroughfare": "Stiftsbogen 74" + }, + { + "request_id": "d000630", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nano Medicina, trgovina d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1260", + "post_name": "Ljubljana - Polje", + "thoroughfare": "Grajzerjeva ulica 23A" + }, + { + "request_id": "d000631", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Omega svetovanje, inženiring, razvoj in raziskovanje, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Dolinškova ulica 8" + }, + { + "request_id": "d000632", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Univerzitetni klinični center Maribor", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Ljubljanska ulica 5" + }, + { + "request_id": "d000633", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sector 3 (Primăria Sector 3 București)", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "031084", + "post_name": "Bucureşti", + "thoroughfare": "Str. Dudești nr. 191" + }, + { + "request_id": "d000634", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Siemens Financial Services", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "93527", + "post_name": "Saint-Denis Cedex", + "thoroughfare": "40 avenue des Fruitiers" + }, + { + "request_id": "d000635", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Ob Dravi 2A" + }, + { + "request_id": "d000636", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vladoor Smart", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "207115", + "post_name": "Breasta", + "thoroughfare": "Str. Parcului nr. 5A" + }, + { + "request_id": "d000637", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Skarb Państwa – Urząd Komunikacji Elektronicznej", + "country_code": "POL", + "nuts_code": "PL91", + "post_code": "01-211", + "post_name": "Warszawa", + "thoroughfare": "ul. Giełdowa 7/9" + }, + { + "request_id": "d000638", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "HWK Trier", + "country_code": "DEU", + "nuts_code": "DEB21", + "post_code": null, + "post_name": "Trier", + "thoroughfare": null + }, + { + "request_id": "d000639", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Coral Impex S.R.L.", + "country_code": "ROU", + "nuts_code": "RO316", + "post_code": "100510", + "post_name": "Ploiești", + "thoroughfare": "Str. Peneș Curcanu nr. 8, bloc 151C, ap. 10" + }, + { + "request_id": "d000640", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Acea SpA", + "country_code": "ITA", + "nuts_code": "ITI43", + "post_code": null, + "post_name": "Roma", + "thoroughfare": "p.le Ostiense 2" + }, + { + "request_id": "d000641", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FOCUS TRADING '94 S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "011657", + "post_name": "Bucuresti", + "thoroughfare": "Strada Tudor Stefan, Nr. 10, Sector: 1" + }, + { + "request_id": "d000642", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pop Industry S.R.L.", + "country_code": "ROU", + "nuts_code": "RO414", + "post_code": "230070", + "post_name": "Slatina", + "thoroughfare": "Strada, Nr." + }, + { + "request_id": "d000643", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix Telecom S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "020331", + "post_name": "București", + "thoroughfare": "Str. Fabrica de Glucoză nr. 11D" + }, + { + "request_id": "d000644", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Blackboard", + "country_code": "NLD", + "nuts_code": "NL32", + "post_code": "Amsterdam", + "post_name": "Amsterdam", + "thoroughfare": "Paleisstraat 1-5" + }, + { + "request_id": "d000645", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Land Berlin, Sondervermögen für Daseinsvorsorge und nicht betriebsnotwendige Bestandsgrundstücke des Landes Berlin (SODA)vertreten durch die Berliner Immobilienmanagement GmbH", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "10178", + "post_name": "Berlin", + "thoroughfare": "Alexanderstraße 3" + }, + { + "request_id": "d000646", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Proxis spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "184 00", + "post_name": "Praha 8", + "thoroughfare": "Spořická 296/46" + }, + { + "request_id": "d000647", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bright Finland Oy", + "country_code": "FIN", + "nuts_code": "FI1B1", + "post_code": null, + "post_name": "Vantaa", + "thoroughfare": null + }, + { + "request_id": "d000648", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Daser srl", + "country_code": "ITA", + "nuts_code": "IT", + "post_code": null, + "post_name": "Treviso", + "thoroughfare": null + }, + { + "request_id": "d000649", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasser und Kulturbau Leeegebruch GmbH", + "country_code": "DEU", + "nuts_code": "DE40", + "post_code": "16767", + "post_name": "Leegebruch", + "thoroughfare": "Eichenallee 1" + }, + { + "request_id": "d000650", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Județean de Urgență Bacău", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bacău", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000651", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Uniha GCS", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69003", + "post_name": "Lyon", + "thoroughfare": "9 rue des Tuiliers" + }, + { + "request_id": "d000652", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "BOMA nv", + "country_code": "BEL", + "nuts_code": "BE", + "post_code": "2030", + "post_name": "Antwerpen 3", + "thoroughfare": "Noorderlaan 131" + }, + { + "request_id": "d000653", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Planon SA", + "country_code": "BEL", + "nuts_code": "BE21", + "post_code": "2800", + "post_name": "Mechelen", + "thoroughfare": null + }, + { + "request_id": "d000654", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Verovškova ulica 70" + }, + { + "request_id": "d000655", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Urbaser, S. A.", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": null, + "post_name": "Madrid", + "thoroughfare": null + }, + { + "request_id": "d000656", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wohn- und Pflegeheim Zell am Ziller - Kaiser Franz Josef Stiftung", + "country_code": "AUT", + "nuts_code": "AT335", + "post_code": "6280", + "post_name": "Zell am Ziller", + "thoroughfare": "Gerlosstraße 5" + }, + { + "request_id": "d000657", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "KARL STORZ ENDOSCOPIA ROMANIA", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "041393", + "post_name": "Bucuresti", + "thoroughfare": "Strada Colorian Anton, prof. dr., Nr. 74, Sector: 4" + }, + { + "request_id": "d000658", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SICI srl", + "country_code": "ITA", + "nuts_code": "ITH20", + "post_code": null, + "post_name": "S. Pietro in Cariano (VR)", + "thoroughfare": null + }, + { + "request_id": "d000659", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vertex Pharmaceutical Ireland Limited", + "country_code": "IRL", + "nuts_code": "IE", + "post_code": "D02 EK84", + "post_name": "Dublin 2", + "thoroughfare": "28-32, Pembroke Street Upper" + }, + { + "request_id": "d000660", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dupligrafic SARL", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "77776", + "post_name": "Marne-la-Vallée", + "thoroughfare": "20 avenue Graham-Bell" + }, + { + "request_id": "d000661", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Jacobs U.K. Ltd", + "country_code": "GBR", + "nuts_code": "UKI", + "post_code": "SE1 2QG", + "post_name": "London", + "thoroughfare": "Cottons Centre, Cottons Lane, London, SE1 2QG" + }, + { + "request_id": "d000662", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vrtec Viški gaj", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Reška ulica 31" + }, + { + "request_id": "d000663", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Inetum", + "country_code": "FRA", + "nuts_code": "FR106", + "post_code": "93400", + "post_name": "Saint-Ouen", + "thoroughfare": "145 boulevard Victor Hugo" + }, + { + "request_id": "d000664", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Magirus GmbH", + "country_code": "DEU", + "nuts_code": "DE144", + "post_code": "89079", + "post_name": "Ulm", + "thoroughfare": "Graf-Arco-Str. 30" + }, + { + "request_id": "d000665", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Takeda Pharma Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL9", + "post_code": "00-838", + "post_name": "Warszawa", + "thoroughfare": "ul. Prosta 68" + }, + { + "request_id": "d000666", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Communauté agglo. Privas Centre Ardèche", + "country_code": "FRA", + "nuts_code": "FRK22", + "post_code": "07003", + "post_name": "Privas", + "thoroughfare": "1 rue Serre-du-Serret, BP 337" + }, + { + "request_id": "d000667", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "NRW.BANK AöR", + "country_code": "DEU", + "nuts_code": "DEA11", + "post_code": "40213", + "post_name": "Düsseldorf", + "thoroughfare": "Kavalleriestraße 22" + }, + { + "request_id": "d000668", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fresenius Medical care Slovenija, Trgovsko in proizvodno podjetje medicinske opreme d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "3000", + "post_name": "Celje", + "thoroughfare": "Gaji 28" + }, + { + "request_id": "d000669", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kommunale Immobilien Jena", + "country_code": "DEU", + "nuts_code": "DEG03", + "post_code": "07743", + "post_name": "Jena", + "thoroughfare": "Paradiesstraße 6" + }, + { + "request_id": "d000670", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Electrabel NV", + "country_code": "BEL", + "nuts_code": "BE100", + "post_code": "1000", + "post_name": "Bruxelles", + "thoroughfare": "Boulevard Simon Bolivar 34" + }, + { + "request_id": "d000671", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Splošna bolnišnica Novo mesto", + "country_code": "SVN", + "nuts_code": "SI037", + "post_code": "8000", + "post_name": "Novo mesto", + "thoroughfare": "Šmihelska cesta 1" + }, + { + "request_id": "d000672", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Forstbetrieb Johann Ried", + "country_code": "DEU", + "nuts_code": "DE234", + "post_code": "92266", + "post_name": "Ensdorf", + "thoroughfare": null + }, + { + "request_id": "d000673", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "3TI Progetti Italia Ingegneria Integrata SpA", + "country_code": "ITA", + "nuts_code": "ITI43", + "post_code": "00146", + "post_name": "Roma", + "thoroughfare": "Lungotevere V. Gassman 22" + }, + { + "request_id": "d000674", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Entech Ingénieurs Conseils", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "34140", + "post_name": "Mèze", + "thoroughfare": "Parc scientifique — BP 118" + }, + { + "request_id": "d000675", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Riigikontroll", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "15013", + "post_name": "Tallinn", + "thoroughfare": "Kiriku tn 2" + }, + { + "request_id": "d000676", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ville de Vincennes", + "country_code": "FRA", + "nuts_code": "FR107", + "post_code": "94300", + "post_name": "Vincennes", + "thoroughfare": "53 bis rue de Fontenay" + }, + { + "request_id": "d000677", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "VRTEC POD GRADOM", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Praprotnikova ulica 2" + }, + { + "request_id": "d000678", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Druckerei Schmerbeck GmbH", + "country_code": "DEU", + "nuts_code": "DE227", + "post_code": "84184", + "post_name": "Tiefenbach", + "thoroughfare": "Gutenbergstr. 12" + }, + { + "request_id": "d000679", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Keysight Technologies Deutschland GmbH", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": null, + "post_name": "Böblingen", + "thoroughfare": null + }, + { + "request_id": "d000680", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle", + "country_code": "DEU", + "nuts_code": "DED41", + "post_code": "09111", + "post_name": "Chemnitz", + "thoroughfare": "Friedensplatz 1" + }, + { + "request_id": "d000681", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vrtec Viški gaj", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Reška ulica 31" + }, + { + "request_id": "d000682", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Biming", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69007", + "post_name": "Lyon", + "thoroughfare": "24 rue Jean-Baldassini" + }, + { + "request_id": "d000683", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "BRIARI'S IND", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": null, + "post_name": "Carcea", + "thoroughfare": "Strada Calea Bucuresti, Nr. 2" + }, + { + "request_id": "d000684", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Unipolsai assicurazioni SpA", + "country_code": "ITA", + "nuts_code": "ITH55", + "post_code": null, + "post_name": "Bologna", + "thoroughfare": null + }, + { + "request_id": "d000685", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Idraulica F.lli Sala", + "country_code": "ITA", + "nuts_code": "IT", + "post_code": null, + "post_name": "Concordia sulla Secchia (MO)", + "thoroughfare": null + }, + { + "request_id": "d000686", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "EMSOR, S. L.", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": "28050", + "post_name": "Madrid", + "thoroughfare": "C/ Isabel Colbrand, 10-12, local 138" + }, + { + "request_id": "d000687", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medias International, trgovanje in trženje z medicinskim materialom d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Leskoškova cesta 9D" + }, + { + "request_id": "d000688", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Biomedis M.B. trgovina d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Jurančičeva ulica 11" + }, + { + "request_id": "d000689", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ERNE AG Bauunternehmung", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "8064", + "post_name": "Zürich", + "thoroughfare": "Bernerstraße Nord 202" + }, + { + "request_id": "d000690", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Przedsiębiorstwo Handlowo-Usługowe Anmar Sp. z o.o. Sp. k.", + "country_code": "POL", + "nuts_code": "PL514", + "post_code": "50-502", + "post_name": "Wrocław", + "thoroughfare": "ul. Hubska 44" + }, + { + "request_id": "d000691", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Eco-Equip SAM", + "country_code": "ESP", + "nuts_code": "ES511", + "post_code": "08223", + "post_name": "Terrassa", + "thoroughfare": "C/ Esla, 34" + }, + { + "request_id": "d000692", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Heinäveden kunta", + "country_code": "FIN", + "nuts_code": "FI1D3", + "post_code": null, + "post_name": "Heinävesi", + "thoroughfare": null + }, + { + "request_id": "d000693", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bravida Norge AS (hovedenhet)", + "country_code": "NOR", + "nuts_code": "NO081", + "post_code": "0596", + "post_name": "Oslo", + "thoroughfare": "Østre akervei 90" + }, + { + "request_id": "d000694", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Unielektro GmbH", + "country_code": "DEU", + "nuts_code": "DEB21", + "post_code": null, + "post_name": "Trier", + "thoroughfare": null + }, + { + "request_id": "d000695", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "A la Carte Uniforms OÜ", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "11313", + "post_name": "Tallinn", + "thoroughfare": "Töökoja tn 8" + }, + { + "request_id": "d000696", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "O2 Czech Republic, a.s.", + "country_code": "CZE", + "nuts_code": "CZ01", + "post_code": "140 22", + "post_name": "Praha 4 - Michle", + "thoroughfare": "Za Brumlovkou 266/260193336" + }, + { + "request_id": "d000697", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fritsch Knodt Klug + Partner mbH Architekten", + "country_code": "DEU", + "nuts_code": "DE254", + "post_code": null, + "post_name": "Nürnberg", + "thoroughfare": null + }, + { + "request_id": "d000698", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Étamine", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69120", + "post_name": "Vaulx-en-Velin", + "thoroughfare": "10 allée des Canuts" + }, + { + "request_id": "d000699", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Amsterdam, Personeel en Organisatieadvies", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "1102 CW", + "post_name": "Amsterdam", + "thoroughfare": "Anton de Komplein 150" + }, + { + "request_id": "d000700", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Decutis", + "country_code": "FRA", + "nuts_code": "FRI21", + "post_code": "19300", + "post_name": "Malemort", + "thoroughfare": "9001 route de Beynat" + }, + { + "request_id": "d000701", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "S.C. Nisara Impex S.R.L", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "505600", + "post_name": "Săcele", + "thoroughfare": "Str. Gen. I. Dragalina nr. 21 A" + }, + { + "request_id": "d000702", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Municipiul Cluj-Napoca", + "country_code": "ROU", + "nuts_code": "RO113", + "post_code": "400001", + "post_name": "Cluj-Napoca", + "thoroughfare": "Str. Moților nr. 1-3" + }, + { + "request_id": "d000703", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Penta Általános Építőipari Korlátolt Felelősségű Társaság", + "country_code": "HUN", + "nuts_code": "HU", + "post_code": "2100", + "post_name": "Gödöllő", + "thoroughfare": "Kenyérgyári út 1/E." + }, + { + "request_id": "d000704", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DGPW, S. A.", + "country_code": "PRT", + "nuts_code": "PT112", + "post_code": "4789-180", + "post_name": "Gême", + "thoroughfare": "Centro Empresarial de Gême, pavilhão A8" + }, + { + "request_id": "d000705", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "4PL Central Station Nordic AB", + "country_code": "SWE", + "nuts_code": "SE", + "post_code": "211 20", + "post_name": "Malmö", + "thoroughfare": "Elbegatan 5" + }, + { + "request_id": "d000706", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kassenzahnärztliche Vereinigung Bayerns", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "81369", + "post_name": "München", + "thoroughfare": "Fallstraße 34" + }, + { + "request_id": "d000707", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Alcaldía del Ayuntamiento de San Bartolomé de Lanzarote", + "country_code": "ESP", + "nuts_code": "ES70", + "post_code": "35550", + "post_name": "San Bartolomé", + "thoroughfare": "Plaza León y Castillo, 8" + }, + { + "request_id": "d000708", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Amt Parchimer Umland — Der Amtsvorsteher", + "country_code": "DEU", + "nuts_code": "DE80O", + "post_code": "19370", + "post_name": "Parchim", + "thoroughfare": "Walter-Hase-Straße 42" + }, + { + "request_id": "d000709", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "b. i. g. sicherheit gmbh", + "country_code": "DEU", + "nuts_code": "DEE02", + "post_code": "06116", + "post_name": "Halle Saale", + "thoroughfare": "Fiete-Schulze-Str. 15" + }, + { + "request_id": "d000710", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Krimpen aan den IJssel", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Krimpen aan den IJssel", + "thoroughfare": null + }, + { + "request_id": "d000711", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Moog GmbH.", + "country_code": "DEU", + "nuts_code": "DE1", + "post_code": "88693", + "post_name": "Deggenhausertal", + "thoroughfare": "Im Gewerbegebiet 8" + }, + { + "request_id": "d000712", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nordic Energy Research", + "country_code": "NOR", + "nuts_code": "NO", + "post_code": "0170", + "post_name": "Oslo", + "thoroughfare": "Stensberggata 27" + }, + { + "request_id": "d000713", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Staatl. Bauamt Erlangen-Nürnberg", + "country_code": "DEU", + "nuts_code": "DE254", + "post_code": "90408", + "post_name": "Nürnberg", + "thoroughfare": "Bucher Str. 30" + }, + { + "request_id": "d000714", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Siemens Healthcare Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL911", + "post_code": "03-821", + "post_name": "Warszawa", + "thoroughfare": "Żupnicza 11" + }, + { + "request_id": "d000715", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AE Dozoring", + "country_code": "SVK", + "nuts_code": "SK010", + "post_code": null, + "post_name": null, + "thoroughfare": "Str. Somolického nr. 1/B" + }, + { + "request_id": "d000716", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Autoridade Nacional de Segurança Rodoviária", + "country_code": "PRT", + "nuts_code": "PT", + "post_code": "2734-507", + "post_name": "Barcarena", + "thoroughfare": "Avenida de Casal de Cabanas, Parque de Ciências e Tecnologia de Oeiras" + }, + { + "request_id": "d000717", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Z+M Logistics, spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ080", + "post_code": "702 00", + "post_name": "Ostrava", + "thoroughfare": "Gorkého 621/26, Moravská Ostrava" + }, + { + "request_id": "d000718", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kone", + "country_code": "FRA", + "nuts_code": "FRL0", + "post_code": "06200", + "post_name": "Nice", + "thoroughfare": "455 promenade des Anglais" + }, + { + "request_id": "d000719", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Zagrebška cesta 22" + }, + { + "request_id": "d000720", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Consorzio Innova società cooperativa", + "country_code": "ITA", + "nuts_code": "ITH55", + "post_code": "40128", + "post_name": "Bologna", + "thoroughfare": "via Giovanni Papini 18" + }, + { + "request_id": "d000721", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Castrén Engine Osakeyhtiö", + "country_code": "FIN", + "nuts_code": "FI1B1", + "post_code": null, + "post_name": "Helsinki", + "thoroughfare": null + }, + { + "request_id": "d000722", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AVID", + "country_code": "GBR", + "nuts_code": "UK", + "post_code": "EC3R 8HL", + "post_name": "London", + "thoroughfare": "20 St Dunstans Hill" + }, + { + "request_id": "d000723", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "de Rolf groep bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": "4051 CV", + "post_name": "Ochten", + "thoroughfare": "Mercuriusweg 14" + }, + { + "request_id": "d000724", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Service départemental d'incendie et de secours de Seine-et-Marne", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "77001", + "post_name": "Melun Cedex", + "thoroughfare": "56 avenue de Corbeil, BP 70109" + }, + { + "request_id": "d000725", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nemocnica s poliklinikou Dunajská Streda, a.s.", + "country_code": "SVK", + "nuts_code": "SK021", + "post_code": "929 01", + "post_name": "Dunajská Streda", + "thoroughfare": "Veľkoblahovská 23" + }, + { + "request_id": "d000726", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fehlings Weiß Gleistechnik und Entsorgung GmbH", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "12437", + "post_name": "Berlin", + "thoroughfare": "Palisadenstraße 40" + }, + { + "request_id": "d000727", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Põllumajandusuuringute Keskus", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "75501", + "post_name": "Saku vald", + "thoroughfare": "Teaduse tn 4" + }, + { + "request_id": "d000728", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vermögen und Bau Baden-Württemberg Amt Mannheim und Heidelberg Dienstsitz Mannheim", + "country_code": "DEU", + "nuts_code": "DE126", + "post_code": "68161", + "post_name": "Mannheim", + "thoroughfare": "L 4, 4-6" + }, + { + "request_id": "d000729", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Région Normandie", + "country_code": "FRA", + "nuts_code": "FRD11", + "post_code": "14035", + "post_name": "Caen Cedex", + "thoroughfare": "CS 50523" + }, + { + "request_id": "d000730", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SOS Environnement Nettoyage", + "country_code": "FRA", + "nuts_code": "FRG04", + "post_code": "72700", + "post_name": "Rouillon", + "thoroughfare": "3 impasse Chanteloup" + }, + { + "request_id": "d000731", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bau- und Liegenschaftsbetrieb NRW Bielefeld", + "country_code": "DEU", + "nuts_code": "DEA41", + "post_code": "33602", + "post_name": "Bielefeld", + "thoroughfare": "August- Bebel-Straße 91" + }, + { + "request_id": "d000732", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kemofarmacija, veletrgovina za oskrbo zdravstva, d.d.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Cesta na Brdo 100" + }, + { + "request_id": "d000733", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Department of Contracts", + "country_code": "MLT", + "nuts_code": "MT", + "post_code": "FRN-1600", + "post_name": "Floriana", + "thoroughfare": "Notre Dame Ravelin" + }, + { + "request_id": "d000734", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Commune de la Grande-Motte", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "34280", + "post_name": "La Grande-Motte", + "thoroughfare": "place du 1er Octobre 1974" + }, + { + "request_id": "d000735", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "BG Ingénieurs Conseils SAS, le cotraitant", + "country_code": "FRA", + "nuts_code": "FR107", + "post_code": "94200", + "post_name": "Ivry-sur-Sein", + "thoroughfare": "Metro Sud, 1 BD Hippolyte-Marques" + }, + { + "request_id": "d000736", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Arcobaleno Multiservice srl", + "country_code": "ITA", + "nuts_code": "ITC4C", + "post_code": "20090", + "post_name": "Cesano Boscone (MI)", + "thoroughfare": "via Magellano 4/6" + }, + { + "request_id": "d000737", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Communauté de communes Les Portes Briardes", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "77330", + "post_name": "Ozoir-la-Ferrière", + "thoroughfare": "43 avenue du Général de Gaulle" + }, + { + "request_id": "d000738", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Lansingerland", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Bergschenhoek", + "thoroughfare": null + }, + { + "request_id": "d000739", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Elektrocentar Petek, d.o.o.", + "country_code": "HRV", + "nuts_code": "HR", + "post_code": "10310", + "post_name": "Ivanić Grad", + "thoroughfare": "Etanska cesta 8" + }, + { + "request_id": "d000740", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Roez, s.r.o.", + "country_code": "SVK", + "nuts_code": "SK023", + "post_code": "934 01", + "post_name": "Levice", + "thoroughfare": "Tyršova 2354/2" + }, + { + "request_id": "d000741", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "MAMMUT Deutschland GmbH & Co.KG", + "country_code": "DEU", + "nuts_code": "DE600", + "post_code": null, + "post_name": "Hamburg", + "thoroughfare": null + }, + { + "request_id": "d000742", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Comune di Montefalcone nel Sannio", + "country_code": "ITA", + "nuts_code": "ITF22", + "post_code": "86033", + "post_name": "Montefalcone nel Sannio", + "thoroughfare": "vico 1° V. De Fanis" + }, + { + "request_id": "d000743", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FSMA", + "country_code": "BEL", + "nuts_code": "BE1", + "post_code": "1000", + "post_name": "Bruxelles", + "thoroughfare": "Rue du Congrès 12-14" + }, + { + "request_id": "d000744", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CCI de région Nord-de-France", + "country_code": "FRA", + "nuts_code": "FRE1", + "post_code": "59031", + "post_name": "Lille Cedex", + "thoroughfare": "299 boulevard de Leeds" + }, + { + "request_id": "d000745", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Zagrebška cesta 22" + }, + { + "request_id": "d000746", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Deurganckdoksluis nv", + "country_code": "BEL", + "nuts_code": "BE211", + "post_code": "2030", + "post_name": "Antwerpen", + "thoroughfare": "Zaha Hadidplein 1" + }, + { + "request_id": "d000747", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Staatsbetrieb Sächsische Informatik Dienste", + "country_code": "DEU", + "nuts_code": "DED2", + "post_code": "01445", + "post_name": "Radebeul", + "thoroughfare": "Dresdner Straße 78 A" + }, + { + "request_id": "d000748", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IKK classic", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "01099", + "post_name": "Dresden", + "thoroughfare": "Tannenstraße 4 b" + }, + { + "request_id": "d000749", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bundesamt für Seeschifffahrt und Hydrographie", + "country_code": "DEU", + "nuts_code": "DE600", + "post_code": "20359", + "post_name": "Hamburg", + "thoroughfare": null + }, + { + "request_id": "d000750", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Občina Rečica ob Savinji", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "3332", + "post_name": "Rečica ob Savinji", + "thoroughfare": "Rečica ob Savinji 55" + }, + { + "request_id": "d000751", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CGI Norge AS", + "country_code": "NOR", + "nuts_code": "NO", + "post_code": "0605", + "post_name": "oslo", + "thoroughfare": "Grenseveien 86" + }, + { + "request_id": "d000752", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Interiéry Riljak, s.r.o.", + "country_code": "SVK", + "nuts_code": "SK031", + "post_code": "027 41", + "post_name": "Oravský Podzámok", + "thoroughfare": "33" + }, + { + "request_id": "d000753", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadtwerke München GmbH", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "80287", + "post_name": "München", + "thoroughfare": "Emmy-Noether-Straße 2" + }, + { + "request_id": "d000754", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vegacom a.s.", + "country_code": "CZE", + "nuts_code": "CZ01", + "post_code": "142 01", + "post_name": "Praha 4–Lhotka", + "thoroughfare": "Novodvorská 1010/14" + }, + { + "request_id": "d000755", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DISP Centre-Est Dijon", + "country_code": "FRA", + "nuts_code": "FRC11", + "post_code": "21033", + "post_name": "Dijon Cedex", + "thoroughfare": "72 A rue d'Auxonne, BP 13331" + }, + { + "request_id": "d000756", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Forsvarsministeriets Ejendomsstyrelse", + "country_code": "DNK", + "nuts_code": "DK", + "post_code": "9800", + "post_name": "Hjørring", + "thoroughfare": "Arsenalvej 55" + }, + { + "request_id": "d000757", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kur- und Touristikunternehmen der Stadt Bad Salzungen (kAöR)", + "country_code": "DEU", + "nuts_code": "DEG0P", + "post_code": "36433", + "post_name": "Bad Salzungen", + "thoroughfare": "Am Flößrasen 1" + }, + { + "request_id": "d000758", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Cobra Instalaciones y Servicios, S. A.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "28016", + "post_name": "Madrid", + "thoroughfare": "C/ Cardenal Marcelo Spinola, 10" + }, + { + "request_id": "d000759", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mida Soft Business", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "062076", + "post_name": "București", + "thoroughfare": "Str. Cetatea Histria nr. 7" + }, + { + "request_id": "d000760", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nomago, storitve mobilnosti in potovanj, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Vošnjakova ulica 3" + }, + { + "request_id": "d000761", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "G. Strauß", + "country_code": "DEU", + "nuts_code": "DE713", + "post_code": "63071", + "post_name": "Offenbach", + "thoroughfare": "Bieberer Str. 207" + }, + { + "request_id": "d000762", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Dnevnik, družba medijskih vsebin, d.d.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Kopitarjeva ulica 2" + }, + { + "request_id": "d000763", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "A G I HK spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ052", + "post_code": "500 03", + "post_name": "Hradec Králové", + "thoroughfare": "Špitálská 182/3" + }, + { + "request_id": "d000764", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Malermeister Hofmann", + "country_code": "DEU", + "nuts_code": "DED51", + "post_code": "04288", + "post_name": "Leipzig", + "thoroughfare": "Liebertwolkwitzer Straße 77" + }, + { + "request_id": "d000765", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "S.C. Andrea Forest S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "547510", + "post_name": "Saschiz", + "thoroughfare": "Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" + }, + { + "request_id": "d000766", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fis SA", + "country_code": "CHE", + "nuts_code": "CH", + "post_code": "1216", + "post_name": "Cointrin", + "thoroughfare": "Le Grand-Saconnex, route de l'Aéroport 29-31" + }, + { + "request_id": "d000767", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Prior und Preußner GmbH und Co KG", + "country_code": "DEU", + "nuts_code": "DE944", + "post_code": "49084", + "post_name": "Osnabrück", + "thoroughfare": "Dammstr. 16-20" + }, + { + "request_id": "d000768", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Univerza v Mariboru", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Slomškov trg 15" + }, + { + "request_id": "d000769", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medinova zastopstva in trgovina d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Ukmarjeva ulica 6" + }, + { + "request_id": "d000770", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Giotto water srl", + "country_code": "ITA", + "nuts_code": "ITC48", + "post_code": "27058", + "post_name": "Voghera", + "thoroughfare": "via Prati Nuovi" + }, + { + "request_id": "d000771", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Grupo Control Empresa de Seguridad, S. A.", + "country_code": "ESP", + "nuts_code": "ES611", + "post_code": "04004", + "post_name": "Almería", + "thoroughfare": "C/ Soldado Español, 12" + }, + { + "request_id": "d000772", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Subsecretaría de la Consellería de Sanidad y Salud Pública", + "country_code": "ESP", + "nuts_code": "ES523", + "post_code": "46010", + "post_name": "Valencia", + "thoroughfare": "C/ Micer Mascó, 31-33" + }, + { + "request_id": "d000773", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Communauté urbaine Le Creusot — Montceau-les-Mines", + "country_code": "FRA", + "nuts_code": "FRC13", + "post_code": "71206", + "post_name": "Le Creusot Cedex", + "thoroughfare": "château de la Verrerie, BP 90069" + }, + { + "request_id": "d000774", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Domeni d.o.o.", + "country_code": "HRV", + "nuts_code": "HR031", + "post_code": "51211", + "post_name": "Matulji", + "thoroughfare": "Frana Supila 11" + }, + { + "request_id": "d000775", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kemis kemični izdelki, predelava in odstranjevanje odpadkov d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1360", + "post_name": "Vrhnika", + "thoroughfare": "Pot na Tojnice 42" + }, + { + "request_id": "d000776", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Județean de Urgență Bacău", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bacău", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000777", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Krabu Grupp OÜ", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "11411", + "post_name": "Tallinn", + "thoroughfare": "Kivimurru tn 34" + }, + { + "request_id": "d000778", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Generali Italia SpA", + "country_code": "ITA", + "nuts_code": "ITH55", + "post_code": null, + "post_name": "Bologna", + "thoroughfare": null + }, + { + "request_id": "d000779", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Idraulica F.lli Sala", + "country_code": "ITA", + "nuts_code": "IT", + "post_code": null, + "post_name": "Concordia sulla Secchia (MO)", + "thoroughfare": null + }, + { + "request_id": "d000780", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadtwerke Eberbach (hier vertreten durch die Stadtverwaltung Eberbach)", + "country_code": "DEU", + "nuts_code": "DE715", + "post_code": "69412", + "post_name": "Eberbach", + "thoroughfare": "Stadtbauamt, Leopoldsplatz 1" + }, + { + "request_id": "d000781", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kanta-Hämeen sairaanhoitopiirin kuntayhtymä", + "country_code": "FIN", + "nuts_code": "FI1C2", + "post_code": null, + "post_name": "Hämeenlinna", + "thoroughfare": null + }, + { + "request_id": "d000782", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Weinrich Office GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000783", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Città di Lucca — Amministrazione comunale", + "country_code": "ITA", + "nuts_code": "ITI12", + "post_code": "55100", + "post_name": "Lucca", + "thoroughfare": "via Santa Giustina 6" + }, + { + "request_id": "d000784", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Västra Götalandsregionen", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "462 80", + "post_name": "Vänersborg", + "thoroughfare": "Regionens Hus" + }, + { + "request_id": "d000785", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasserverband Weddel-Lehre", + "country_code": "DEU", + "nuts_code": "DE91", + "post_code": "38162", + "post_name": "Cremlingen", + "thoroughfare": "Hauptstr. 2b" + }, + { + "request_id": "d000786", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "TRPN (Terrassement réseau publics de Normandie)", + "country_code": "FRA", + "nuts_code": "FRD2", + "post_code": "76700", + "post_name": "Gainneville", + "thoroughfare": "ZA Le Clos des Perdrix Côte des Châtaigniers" + }, + { + "request_id": "d000787", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "fesa e. V.", + "country_code": "DEU", + "nuts_code": "DE13", + "post_code": "79098", + "post_name": "Freiburg", + "thoroughfare": "Gerberau 5a" + }, + { + "request_id": "d000788", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Senn AG", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "4665", + "post_name": "Oftringen", + "thoroughfare": "Bernstraße 9" + }, + { + "request_id": "d000789", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kristiansand Kommune", + "country_code": "NOR", + "nuts_code": "NO", + "post_code": "4685", + "post_name": "Nodeland", + "thoroughfare": "Postboks 4" + }, + { + "request_id": "d000790", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "E 3, Energetika, ekologija, ekonomija, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "5000", + "post_name": "Nova Gorica", + "thoroughfare": "Erjavčeva ulica 24" + }, + { + "request_id": "d000791", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bundesagentur für Arbeit Regionales Einkaufszentrum Südwest", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "60528", + "post_name": "Frankfurt am Main", + "thoroughfare": "Saonestr. 2-4" + }, + { + "request_id": "d000792", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vodafone România", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "020276", + "post_name": "București", + "thoroughfare": "Str. Barbu Văcărescu nr. 201" + }, + { + "request_id": "d000793", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Communauté d'agglomération du Soissonnais", + "country_code": "FRA", + "nuts_code": "FRE21", + "post_code": "02880", + "post_name": "Cuffies", + "thoroughfare": "Les Terrasses du Mail, 11 avenue François Mitterrand, 0288" + }, + { + "request_id": "d000794", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Commune Meaux", + "country_code": "FRA", + "nuts_code": "FR102", + "post_code": "77107", + "post_name": "Meaux Cedex", + "thoroughfare": "place de l'Hôtel de Ville Jacques Chirac — BP 227" + }, + { + "request_id": "d000795", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ministrstvo za okolje in prostor Direkcija Republike Slovenije za vode", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Hajdrihova ulica 28C" + }, + { + "request_id": "d000796", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Total direct énergie SA", + "country_code": "FRA", + "nuts_code": "FRL", + "post_code": "75015", + "post_name": "Paris", + "thoroughfare": "2 bis rue Louis Armand" + }, + { + "request_id": "d000797", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Notes CS, a.s.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "149 00", + "post_name": "Praha", + "thoroughfare": "Türkova 2319 5b" + }, + { + "request_id": "d000798", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AEA Architectes", + "country_code": "FRA", + "nuts_code": "FRF11", + "post_code": "67000", + "post_name": "Strasbourg", + "thoroughfare": "3a rue du 22 Novembre" + }, + { + "request_id": "d000799", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Achats du groupe biens de consommation", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "3000", + "post_name": "Berne 65", + "thoroughfare": "Hilfikerstr. 3" + }, + { + "request_id": "d000800", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Samifra", + "country_code": "FRA", + "nuts_code": "FRC12", + "post_code": "58641", + "post_name": "Varennes-Vauzelles", + "thoroughfare": "le Bengy" + }, + { + "request_id": "d000801", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AMO 2T", + "country_code": "FRA", + "nuts_code": "FRE23", + "post_code": "80440", + "post_name": "Boves", + "thoroughfare": "8 rue Alphonse Tellier" + }, + { + "request_id": "d000802", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Grupa Azoty Zakłady Chemiczne Police S.A.", + "country_code": "POL", + "nuts_code": "PL42", + "post_code": "72-010", + "post_name": "Police", + "thoroughfare": "ul. Kuźnicka 1" + }, + { + "request_id": "d000803", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Valeor", + "country_code": "FRA", + "nuts_code": "FRL05", + "post_code": "83300", + "post_name": "Draguignan", + "thoroughfare": "109 rue Jean Aicard" + }, + { + "request_id": "d000804", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Elektro Esser", + "country_code": "DEU", + "nuts_code": "DEG0B", + "post_code": "98617", + "post_name": "Utendorf", + "thoroughfare": "Metzelser Weg 116" + }, + { + "request_id": "d000805", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Surovina, družba za predelavo odpadkov d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Ulica Vita Kraigherja 5" + }, + { + "request_id": "d000806", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hebyfastigheter AB", + "country_code": "SWE", + "nuts_code": "SE121", + "post_code": "744 21", + "post_name": "Heby", + "thoroughfare": "Box 29" + }, + { + "request_id": "d000807", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Leonor Neto Lopes", + "country_code": "PRT", + "nuts_code": "PT170", + "post_code": null, + "post_name": "Lisboa", + "thoroughfare": null + }, + { + "request_id": "d000808", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Martín Casillas, S. L. U.", + "country_code": "ESP", + "nuts_code": "ES618", + "post_code": null, + "post_name": "Sevilla", + "thoroughfare": null + }, + { + "request_id": "d000809", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Phœnix pharma", + "country_code": "FRA", + "nuts_code": "FR1", + "post_code": null, + "post_name": "Créteil", + "thoroughfare": null + }, + { + "request_id": "d000810", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "RAG Rohrleitungs- und Anlagenbau GmbH", + "country_code": "DEU", + "nuts_code": "DE949", + "post_code": "49716", + "post_name": "Meppen", + "thoroughfare": "Backemuder Str. 16" + }, + { + "request_id": "d000811", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Renault Retail Group Courbevoie", + "country_code": "FRA", + "nuts_code": "FR105", + "post_code": "92400", + "post_name": "Courbevoie", + "thoroughfare": "8 boulevard Georges-Clémenceau" + }, + { + "request_id": "d000812", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Esclapes e Hijos, S. L.", + "country_code": "ESP", + "nuts_code": "ES521", + "post_code": "03007", + "post_name": "Alicante", + "thoroughfare": "Avenida Saturno, s/n" + }, + { + "request_id": "d000813", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "BewGe AVS / Helaba / transact", + "country_code": "DEU", + "nuts_code": "DE24", + "post_code": "95444", + "post_name": "Bayreuth", + "thoroughfare": "Josephsplatz 8 (c/o AVS GmbH)" + }, + { + "request_id": "d000814", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Winkels Servicegesellschaft mbH", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": null, + "post_name": "Berlin", + "thoroughfare": null + }, + { + "request_id": "d000815", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UTE Otipsa Consultores, S. L. — Viasur, Prevención e Ingeniería, S. A.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "04004", + "post_name": "Almería", + "thoroughfare": "Rambla Obispo Orberá" + }, + { + "request_id": "d000816", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ayesa Advanced Technologies, S. A., Alfatec Sistemas, S. L., Unión Temporal de Empresas, Ley 18/1982, de 26 de mayo", + "country_code": "ESP", + "nuts_code": "ES62", + "post_code": null, + "post_name": "Murcia", + "thoroughfare": null + }, + { + "request_id": "d000817", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "MOOVE GmbH", + "country_code": "DEU", + "nuts_code": "DEA23", + "post_code": "50999", + "post_name": "Köln", + "thoroughfare": "Industriestraße 161 — Haus 6" + }, + { + "request_id": "d000818", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tressol", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "34500", + "post_name": "Béziers", + "thoroughfare": "ZAC de Montimaran" + }, + { + "request_id": "d000819", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Asseco Lietuva“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": null, + "post_name": "Vilnius", + "thoroughfare": null + }, + { + "request_id": "d000820", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Entsorgungsbetriebe Essen GmbH", + "country_code": "DEU", + "nuts_code": "DEA13", + "post_code": "45141", + "post_name": "Essen", + "thoroughfare": "Pferdebahnstraße 32" + }, + { + "request_id": "d000821", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Matra S.R.L.", + "country_code": "ROU", + "nuts_code": "RO414", + "post_code": "235600", + "post_name": "Scornicești", + "thoroughfare": "Bulevardul Muncii nr. 11" + }, + { + "request_id": "d000822", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vojenské lesy a statky ČR, s.p.", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "160 00", + "post_name": "Praha 6", + "thoroughfare": "Pod Juliskou 1621/5, Dejvice" + }, + { + "request_id": "d000823", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "RATP", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75599", + "post_name": "Paris Cedex 12", + "thoroughfare": "Lac B916, 54 quai de la Rapée" + }, + { + "request_id": "d000824", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeente Capelle aan den IJssel", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Capelle aan den IJssel", + "thoroughfare": null + }, + { + "request_id": "d000825", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lindbak AS", + "country_code": "NOR", + "nuts_code": "NO082", + "post_code": "7038", + "post_name": "Trondheim", + "thoroughfare": "Nordslettvegen 1" + }, + { + "request_id": "d000826", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "S.C. ELMED S.R.L.", + "country_code": "ROU", + "nuts_code": "RO114", + "post_code": "430111", + "post_name": "Baia Mare", + "thoroughfare": "Strada Slavici Ion, Nr. 3" + }, + { + "request_id": "d000827", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Costacos Com S.R.L.", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500108", + "post_name": "Brașov", + "thoroughfare": "Str. Valea Tei nr. 31A" + }, + { + "request_id": "d000828", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "G Travel Østfold", + "country_code": "NOR", + "nuts_code": "NO074", + "post_code": "1504", + "post_name": "Moss", + "thoroughfare": "Pb 802" + }, + { + "request_id": "d000829", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CHU de Montpellier", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "34295", + "post_name": "Montpellier Cedex 5", + "thoroughfare": "191 avenue du Doyen-Gaston-Giraud" + }, + { + "request_id": "d000830", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "B&W Bautenschutz", + "country_code": "DEU", + "nuts_code": "DEA37", + "post_code": "48431", + "post_name": "Rheine", + "thoroughfare": "Windhorststr. 2B" + }, + { + "request_id": "d000831", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Costacos Com S.R.L.", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500108", + "post_name": "Brașov", + "thoroughfare": "Str. Valea Tei nr. 31A" + }, + { + "request_id": "d000832", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Service départemental métropolitain d'incendie de secours", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69421", + "post_name": "Lyon Cedex 03", + "thoroughfare": "17 rue Rabelais" + }, + { + "request_id": "d000833", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "hectas Facility Services Stiftung & Co. KG", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": null, + "post_name": "Berlin", + "thoroughfare": null + }, + { + "request_id": "d000834", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Statutární město Brno, městská část Brno–Líšeň", + "country_code": "CZE", + "nuts_code": "CZ064", + "post_code": "628 00", + "post_name": "Brno", + "thoroughfare": "Jírova 2" + }, + { + "request_id": "d000835", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "OPCO atlas", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75013", + "post_name": "Paris", + "thoroughfare": "25 quai Panhard et Levassor" + }, + { + "request_id": "d000836", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wirtschaftsbetriebe Duisburg AöR", + "country_code": "DEU", + "nuts_code": "DEA12", + "post_code": "47059", + "post_name": "Duisburg", + "thoroughfare": "Schifferstr. 190" + }, + { + "request_id": "d000837", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fakultní nemocnice Plzeň", + "country_code": "CZE", + "nuts_code": "CZ032", + "post_code": "305 99", + "post_name": "Plzeň", + "thoroughfare": "Edvarda Beneše 1128/13" + }, + { + "request_id": "d000838", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ITMA, S. L. U.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": "33428", + "post_name": "Llanera", + "thoroughfare": "C/ B, parcela 60, nave 5, polígono Asipo" + }, + { + "request_id": "d000839", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Scottish Water", + "country_code": "GBR", + "nuts_code": "UKM", + "post_code": "G33 6FB", + "post_name": "Glasgow", + "thoroughfare": "6 Buchanan Gate" + }, + { + "request_id": "d000840", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ville de Nantes", + "country_code": "FRA", + "nuts_code": "FRG01", + "post_code": null, + "post_name": "Nantes", + "thoroughfare": null + }, + { + "request_id": "d000841", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IKK classic.de", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "01099", + "post_name": "Dresden", + "thoroughfare": null + }, + { + "request_id": "d000842", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB „Goodpoint“", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-46326", + "post_name": "Kaunas", + "thoroughfare": "Saulėgrąžų g. 26" + }, + { + "request_id": "d000843", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stockholm Innovation & Growth AB", + "country_code": "SWE", + "nuts_code": "SE110", + "post_code": null, + "post_name": "Stockholm", + "thoroughfare": null + }, + { + "request_id": "d000844", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Mönchengladbach, Dezernat Planen, Bauen, Mobilität, Umwelt - VI/V - Vergabestelle -", + "country_code": "DEU", + "nuts_code": "DEA15", + "post_code": "41236", + "post_name": "Mönchengladbach", + "thoroughfare": "Markt 11" + }, + { + "request_id": "d000845", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Municipal Câmpulung Muscel", + "country_code": "ROU", + "nuts_code": "RO311", + "post_code": "115100", + "post_name": "Câmpulung", + "thoroughfare": "Str. Dr. Costea nr. 8" + }, + { + "request_id": "d000846", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Absobo studio SAS", + "country_code": "FRA", + "nuts_code": "FRI12", + "post_code": "33074", + "post_name": "Bordeaux", + "thoroughfare": "23 parvis des Chartrons" + }, + { + "request_id": "d000847", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Aktsiaselts Pinus", + "country_code": "EST", + "nuts_code": "EE", + "post_code": "10618", + "post_name": "Tallinn", + "thoroughfare": "Paldiski mnt 107" + }, + { + "request_id": "d000848", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medika d.d.", + "country_code": "HRV", + "nuts_code": "HR050", + "post_code": "10000", + "post_name": "Zagreb", + "thoroughfare": "Capraška 1" + }, + { + "request_id": "d000849", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Brandenburgischer Landesbetrieb für Liegenschaften und Bauen (BLB) — Zentrale Vergabestelle", + "country_code": "DEU", + "nuts_code": "DE40H", + "post_code": "15806", + "post_name": "Zossen", + "thoroughfare": "An der Wache 2" + }, + { + "request_id": "d000850", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Cetim", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "60304", + "post_name": "Senlis Cedex", + "thoroughfare": "52 avenue Félix Louat, BP 80067" + }, + { + "request_id": "d000851", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Krakowski Szpital Specjalistyczny im. Jana Pawła II", + "country_code": "POL", + "nuts_code": "PL213", + "post_code": "31-202", + "post_name": "Kraków", + "thoroughfare": "ul. Prądnicka 80" + }, + { + "request_id": "d000852", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ISL ingénierie", + "country_code": "FRA", + "nuts_code": "FRJ13", + "post_code": "34170", + "post_name": "Castelnau-le-Lez", + "thoroughfare": "65 avenue Clément Ader" + }, + { + "request_id": "d000853", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Klinikum Hochsauerland GmbH", + "country_code": "DEU", + "nuts_code": "DEA57", + "post_code": "59755", + "post_name": "Arnsberg", + "thoroughfare": "Goethestraße 15, 59755 Arnsberg" + }, + { + "request_id": "d000854", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Verdo Teknik A/S", + "country_code": "DNK", + "nuts_code": "DK032", + "post_code": "25481992", + "post_name": "Randers NV", + "thoroughfare": "Agerskellet 7" + }, + { + "request_id": "d000855", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "NFP Nemzeti Fejlesztési Programiroda Nonprofit Korlátolt Felelősségű Társaság", + "country_code": "HUN", + "nuts_code": "HU", + "post_code": "1139", + "post_name": "Budapest", + "thoroughfare": "Pap Károly utca 4–6." + }, + { + "request_id": "d000856", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bio Technic România S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "060015", + "post_name": "București", + "thoroughfare": "Str. Plevnei nr. 196, sector 6" + }, + { + "request_id": "d000857", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Miasto Bielsko-Biała Urząd Miejski w Bielsku-Białej", + "country_code": "POL", + "nuts_code": "PL225", + "post_code": "43-300", + "post_name": "Bielsko-Biała", + "thoroughfare": "pl. Ratuszowy 9" + }, + { + "request_id": "d000858", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AEP Estrich GmbH", + "country_code": "DEU", + "nuts_code": "DE1", + "post_code": "74369", + "post_name": "Löchgau", + "thoroughfare": "Friederike-Franck-Straße 12" + }, + { + "request_id": "d000859", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbrăveni", + "thoroughfare": "Str. Gării nr. 3" + }, + { + "request_id": "d000860", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Enel Italia SpA in nome e per conto di e-distribuzione SpA", + "country_code": "ITA", + "nuts_code": "ITI43", + "post_code": "00198", + "post_name": "Roma (RM)", + "thoroughfare": "viale Regina Margherita 125" + }, + { + "request_id": "d000861", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "OMV Petrom Marketing", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "013329", + "post_name": "București", + "thoroughfare": "Str. Coralilor nr. 22, sector 1" + }, + { + "request_id": "d000862", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Conduent Business Solutions AG", + "country_code": "CHE", + "nuts_code": "CH", + "post_code": null, + "post_name": "Bern", + "thoroughfare": null + }, + { + "request_id": "d000863", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Občina Mozirje", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "3330", + "post_name": "Mozirje", + "thoroughfare": "Šmihelska cesta 2" + }, + { + "request_id": "d000864", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Axis Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO423", + "post_code": "330004", + "post_name": "Deva", + "thoroughfare": "Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" + }, + { + "request_id": "d000865", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Sodexo AB", + "country_code": "SWE", + "nuts_code": "SE", + "post_code": "169 03", + "post_name": "Solna", + "thoroughfare": "Dalvägen 22" + }, + { + "request_id": "d000866", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vestra Industry S.R.L.", + "country_code": "ROU", + "nuts_code": "RO212", + "post_code": null, + "post_name": "Cătămărești-Deal", + "thoroughfare": "Str. Mihai Eminescu nr. 85" + }, + { + "request_id": "d000867", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bilbao Exhibition Centre, S. A.", + "country_code": "ESP", + "nuts_code": "ES213", + "post_code": null, + "post_name": "Bilbao", + "thoroughfare": null + }, + { + "request_id": "d000868", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "GEAPRODUKT trgovsko podjetje na debelo in drobno d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Dolenjska cesta 242" + }, + { + "request_id": "d000869", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Domanys", + "country_code": "FRA", + "nuts_code": "FRC14", + "post_code": "89000", + "post_name": "Auxerre", + "thoroughfare": "9 rue de Douaumont" + }, + { + "request_id": "d000870", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Energotech S.A.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "061334", + "post_name": "București", + "thoroughfare": "Str. Timișoara nr. 104 B, sector 6" + }, + { + "request_id": "d000871", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ACOLAV, podjetje za storitve, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1241", + "post_name": "Kamnik", + "thoroughfare": "Prešernova ulica 4" + }, + { + "request_id": "d000872", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Atelier du Val de Sambre", + "country_code": "FRA", + "nuts_code": "FRE11", + "post_code": "59600", + "post_name": "Maubeuge", + "thoroughfare": "251 rue du Pont de Pierres" + }, + { + "request_id": "d000873", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kemijski inštitut", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Hajdrihova ulica 19" + }, + { + "request_id": "d000874", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Slovak Telekom, a.s.", + "country_code": "SVK", + "nuts_code": "SK01", + "post_code": "817 62", + "post_name": "Bratislava", + "thoroughfare": "Bajkalská 28" + }, + { + "request_id": "d000875", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "BTL ROMANIA APARATURA MEDICALA S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "040184", + "post_name": "Bucuresti", + "thoroughfare": "Strada CPT MIRCEA VASILESCU, Nr. 12-14, Sector: 4" + }, + { + "request_id": "d000876", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Drum Asfalt", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": "410270", + "post_name": "Oradea", + "thoroughfare": "Șoseaua Borșului nr. 14/A" + }, + { + "request_id": "d000877", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Baby Business S.R.L.", + "country_code": "ROU", + "nuts_code": "RO124", + "post_code": "535600", + "post_name": "Odorheiu Secuiesc", + "thoroughfare": "Str. Budcar nr. 58" + }, + { + "request_id": "d000878", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "VĮ Lietuvos automobilių kelių direkcija", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03109", + "post_name": "Vilnius", + "thoroughfare": "J. Basanavičiaus g. 36" + }, + { + "request_id": "d000879", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nohl Eisennach GmbH", + "country_code": "DEU", + "nuts_code": "DEG0N", + "post_code": "99817", + "post_name": "Eisenach", + "thoroughfare": "An der Feuerwache 4" + }, + { + "request_id": "d000880", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AKR1, s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ01", + "post_code": "140 00", + "post_name": "Praha 4 - Nusle", + "thoroughfare": "Svatoslavova 589/9" + }, + { + "request_id": "d000881", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Valstybės sienos apsaugos tarnyba prie Lietuvos Respublikos vidaus reikalų ministerijos", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03116", + "post_name": "Vilnius", + "thoroughfare": "Savanorių pr. 2" + }, + { + "request_id": "d000882", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Greenfish", + "country_code": "BEL", + "nuts_code": "BE100", + "post_code": "1050", + "post_name": "Ixelles", + "thoroughfare": "Avenue Louise 279" + }, + { + "request_id": "d000883", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SEMAB", + "country_code": "FRA", + "nuts_code": "FRI11", + "post_code": null, + "post_name": "Bergerac", + "thoroughfare": null + }, + { + "request_id": "d000884", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Anmedic, družba za trgovino s profesionalno medicinsko opremo in pripomočki, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Šmartinska cesta 53" + }, + { + "request_id": "d000885", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "GE Healthcare", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "78457", + "post_name": "Vélizy Cedex", + "thoroughfare": "24 avenue de l'Europe" + }, + { + "request_id": "d000886", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Mönchengladbach, Dezernat Planen, Bauen, Mobilität, Umwelt – VI/V – Vergabestelle", + "country_code": "DEU", + "nuts_code": "DEA15", + "post_code": "41236", + "post_name": "Mönchengladbach", + "thoroughfare": "Markt 11" + }, + { + "request_id": "d000887", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "WSA Weser- Jade- Nordsee; Technische Fachstelle Nordawest", + "country_code": "DEU", + "nuts_code": "DE94G", + "post_code": "26919", + "post_name": "Brake", + "thoroughfare": "Hinrich-Schnitger- Straße 20" + }, + { + "request_id": "d000888", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Rupert App GmbH & Co.", + "country_code": "DEU", + "nuts_code": "DE148", + "post_code": "88299", + "post_name": "Leutkirch", + "thoroughfare": "Unterzeiler Weg 3" + }, + { + "request_id": "d000889", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Deutsches Zentrum für Luft- und Raumfahrt e. V. (DLR)", + "country_code": "DEU", + "nuts_code": "DEA23", + "post_code": "51147", + "post_name": "Köln", + "thoroughfare": "Linder Höhe" + }, + { + "request_id": "d000890", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "kreuger wilkins architekten gbr", + "country_code": "DEU", + "nuts_code": "DE111", + "post_code": null, + "post_name": "Stuttgart", + "thoroughfare": null + }, + { + "request_id": "d000891", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CAE STS LTD", + "country_code": "GBR", + "nuts_code": "UKJ28", + "post_code": null, + "post_name": "Burgess Hill", + "thoroughfare": null + }, + { + "request_id": "d000892", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "(Uczestnik) Tramco Spółka z o.o. Wolskie", + "country_code": "POL", + "nuts_code": "PL", + "post_code": "05-860", + "post_name": "Płochocin", + "thoroughfare": "ul. Wolska 14" + }, + { + "request_id": "d000893", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mollier, inženiring, storitve, proizvodnja, trgovina d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "3000", + "post_name": "Celje", + "thoroughfare": "Opekarniška cesta 3" + }, + { + "request_id": "d000894", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Chambre de Métiers et de l'Artisanat des Hauts-de-France", + "country_code": "FRA", + "nuts_code": "FRE", + "post_code": "59011", + "post_name": "Lille Cedex", + "thoroughfare": "place des Artisans — CS 12010" + }, + { + "request_id": "d000895", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Intersurgical España, S. L.", + "country_code": "ESP", + "nuts_code": "ES30", + "post_code": null, + "post_name": "Móstoles", + "thoroughfare": null + }, + { + "request_id": "d000896", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kristiansand kommune", + "country_code": "NOR", + "nuts_code": "NO", + "post_code": "4685", + "post_name": "Nodeland", + "thoroughfare": "Postboks 4" + }, + { + "request_id": "d000897", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Anticimex Aktiebolag", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "100 74", + "post_name": "Stockholm", + "thoroughfare": "Box 47025" + }, + { + "request_id": "d000898", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Derichebourg SNG Mandataire", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69310", + "post_name": "Pierre-Benite", + "thoroughfare": "84 boulevard de l'Europe" + }, + { + "request_id": "d000899", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Axis Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO423", + "post_code": "330004", + "post_name": "Deva", + "thoroughfare": "Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" + }, + { + "request_id": "d000900", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "KLS spol. s.r.o.", + "country_code": "SVK", + "nuts_code": "SK031", + "post_code": "010 01", + "post_name": "Žilina", + "thoroughfare": "Martina Rázusa 9" + }, + { + "request_id": "d000901", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ČEZ Distribuce, a.s.", + "country_code": "CZE", + "nuts_code": "CZ042", + "post_code": null, + "post_name": "Děčín IV-Podmokly", + "thoroughfare": null + }, + { + "request_id": "d000902", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "RER VEST", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": "410270", + "post_name": "Oradea", + "thoroughfare": "Strada Vladimirescu Tudor, Nr. 79" + }, + { + "request_id": "d000903", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IFOK GmbH", + "country_code": "DEU", + "nuts_code": "DE715", + "post_code": "64625", + "post_name": "Bensheim", + "thoroughfare": "Berliner Ring 89" + }, + { + "request_id": "d000904", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CC Pharma GmbH", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": null, + "post_name": "Densborn", + "thoroughfare": null + }, + { + "request_id": "d000905", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vygon, S. A. U.", + "country_code": "ESP", + "nuts_code": "ES523", + "post_code": null, + "post_name": "Paterna", + "thoroughfare": null + }, + { + "request_id": "d000906", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Verovškova ulica 70" + }, + { + "request_id": "d000907", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadtverwaltung Balingen", + "country_code": "DEU", + "nuts_code": "DE143", + "post_code": "72336", + "post_name": "Balingen", + "thoroughfare": "Neue Straße 31" + }, + { + "request_id": "d000908", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "VšĮ Klaipėdos universitetinė ligoninė", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-92288", + "post_name": "Klaipėda", + "thoroughfare": "Liepojos g. 41" + }, + { + "request_id": "d000909", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FOCUS TRADING '94 S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "011657", + "post_name": "Bucuresti", + "thoroughfare": "Strada Tudor Stefan, Nr. 10, Sector: 1" + }, + { + "request_id": "d000910", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ríkiskaup", + "country_code": "ISL", + "nuts_code": "IS", + "post_code": "IS-105", + "post_name": "Reykjavik", + "thoroughfare": "Borgartun 7c" + }, + { + "request_id": "d000911", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Energimyndigheten", + "country_code": "SWE", + "nuts_code": "SE122", + "post_code": "631 04", + "post_name": "Eskilstuna", + "thoroughfare": "Box 310" + }, + { + "request_id": "d000912", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Inspectoratul General al Poliţiei Române", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "050041", + "post_name": "Bucureşti", + "thoroughfare": "Str. Mihai Vodă nr. 6" + }, + { + "request_id": "d000913", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Marinko Zubčić- pripremni radovi na gradilištu", + "country_code": "HRV", + "nuts_code": "HR", + "post_code": "23241", + "post_name": "Poličnik", + "thoroughfare": "Murvica IK 7a" + }, + { + "request_id": "d000914", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Univerzitetni klinični center Maribor", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Ljubljanska ulica 5" + }, + { + "request_id": "d000915", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Roudenn Grafik", + "country_code": "FRA", + "nuts_code": "FRH01", + "post_code": "22194", + "post_name": "Plérin", + "thoroughfare": null + }, + { + "request_id": "d000916", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Consejería de Desarrollo Autonómico", + "country_code": "ESP", + "nuts_code": "ES230", + "post_code": "26071", + "post_name": "Logroño", + "thoroughfare": "Avenida Zaragoza, 21" + }, + { + "request_id": "d000917", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Engie", + "country_code": "FRA", + "nuts_code": "FRK26", + "post_code": "69246", + "post_name": "Lyon", + "thoroughfare": "127 avenue Barthélémy Buyer" + }, + { + "request_id": "d000918", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ExperTeach Gesellschaft für Netzwerkkompetenz mbH", + "country_code": "DEU", + "nuts_code": "DE71C", + "post_code": "63128", + "post_name": "Dietzenbach", + "thoroughfare": "Waldstraße 94" + }, + { + "request_id": "d000919", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "PLG Paris Île-de-France", + "country_code": "FRA", + "nuts_code": "FR103", + "post_code": "95140", + "post_name": "Garges-lès-Gonesse", + "thoroughfare": "29 avenue des Morillons" + }, + { + "request_id": "d000920", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "HTM", + "country_code": "FRA", + "nuts_code": "FRI15", + "post_code": "64210", + "post_name": "Bidart", + "thoroughfare": "56 allée Antoine d'Abbadie Bâtiment Enerpole" + }, + { + "request_id": "d000921", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fresenius Kabi Polska Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL", + "post_code": "02-305", + "post_name": "Warszawa", + "thoroughfare": "Al. Jerozolimskie 134" + }, + { + "request_id": "d000922", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mundiaudit, S. L.", + "country_code": "ESP", + "nuts_code": "ES", + "post_code": null, + "post_name": "Las Palmas de Gran Canaria", + "thoroughfare": "C/ Goya, 7" + }, + { + "request_id": "d000923", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Land Schleswig-Holstein endvertreten durch Gebäudemanagement Schleswig-Holstein AöR", + "country_code": "DEU", + "nuts_code": "DEF03", + "post_code": "23566", + "post_name": "Lübeck", + "thoroughfare": "Schillstraße 1-3" + }, + { + "request_id": "d000924", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "blankService Torsten Werner", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": "13088", + "post_name": "Berlin", + "thoroughfare": "Meyerbeerstraße 58" + }, + { + "request_id": "d000925", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ARGE Kutter Hts Bauunternehmung GmbH/Ludwig Pfeiffer Hoch- und Tiefbau GmbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DEE0A", + "post_code": "06311", + "post_name": "Helbra", + "thoroughfare": null + }, + { + "request_id": "d000926", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "MOGA družba za urejanje okolja d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Zemljičeva ulica 21" + }, + { + "request_id": "d000927", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Quadrat Études", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75012", + "post_name": "Paris", + "thoroughfare": "45 rue de Lyon" + }, + { + "request_id": "d000928", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000929", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spirale Print", + "country_code": "FRA", + "nuts_code": "FR101", + "post_code": "75017", + "post_name": "Paris", + "thoroughfare": "2-4 rue Baye" + }, + { + "request_id": "d000930", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Inspyr énergies environnement", + "country_code": "FRA", + "nuts_code": "FRI15", + "post_code": "64000", + "post_name": "Pau", + "thoroughfare": "2 avenue Pierre Angot" + }, + { + "request_id": "d000931", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tinmar Energy S.A.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "014476", + "post_name": "București", + "thoroughfare": "Str. Floreasca nr. 246C" + }, + { + "request_id": "d000932", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ministry for the Environment Climate Change and Planning — MPU", + "country_code": "MLT", + "nuts_code": "MT", + "post_code": "SVR 1301", + "post_name": "Santa Venera", + "thoroughfare": "Permanent Secretariat Offices, 6 Qormi Road" + }, + { + "request_id": "d000933", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Žale Javno podjetje, d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Med hmeljniki 2" + }, + { + "request_id": "d000934", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Banskobystrický samosprávny kraj", + "country_code": "SVK", + "nuts_code": "SK032", + "post_code": "974 01", + "post_name": "Banská Bystrica", + "thoroughfare": "Nám. SNP 23" + }, + { + "request_id": "d000935", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Aema Hispánica, S. L.", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": "28036", + "post_name": "Madrid", + "thoroughfare": "C/ Santiago Bernabéu, 4, 4" + }, + { + "request_id": "d000936", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ANDYTEH CONCEPT S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "031126", + "post_name": "Bucuresti", + "thoroughfare": "Strada Negoiu, Nr. 6" + }, + { + "request_id": "d000937", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Univerzitetni klinični center Maribor", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2000", + "post_name": "Maribor", + "thoroughfare": "Ljubljanska ulica 5" + }, + { + "request_id": "d000938", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landkreis München, vertreten durch die Münchner Verkehrs- und Tarifverbund GmbH", + "country_code": "DEU", + "nuts_code": "DE21H", + "post_code": "80538", + "post_name": "München", + "thoroughfare": "Thierschstr. 2" + }, + { + "request_id": "d000939", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Icartare, S. L.", + "country_code": "ESP", + "nuts_code": "ES618", + "post_code": null, + "post_name": "Sevilla", + "thoroughfare": null + }, + { + "request_id": "d000940", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Arthrex Adria d.o.o.", + "country_code": "HRV", + "nuts_code": "HR", + "post_code": "10000", + "post_name": "Zagreb", + "thoroughfare": "Ulica grada Vukovara 269 G" + }, + { + "request_id": "d000941", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Zaloker & Zaloker trgovinska in proizvodna d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Kajuhova ulica 9" + }, + { + "request_id": "d000942", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Krankenhaus Düren gGmbH", + "country_code": "DEU", + "nuts_code": "DEA26", + "post_code": "52351", + "post_name": "Düren", + "thoroughfare": "Roonstraße 30" + }, + { + "request_id": "d000943", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadtwerke Eberbach (hier vertreten durch die Stadtverwaltung Eberbach)", + "country_code": "DEU", + "nuts_code": "DE715", + "post_code": "69412", + "post_name": "Eberbach", + "thoroughfare": "Stadtbauamt, Leopoldsplatz 1" + }, + { + "request_id": "d000944", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bock GmbH", + "country_code": "DEU", + "nuts_code": "DEG0F", + "post_code": null, + "post_name": "Ilmenau", + "thoroughfare": null + }, + { + "request_id": "d000945", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Xanadu, s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ01", + "post_code": "106 00", + "post_name": "Záběhlice Praha 10", + "thoroughfare": "Žirovnická 2389/1a" + }, + { + "request_id": "d000946", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AMJ Turku Audio Oy", + "country_code": "FIN", + "nuts_code": "FI1C1", + "post_code": null, + "post_name": "Lieto", + "thoroughfare": null + }, + { + "request_id": "d000947", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vrtec Ptuj", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "2250", + "post_name": "Ptuj", + "thoroughfare": "Puhova ulica 6" + }, + { + "request_id": "d000948", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Markt Berchtesgaden", + "country_code": "DEU", + "nuts_code": "DE215", + "post_code": "83471", + "post_name": "Berchtesgaden", + "thoroughfare": "Rathausplatz 1" + }, + { + "request_id": "d000949", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Miasto Stołeczne Warszawa Dzielnica Mokotów", + "country_code": "POL", + "nuts_code": "PL911", + "post_code": "02-517", + "post_name": "Warszawa", + "thoroughfare": "ul. Rakowiecka 25/27" + }, + { + "request_id": "d000950", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Bauelemente Herbst GmbH", + "country_code": "DEU", + "nuts_code": "DE7", + "post_code": "63628", + "post_name": "Bad Soden Salmünster", + "thoroughfare": "Am Palmusacker 2" + }, + { + "request_id": "d000951", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "BCH Compresseurs", + "country_code": "FRA", + "nuts_code": "FRK27", + "post_code": "73800", + "post_name": "Porte-de-Savoie", + "thoroughfare": "422 rue de la Jacquère" + }, + { + "request_id": "d000952", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Weatherford Atlas GIP S.A.", + "country_code": "ROU", + "nuts_code": "RO", + "post_code": "100189", + "post_name": "Ploiești", + "thoroughfare": "Str. Clopoței nr. 2A" + }, + { + "request_id": "d000953", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SANTIS Training AG", + "country_code": "CHE", + "nuts_code": "CH0", + "post_code": "8048", + "post_name": "Zürich", + "thoroughfare": "Hohlstrasse 550" + }, + { + "request_id": "d000954", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SWCO Polska Sp. z o.o.", + "country_code": "POL", + "nuts_code": "PL415", + "post_code": "60-829", + "post_name": "Poznań", + "thoroughfare": "ul. Franklina Roosevelta 22" + }, + { + "request_id": "d000955", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Clinic de Boli Infecțioase și Pneumoftiziologie „Dr. Victor Babeș” Timișoara", + "country_code": "ROU", + "nuts_code": "RO424", + "post_code": "300310", + "post_name": "Timișoara", + "thoroughfare": "Str. Adam Gheorghe nr. 13" + }, + { + "request_id": "d000956", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Fraunhofer-Gesellschaft, Einkauf und Gerätewirtschaft C2", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "80686", + "post_name": "München", + "thoroughfare": "Hansastraße 28" + }, + { + "request_id": "d000957", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Codema International GmbH", + "country_code": "DEU", + "nuts_code": "DE713", + "post_code": "63065", + "post_name": "Offenbach am Main", + "thoroughfare": "Frankfurter Straße 1" + }, + { + "request_id": "d000958", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Confeções São Gregório, Lda.", + "country_code": "PRT", + "nuts_code": "PT111", + "post_code": null, + "post_name": "Cristelo (Pias)", + "thoroughfare": "Monção" + }, + { + "request_id": "d000959", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Monitorización y Medidas, S. L.", + "country_code": "ESP", + "nuts_code": "ES300", + "post_code": "28223", + "post_name": "Pozuelo de Alarcón", + "thoroughfare": "C/ Virgilio, 25" + }, + { + "request_id": "d000960", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Duktus (Wetzlar) GmbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DE722", + "post_code": "35576", + "post_name": "Wetzlar", + "thoroughfare": "Sophienstraße 52-54" + }, + { + "request_id": "d000961", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Atelier 5", + "country_code": "FRA", + "nuts_code": "FRL01", + "post_code": "83000", + "post_name": "Toulon", + "thoroughfare": "5 rue Gozza" + }, + { + "request_id": "d000962", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Alenium consultants", + "country_code": "FRA", + "nuts_code": "FR1", + "post_code": null, + "post_name": "Paris", + "thoroughfare": null + }, + { + "request_id": "d000963", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Timed, s.r.o.", + "country_code": "SVK", + "nuts_code": "SK01", + "post_code": "821 01", + "post_name": "Bratislava", + "thoroughfare": "Trnavská cesta 112" + }, + { + "request_id": "d000964", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tuomi Logistiikka Oy", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-33840", + "post_name": "Tampere", + "thoroughfare": "Särkijärvenkatu 1" + }, + { + "request_id": "d000965", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Maandag Interim Professionals bv", + "country_code": "NLD", + "nuts_code": "NL", + "post_code": null, + "post_name": "Rotterdam", + "thoroughfare": null + }, + { + "request_id": "d000966", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Neumarkt in der Oberpfalz", + "country_code": "DEU", + "nuts_code": "DE236", + "post_code": "92318", + "post_name": "Neumarkt in der Oberpfalz", + "thoroughfare": "Rathausplatz 1" + }, + { + "request_id": "d000967", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Anton Gerl GmbH", + "country_code": "DEU", + "nuts_code": "DEA2", + "post_code": "50996", + "post_name": "Köln", + "thoroughfare": "131, Industriestrasse" + }, + { + "request_id": "d000968", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "MIPS Deutschland GmbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DE71D", + "post_code": "65343", + "post_name": "Eltville", + "thoroughfare": "Im Kappelhof 1" + }, + { + "request_id": "d000969", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Burnickl Ingenieur GmbH", + "country_code": "DEU", + "nuts_code": "DE23", + "post_code": "92355", + "post_name": "Velburg", + "thoroughfare": null + }, + { + "request_id": "d000970", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Nemocnice AGEL Jeseník a.s.", + "country_code": "CZE", + "nuts_code": "CZ071", + "post_code": "790 01", + "post_name": "Jeseník", + "thoroughfare": "Lipovská 103/39" + }, + { + "request_id": "d000971", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Svenska Inredningsfabrikanters Försäljnings Aktiebolag", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "411 25", + "post_name": "Göteborg", + "thoroughfare": "Viktoriagatan 24" + }, + { + "request_id": "d000972", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Ministerstvo spravedlnosti České republiky", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "128 10", + "post_name": "Praha 2", + "thoroughfare": "Vyšehradská 16" + }, + { + "request_id": "d000973", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Vermögen und Bau Baden-Württemberg Amt Ludwigsburg", + "country_code": "DEU", + "nuts_code": "DE115", + "post_code": "71638", + "post_name": "Ludwigsburg", + "thoroughfare": "Karlsplatz 5" + }, + { + "request_id": "d000974", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gegenbauer Services GmbH", + "country_code": "DEU", + "nuts_code": "DE300", + "post_code": null, + "post_name": "Berlin", + "thoroughfare": null + }, + { + "request_id": "d000975", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Halle (Saale), Fachbereich Recht, Team Vergabe Bauleistungen/Bauplanungen", + "country_code": "DEU", + "nuts_code": "DEE02", + "post_code": "06108", + "post_name": "Halle (Saale)", + "thoroughfare": "Marktplatz 1" + }, + { + "request_id": "d000976", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landgesellschaft Mecklenburg-Vorpommern mbH", + "country_code": "DEU", + "nuts_code": "DE80O", + "post_code": "19067", + "post_name": "Leezen", + "thoroughfare": "Lindenallee 2a" + }, + { + "request_id": "d000977", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Salzgitter", + "country_code": "DEU", + "nuts_code": "DE912", + "post_code": "38226", + "post_name": "Salzgitter", + "thoroughfare": "Joachim-Campe-Straße 6-8" + }, + { + "request_id": "d000978", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Mylan Healthcare GmbH (A Viatris company), Zweigniederlassung Bad Homburg", + "country_code": "DEU", + "nuts_code": "DE71", + "post_code": "61352", + "post_name": "Bad Homburg", + "thoroughfare": "Benzstraße 1" + }, + { + "request_id": "d000979", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix Telecom S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "020331", + "post_name": "Bucureşti", + "thoroughfare": "Str. Fabrica de Glucoză nr. 11D" + }, + { + "request_id": "d000980", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Atlas Sport", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "540256", + "post_name": "Târgu Mureş", + "thoroughfare": "Str. Voinicenilor nr. 62" + }, + { + "request_id": "d000981", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Kreis Steinfurt", + "country_code": "DEU", + "nuts_code": "DEA37", + "post_code": "48565", + "post_name": "Steinfurt", + "thoroughfare": "Tecklenburger Str. 10" + }, + { + "request_id": "d000982", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DEMGRO nv", + "country_code": "BEL", + "nuts_code": "BE", + "post_code": "8800", + "post_name": "Roeselare", + "thoroughfare": "Zwaaikomstraat 12" + }, + { + "request_id": "d000983", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Județean de Urgență Bacău", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bacău", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000984", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medias International, trgovanje in trženje z medicinskim materialom d.o.o.", + "country_code": "SVN", + "nuts_code": "SI", + "post_code": "1000", + "post_name": "Ljubljana", + "thoroughfare": "Leskoškova cesta 9D" + }, + { + "request_id": "d000985", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Institut klinické a experimentální medicíny", + "country_code": "CZE", + "nuts_code": "CZ010", + "post_code": "140 00", + "post_name": "Praha", + "thoroughfare": "Vídeňská 1958/9" + }, + { + "request_id": "d000986", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000987", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Väylävirasto", + "country_code": "FIN", + "nuts_code": "FI", + "post_code": "FI-00521", + "post_name": "Helsinki", + "thoroughfare": "PL 33 (Opastinsilta 12 A)" + }, + { + "request_id": "d000988", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Iași", + "thoroughfare": "Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000989", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Orano nuclear packages and services (mandataria)", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": null, + "post_name": "Montigny-le-Bretonneux", + "thoroughfare": null + }, + { + "request_id": "d000990", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Università degli studi di Milano — Bicocca", + "country_code": "ITA", + "nuts_code": "ITC4C", + "post_code": "20126", + "post_name": "Milano", + "thoroughfare": "piazza dell'Ateneo Nuovo 1" + }, + { + "request_id": "d000991", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Česká republika – Ministerstvo vnitra", + "country_code": "CZE", + "nuts_code": "CZ0", + "post_code": "170 34", + "post_name": "Praha 7", + "thoroughfare": "Nad Štolou 936/3" + }, + { + "request_id": "d000992", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Consejo Rector del Instituto de Atención Social y Sociosanitaria del Cabildo Insular de Gran Canaria", + "country_code": "ESP", + "nuts_code": "ES70", + "post_code": "35003", + "post_name": "Las Palmas de Gran Canaria", + "thoroughfare": "C/ Tomas Morales, 3" + }, + { + "request_id": "d000993", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universitäts- und Hansestadt Greifswald, Der Oberbürgermeister, Stadtbauamt, Abt. Bauverwaltung", + "country_code": "DEU", + "nuts_code": "DE80N", + "post_code": "17489", + "post_name": "Greifswald", + "thoroughfare": "Markt 15" + }, + { + "request_id": "d000994", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Universitätsklinikum Jena", + "country_code": "DEU", + "nuts_code": "DEG03", + "post_code": "07747", + "post_name": "Jena", + "thoroughfare": "Paul-Schneider-Straße 2" + }, + { + "request_id": "d000995", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Liberecká obalovna, s.r.o.", + "country_code": "CZE", + "nuts_code": "CZ051", + "post_code": "460 01", + "post_name": "Liberec", + "thoroughfare": "Hrádecká 247" + }, + { + "request_id": "d000996", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ebök GmbH", + "country_code": "DEU", + "nuts_code": "DE14", + "post_code": "72072", + "post_name": "Tübingen", + "thoroughfare": "Schellingstraße 4/2" + }, + { + "request_id": "d000997", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pac-Production Sweden AB", + "country_code": "SWE", + "nuts_code": "SE124", + "post_code": "701 48", + "post_name": "Örebro", + "thoroughfare": "Box 409" + }, + { + "request_id": "d000998", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Krogmann Ing. Holzbau GmbH", + "country_code": "DEU", + "nuts_code": "DE94F", + "post_code": "49393", + "post_name": "Lohne", + "thoroughfare": "Kroger Pickerweg 142" + }, + { + "request_id": "d000999", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Gemeindeverwaltung Floh-Seligenthal", + "country_code": "DEU", + "nuts_code": "DEG0B", + "post_code": "98593", + "post_name": "Floh-Seligenthal", + "thoroughfare": "Bahnhofstraße 4" + }, + { + "request_id": "d001000", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "FOCUS TRADING '94 S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "011657", + "post_name": "Bucuresti", + "thoroughfare": "Strada Tudor Stefan, Nr. 10, Sector: 1" + } + ] +} \ No newline at end of file diff --git a/src/demo/data/org-small.json b/src/demo/data/org-small.json new file mode 100644 index 0000000..917a115 --- /dev/null +++ b/src/demo/data/org-small.json @@ -0,0 +1,1106 @@ +{ + "name": "100 Organizations Test Dataset (Address Fields & Name Variations)", + "description": "100 real organizations from 7 EU countries with complete address data and realistic name variations (exact matches, abbreviations, business suffixes, minor typos). Extracted from MDR procurement records. Shuffled for entity resolution testing.", + "mentions": [ + { + "request_id": "d000062", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG", + "country_code": "DEU", + "nuts_code": "DE942", + "post_code": "27751", + "post_name": "Delmenhorst", + "thoroughfare": "Nordenhamer Str. 65" + }, + { + "request_id": "d000010", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u Inc", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000002", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000051", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000032", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pluridet Comexim S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "052082", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Dr. Alexandru Locusteanu nr. 2" + }, + { + "request_id": "d000016", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000057", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier universitaire de Poitiers", + "country_code": "FRA", + "nuts_code": "FRI34", + "post_code": "86021", + "post_name": "Poitiers", + "thoroughfare": "2 rue de la Mil\u00e9trie, CS 90577" + }, + { + "request_id": "d000069", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Augustinum gGmbH", + "country_code": "DEU", + "nuts_code": "DE212", + "post_code": "801375", + "post_name": "M\u00fcnchen", + "thoroughfare": "Stiftsbogen 74" + }, + { + "request_id": "d000077", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix Telecom S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "020331", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Fabrica de Glucoz\u0103 nr. 11D" + }, + { + "request_id": "d000027", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000100", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Oktal Pharma d.o.o.", + "country_code": "HRV", + "nuts_code": "HR050", + "post_code": "10020", + "post_name": "Zagreb", + "thoroughfare": "Utinjska 40" + }, + { + "request_id": "d000071", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wassenberg GmbH", + "country_code": "DEU", + "nuts_code": "DEA1D", + "post_code": "41515", + "post_name": "Grevenbroich", + "thoroughfare": "von-Goldammer-Str. 31" + }, + { + "request_id": "d000031", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pluridet Comexim S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "052082", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Dr. Alexandru Locusteanu nr. 2" + }, + { + "request_id": "d000033", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pluridet Comexim S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "052082", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Dr. Alexandru Locusteanu nr. 2" + }, + { + "request_id": "d000064", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Direcci\u00f3n General \u2014 Osakidetza", + "country_code": "ESP", + "nuts_code": "ES21", + "post_code": "01006", + "post_name": "Vitoria-Gasteiz", + "thoroughfare": "C/ \u00c1lava, 45" + }, + { + "request_id": "d000059", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier universitaire de Poitiers", + "country_code": "FRA", + "nuts_code": "FRI34", + "post_code": "86021", + "post_name": "Poitiers", + "thoroughfare": "2 rue de la Mil\u00e9trie, CS 90577" + }, + { + "request_id": "d000063", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Axis Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO423", + "post_code": "330004", + "post_name": "Deva", + "thoroughfare": "Str. S\u00e2ntuhalm nr. 65B, Deva (Hunedoara), 330004" + }, + { + "request_id": "d000085", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Landesbetrieb Bau und Immobilien Hessen Niederlassung Mitte Zentrale Vergabe", + "country_code": "DEU", + "nuts_code": "DE7", + "post_code": "61231", + "post_name": "Bad Nauheim", + "thoroughfare": "Dieselstra\u00dfe 1-7" + }, + { + "request_id": "d000056", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier universitaire de Poitiers", + "country_code": "FRA", + "nuts_code": "FRI34", + "post_code": "86021", + "post_name": "Poitiers", + "thoroughfare": "2 rue de la Mil\u00e9trie, CS 90577" + }, + { + "request_id": "d000053", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000050", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000048", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM S.R.L. Inc", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbr\u0103veni", + "thoroughfare": "Str. G\u0103rii nr. 3" + }, + { + "request_id": "d000086", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "V\u012e Lietuvos automobili\u0173 keli\u0173 direkcija", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03109", + "post_name": "Vilnius", + "thoroughfare": "J. Basanavi\u010diaus g. 36" + }, + { + "request_id": "d000083", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "S.C. Andrea Forest S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "547510", + "post_name": "Saschiz", + "thoroughfare": "Ferma Hameicola nr. 6, \u00eenscris\u0103 \u00een CF nr. 52512 (nr. cad. 52512) \u0219i CF nr. 3226 (nr. cad. 3226)" + }, + { + "request_id": "d000079", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "IKK classic", + "country_code": "DEU", + "nuts_code": "DE", + "post_code": "01099", + "post_name": "Dresden", + "thoroughfare": "Tannenstra\u00dfe 4 b" + }, + { + "request_id": "d000081", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Netz AG (Bukr 16)", + "country_code": "DEU", + "nuts_code": "DE712", + "post_code": "60327", + "post_name": "Frankfurt am Main", + "thoroughfare": "Adam-Riese-Stra\u00dfe 11-13" + }, + { + "request_id": "d000023", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000009", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000022", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000038", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Ia\u0219i", + "thoroughfare": "Str. I. C. Br\u0103tianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000068", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix Telecom S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "020331", + "post_name": "Bucure\u015fti", + "thoroughfare": "Str. Fabrica de Glucoz\u0103 nr. 11D" + }, + { + "request_id": "d000034", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pluridet Comexim S.R.L.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "052082", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Dr. Alexandru Locusteanu nr. 2" + }, + { + "request_id": "d000011", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000067", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "CEZ V\u00e2nzare S.A.", + "country_code": "ROU", + "nuts_code": "RO411", + "post_code": "200769", + "post_name": "Craiova", + "thoroughfare": "Str. Severinului nr. 97" + }, + { + "request_id": "d000080", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lidk\u00f6pings kommun", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "531 88", + "post_name": "Lidk\u00f6ping", + "thoroughfare": "Skaragatan 8" + }, + { + "request_id": "d000018", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security SRL", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000075", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "OMV Petrom Marketing", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "013329", + "post_name": "Bucure\u015fti", + "thoroughfare": "Str. Coralilor nr. 22, sector 1" + }, + { + "request_id": "d000007", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000042", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L. Inc", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Ia\u0219i", + "thoroughfare": "Str. I. C. Br\u0103tianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000082", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "O2 Czech Republic a.s.", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": "140 22", + "post_name": "Praha 4\u2013Michle", + "thoroughfare": "Za Brumlovkou 266/2" + }, + { + "request_id": "d000061", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Santomed S.R.L.", + "country_code": "ROU", + "nuts_code": "RO424", + "post_code": "300210", + "post_name": "Timi\u0219oara", + "thoroughfare": "Str. Liviu Rebreanu nr. 25" + }, + { + "request_id": "d000015", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000043", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbr\u0103veni", + "thoroughfare": "Str. G\u0103rii nr. 3" + }, + { + "request_id": "d000060", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier universitaire de Poitiers Inc", + "country_code": "FRA", + "nuts_code": "FRI34", + "post_code": "86021", + "post_name": "Poitiers", + "thoroughfare": "2 rue de la Mil\u00e9trie, CS 90577" + }, + { + "request_id": "d000094", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "UAB \u201eIgnitis\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": null, + "post_name": "Vilnius", + "thoroughfare": null + }, + { + "request_id": "d000089", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Hera SpA", + "country_code": "ITA", + "nuts_code": "ITH55", + "post_code": "40127", + "post_name": "Bologna", + "thoroughfare": "viale Carlo Berti Pichat 2/4" + }, + { + "request_id": "d000066", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Baby Business S.R.L.", + "country_code": "ROU", + "nuts_code": "RO124", + "post_code": "535600", + "post_name": "Odorheiu Secuiesc", + "thoroughfare": "Str. Budcar nr. 58" + }, + { + "request_id": "d000037", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Ia\u0219i", + "thoroughfare": "Str. I. C. Br\u0103tianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000024", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000040", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Ia\u0219i", + "thoroughfare": "Str. I. C. Br\u0103tianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000041", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval SRL", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Ia\u0219i", + "thoroughfare": "Str. I. C. Br\u0103tianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000019", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L. Inc", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000073", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AMB Global Kron Consult", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500256", + "post_name": "Bra\u0219ov", + "thoroughfare": "Str. M\u0103cie\u015fului nr. 1" + }, + { + "request_id": "d000006", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000025", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000008", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u Inc", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000035", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pluridet Comexim SRL", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "052082", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Dr. Alexandru Locusteanu nr. 2" + }, + { + "request_id": "d000090", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "G\u00f6teborgs Stad, Lokalf\u00f6rvaltningen", + "country_code": "SWE", + "nuts_code": "SE232", + "post_code": "402 26", + "post_name": "G\u00f6teborg", + "thoroughfare": "Box 5163" + }, + { + "request_id": "d000047", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM SRL", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbr\u0103veni", + "thoroughfare": "Str. G\u0103rii nr. 3" + }, + { + "request_id": "d000003", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000052", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH.", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000017", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000039", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Wasval S.R.L.", + "country_code": "ROU", + "nuts_code": "RO213", + "post_code": "700036", + "post_name": "Ia\u0219i", + "thoroughfare": "Str. I. C. Br\u0103tianu nr. 8A, et. 2, ap. 5" + }, + { + "request_id": "d000045", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbr\u0103veni", + "thoroughfare": "Str. G\u0103rii nr. 3" + }, + { + "request_id": "d000046", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbr\u0103veni", + "thoroughfare": "Str. G\u0103rii nr. 3" + }, + { + "request_id": "d000013", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000049", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000092", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "SUTURA K\u00e9pviseleti \u00e9s Kereskedelmi Korl\u00e1tolt Felel\u0151ss\u00e9g\u0171 T\u00e1rsas\u00e1g", + "country_code": "HUN", + "nuts_code": "HU", + "post_code": "1097", + "post_name": "Budapest", + "thoroughfare": "Gubacsi \u00fat 47." + }, + { + "request_id": "d000014", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000074", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "S.C. Nisara Impex S.R.L", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "505600", + "post_name": "S\u0103cele", + "thoroughfare": "Str. Gen. I. Dragalina nr. 21 A" + }, + { + "request_id": "d000091", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "TREBOR DRUM CONSTRUCT SRL", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": "410265", + "post_name": "Oradea", + "thoroughfare": "Strada Erofte Grigore, Nr. 1B" + }, + { + "request_id": "d000020", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000088", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Lietuvos sveikatos moksl\u0173 universiteto ligonin\u0117 Kauno klinikos", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-50161", + "post_name": "Kaunas", + "thoroughfare": "Eiveni\u0173 g. 2" + }, + { + "request_id": "d000044", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Felix EM S.R.L.", + "country_code": "ROU", + "nuts_code": "RO125", + "post_code": "555500", + "post_name": "Dumbr\u0103veni", + "thoroughfare": "Str. G\u0103rii nr. 3" + }, + { + "request_id": "d000099", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Medika d.d.", + "country_code": "HRV", + "nuts_code": "HR050", + "post_code": "10000", + "post_name": "Zagreb", + "thoroughfare": "Capra\u0161ka 1" + }, + { + "request_id": "d000021", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000001", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000036", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Pluridet Comexim S.R.L. Inc", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "052082", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Dr. Alexandru Locusteanu nr. 2" + }, + { + "request_id": "d000096", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Tinmar Energy S.A.", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "014476", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Floreasca nr. 246C" + }, + { + "request_id": "d000058", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier universitaire de Poitiers Inc", + "country_code": "FRA", + "nuts_code": "FRI34", + "post_code": "86021", + "post_name": "Poitiers", + "thoroughfare": "2 rue de la Mil\u00e9trie, CS 90577" + }, + { + "request_id": "d000029", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000054", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "DB Engineering & Consulting GmbH.", + "country_code": "DEU", + "nuts_code": "DEG01", + "post_code": null, + "post_name": "Erfurt", + "thoroughfare": null + }, + { + "request_id": "d000098", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Siemens Financial Services", + "country_code": "FRA", + "nuts_code": "FR", + "post_code": "93527", + "post_name": "Saint-Denis Cedex", + "thoroughfare": "40 avenue des Fruitiers" + }, + { + "request_id": "d000084", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Weatherford Atlas GIP S.A.", + "country_code": "ROU", + "nuts_code": "RO316", + "post_code": "100189", + "post_name": "Ploie\u0219ti", + "thoroughfare": "Str. Clopo\u021bei nr. 2A" + }, + { + "request_id": "d000026", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000072", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "COMPANIA INDUSTRIALA GRIVITA SA", + "country_code": "ROU", + "nuts_code": "RO322", + "post_code": "077046", + "post_name": "Rudeni", + "thoroughfare": "Strada Rudeni, Nr. 79" + }, + { + "request_id": "d000093", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Z+M Logistics, spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ080", + "post_code": "702 00", + "post_name": "Ostrava", + "thoroughfare": "Gork\u00e9ho 621/26, Moravsk\u00e1 Ostrava" + }, + { + "request_id": "d000078", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "ELZY, spol. s r.o.", + "country_code": "CZE", + "nuts_code": "CZ", + "post_code": "377 01", + "post_name": "Jind\u0159ich\u016fv Hradec", + "thoroughfare": "Jaro\u0161ovsk\u00e1 433" + }, + { + "request_id": "d000065", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "\u010cesk\u00e1 republika - Ministerstvo vnitra", + "country_code": "CZE", + "nuts_code": "CZ0", + "post_code": "170 34", + "post_name": "Praha 7", + "thoroughfare": "Nad \u0160tolou 936/3" + }, + { + "request_id": "d000030", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c Inc", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000028", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "AB \u201eLietuvos gele\u017einkeliai\u201c Inc", + "country_code": "LTU", + "nuts_code": "LT", + "post_code": "LT-03603", + "post_name": "Vilnius", + "thoroughfare": "Mindaugo g. 12" + }, + { + "request_id": "d000097", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "OMV Petrom Marketing", + "country_code": "ROU", + "nuts_code": "RO321", + "post_code": "013329", + "post_name": "Bucure\u0219ti", + "thoroughfare": "Str. Coralilor nr. 22, sector 1" + }, + { + "request_id": "d000004", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000005", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Spitalul Jude\u021bean de Urgen\u021b\u0103 Bac\u0103u", + "country_code": "ROU", + "nuts_code": "RO211", + "post_code": "600114", + "post_name": "Bac\u0103u", + "thoroughfare": "Str. Spiru Haret nr. 2" + }, + { + "request_id": "d000055", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Centre hospitalier universitaire de Poitiers", + "country_code": "FRA", + "nuts_code": "FRI34", + "post_code": "86021", + "post_name": "Poitiers", + "thoroughfare": "2 rue de la Mil\u00e9trie, CS 90577" + }, + { + "request_id": "d000076", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Costacos Com S.R.L.", + "country_code": "ROU", + "nuts_code": "RO122", + "post_code": "500108", + "post_name": "Bra\u0219ov", + "thoroughfare": "Str. Valea Tei nr. 31A" + }, + { + "request_id": "d000012", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Helion Security S.R.L.", + "country_code": "ROU", + "nuts_code": "RO111", + "post_code": null, + "post_name": "\u0218tei", + "thoroughfare": "Str. Andrei Mure\u0219anu nr. AN6" + }, + { + "request_id": "d000070", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "\u010cesk\u00e1 republika \u2013 Ministerstvo vnitra", + "country_code": "CZE", + "nuts_code": "CZ0", + "post_code": "170 34", + "post_name": "Praha 7", + "thoroughfare": "Nad \u0160tolou 936/3" + }, + { + "request_id": "d000095", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "VS Vereinigte Spezialm\u00f6belfabriken GmbH & Co. KG", + "country_code": "DEU", + "nuts_code": "DE11B", + "post_code": "97941", + "post_name": "Tauberbischofsheim", + "thoroughfare": "Hochh\u00e4user Stra\u00dfe 8" + }, + { + "request_id": "d000087", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle", + "country_code": "DEU", + "nuts_code": "DED41", + "post_code": "09111", + "post_name": "Chemnitz", + "thoroughfare": "Friedensplatz 1" + } + ] +} \ No newline at end of file diff --git a/src/demo/data/org-tiny.json b/src/demo/data/org-tiny.json new file mode 100644 index 0000000..aed01a6 --- /dev/null +++ b/src/demo/data/org-tiny.json @@ -0,0 +1,78 @@ +{ + "name": "TED organizations - tiny dataset", + "description": "Demo with real EU data (Germany/France), 2 countries, 2 clusters. Blocking rule prevents cross-country candidates.", + "mentions": [ + { + "request_id": "m1", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Osnabrück", + "country_code": "DEU", + "nuts_code": "DE944", + "post_code": "49074", + "post_name": "Osnabrück", + "thoroughfare": "Krahnstraße 10", + "description": "Mention 1 - German municipality, initial mention" + }, + { + "request_id": "m2", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Osnabrück — Fachdienst Öffentliche Aufträge", + "country_code": "DEU", + "nuts_code": "DE944", + "post_code": "49074", + "post_name": "Osnabrück", + "thoroughfare": "Krahnstraße 10", + "description": "Mention 2 - high similarity to m1 with department name (JW~0.82)" + }, + { + "request_id": "m3", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Conseil départemental Haute-Garonne", + "country_code": "FRA", + "nuts_code": "FRJ23", + "post_code": "31090", + "post_name": "Toulouse", + "thoroughfare": "Boulevard de Strasbourg", + "description": "Mention 3 - different entity (France), new cluster" + }, + { + "request_id": "m4", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Conseil départemental Haute-Garonne Service Public", + "country_code": "FRA", + "nuts_code": "FRJ23", + "post_code": "31090", + "post_name": "Toulouse", + "thoroughfare": "Boulevard de Strasbourg", + "description": "Mention 4 - high similarity to m3 (JW~0.88)" + }, + { + "request_id": "m5", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Stadt Osnabrück, Zentrale", + "country_code": "DEU", + "nuts_code": "DE944", + "post_code": "49074", + "post_name": "Osnabrück", + "thoroughfare": "Krahnstraße 10", + "description": "Mention 5 - similar to m2 (JW~0.89), extends cluster 1" + }, + { + "request_id": "m6", + "source_id": "DEMO", + "entity_type": "ORGANISATION", + "legal_name": "Conseil Haute-Garonne", + "country_code": "FRA", + "nuts_code": "FRJ23", + "post_code": "31090", + "post_name": "Toulouse", + "thoroughfare": "Boulevard de Strasbourg", + "description": "Mention 6 - similar to m3/m4 (JW~0.78), extends cluster 2" + } + ] +} \ No newline at end of file diff --git a/src/demo/demo.py b/src/demo/demo.py new file mode 100755 index 0000000..dd6fcc0 --- /dev/null +++ b/src/demo/demo.py @@ -0,0 +1,563 @@ +#!/usr/bin/env python3 +""" +Demo: Indirect Redis client for ERE (Entity Resolution Engine). + +This demo connects to ERE through the Redis queue infrastructure (no direct Python API). +It demonstrates: +1. Checking Redis connectivity +2. Sending EntityMentionResolutionRequest messages to the queue +3. Listening for EntityMentionResolutionResponse messages +4. Logging all interactions + +The example uses 6 synthetic mentions from ALGORITHM.md that cluster into 2 groups: + - Cluster 1: {1, 2, 5} (organizations with high similarity) + - Cluster 2: {3, 4, 6} (different organizations, also highly similar) + +⚠️ IMPORTANT: The ERE resolver persists state in a DuckDB database volume. + Before running a fresh demo with different data, clear the old database: + + docker volume rm ere-local_ere-data + make infra-rebuild + + Failure to do so will mix old mentions with new ones, corrupting demo results. +""" + +import json +import logging +import os +import sys +import time +from datetime import datetime, timezone +from pathlib import Path + +import redis + +# Default data file path +DEFAULT_DATA_FILE = Path(__file__).parent / "data" / "org-tiny.json" + +DELAY_BETWEEN_MESSAGES = ( + 0 # seconds to wait between sending messages (set to >0 for sequential processing) +) +GLOBAL_TIMEOUT = 0 # seconds to wait for responses before giving up (0 = no timeout) + + +# =============================================================================== +# Configuration +# =============================================================================== + + +def load_env_file(env_path: str = None) -> dict: + """Load configuration from .env or environment variables.""" + config = {} + + # Try to load from .env if it exists + if env_path is None: + env_path = Path(__file__).parent.parent / "infra" / ".env" + + if Path(env_path).exists(): + with open(env_path) as f: + for line in f: + line = line.strip() + if line and not line.startswith("#"): + if "=" in line: + key, value = line.split("=", 1) + config[key.strip()] = value.strip() + + # Environment variables override .env + config["REDIS_HOST"] = os.environ.get( + "REDIS_HOST", config.get("REDIS_HOST", "localhost") + ) + config["REDIS_PORT"] = int( + os.environ.get("REDIS_PORT", config.get("REDIS_PORT", "6379")) + ) + config["REDIS_DB"] = int(os.environ.get("REDIS_DB", config.get("REDIS_DB", "0"))) + config["REDIS_PASSWORD"] = os.environ.get( + "REDIS_PASSWORD", config.get("REDIS_PASSWORD") + ) + config["ERSYS_REQUEST_QUEUE"] = os.environ.get( + "ERSYS_REQUEST_QUEUE", config.get("ERSYS_REQUEST_QUEUE", "ere_requests") + ) + config["ERSYS_RESPONSE_QUEUE"] = os.environ.get( + "ERSYS_RESPONSE_QUEUE", config.get("ERSYS_RESPONSE_QUEUE", "ere_responses") + ) + + return config + + +# =============================================================================== +# Logging Setup +# =============================================================================== + +TRACE = 5 + + +def setup_logging(): + """Configure logging with timestamps.""" + log_level_name = os.environ.get("ERE_LOG_LEVEL", "INFO").upper() + + # Handle custom TRACE level + if log_level_name == "TRACE": + log_level = TRACE + logging.addLevelName(TRACE, "TRACE") + else: + log_level = getattr(logging, log_level_name, logging.INFO) + + logging.basicConfig( + level=log_level, + format="%(asctime)s [%(levelname)s] %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + logger = logging.getLogger(__name__) + logger.setLevel(log_level) + logger.info(f"Logging configured at level {log_level_name}") + + return logger + + +# =============================================================================== +# Redis Connection +# =============================================================================== + + +def check_redis_connectivity( + host: str, port: int, db: int, password: str +) -> redis.Redis: + """ + Check Redis connectivity and return client. + + Attempts connection to specified host first, then fallback to localhost + if configured host is "redis" (Docker). + + Raises: + RuntimeError: If Redis is not accessible. + """ + hosts_to_try = [host] + + # Fallback: if configured host is "redis" (Docker), also try localhost + if host == "redis": + hosts_to_try.append("localhost") + + last_error = None + for try_host in hosts_to_try: + try: + logging.getLogger(__name__).info( + f"Attempting Redis connection to {try_host}:{port}..." + ) + client = redis.Redis( + host=try_host, + port=port, + db=db, + password=password, + decode_responses=False, + ) + client.ping() + return client + except Exception as e: + last_error = e + continue + + raise RuntimeError( + f"Redis unavailable. Tried hosts: {hosts_to_try}, port: {port}, db: {db}" + ) from last_error + + +# =============================================================================== +# Request/Response Handling +# =============================================================================== + + +def escape_turtle_string(value: str) -> str: + """ + Escape a string for safe inclusion in Turtle RDF format. + + Handles special characters: backslash, double quotes, newlines, carriage returns, tabs. + + Args: + value: String to escape + + Returns: + Escaped string safe for use in Turtle string literals + """ + if not value: + return value + + # Escape backslash first (must be done before other escapes) + value = value.replace("\\", "\\\\") + # Escape double quotes + value = value.replace('"', '\\"') + # Escape newlines + value = value.replace("\n", "\\n") + # Escape carriage returns + value = value.replace("\r", "\\r") + # Escape tabs + value = value.replace("\t", "\\t") + + return value + + +def create_entity_mention_request( + request_id: str, + source_id: str, + entity_type: str, + legal_name: str, + country_code: str, + nuts_code: str | None = None, + post_code: str | None = None, + post_name: str | None = None, + thoroughfare: str | None = None, +) -> dict: + """ + Create an EntityMentionResolutionRequest payload. + + Uses RDF/Turtle format with entity metadata including extended address fields. + All string values are properly escaped for Turtle compatibility. + + Args: + request_id: Unique request identifier + source_id: Source system identifier + entity_type: Entity type (e.g., ORGANISATION) + legal_name: Legal name of the entity + country_code: ISO 2-letter country code + nuts_code: Optional NUTS regional code + post_code: Optional postal code + post_name: Optional city/locality name + thoroughfare: Optional street address + """ + # Escape all string values for Turtle safety + legal_name_safe = escape_turtle_string(legal_name or "") + country_code_safe = escape_turtle_string(country_code or "") + + # Build address properties dynamically + address_props = [f'epo:hasCountryCode "{country_code_safe}"'] + if nuts_code: + nuts_code_safe = escape_turtle_string(nuts_code) + address_props.append(f'epo:hasNutsCode "{nuts_code_safe}"') + if post_code: + post_code_safe = escape_turtle_string(post_code) + address_props.append(f'locn:postCode "{post_code_safe}"') + if post_name: + post_name_safe = escape_turtle_string(post_name) + address_props.append(f'locn:postName "{post_name_safe}"') + if thoroughfare: + thoroughfare_safe = escape_turtle_string(thoroughfare) + address_props.append(f'locn:thoroughfare "{thoroughfare_safe}"') + + address_content = " ;\n ".join(address_props) + + content = f"""@prefix org: . +@prefix cccev: . +@prefix epo: . +@prefix locn: . +@prefix epd: . + +epd:ent{request_id} a org:Organization ; + epo:hasLegalName "{legal_name_safe}" ; + cccev:registeredAddress [ + {address_content} + ] . +""" + + return { + "type": "EntityMentionResolutionRequest", + "entity_mention": { + "identifiedBy": { + "request_id": request_id, + "source_id": source_id, + "entity_type": entity_type, + }, + "content": content.strip(), + "content_type": "text/turtle", + }, + "timestamp": datetime.now(timezone.utc).isoformat(), + "ere_request_id": f"{request_id}:01", + } + + +def parse_response(response_bytes: bytes) -> dict: + """Parse JSON response from Redis.""" + return json.loads(response_bytes.decode("utf-8")) + + +# =============================================================================== +# Demo Data Loading +# =============================================================================== + + +def load_demo_mentions(data_file: str | None = None) -> list[dict]: + """ + Load demo mentions from a JSON file. + + Args: + data_file: Path to JSON file containing mentions. If None, uses default. + + Returns: + List of mention dicts with keys: request_id, source_id, entity_type, + legal_name, country_code, description. + + Raises: + FileNotFoundError: If data file does not exist. + ValueError: If JSON is invalid or missing 'mentions' key. + """ + if data_file is None: + data_file = DEFAULT_DATA_FILE + + data_path = Path(data_file) + if not data_path.exists(): + raise FileNotFoundError(f"Data file not found: {data_path}") + + with open(data_path) as f: + data = json.load(f) + + if "mentions" not in data: + raise ValueError(f"JSON must contain 'mentions' key") + + return data["mentions"] + + +# =============================================================================== +# Main Demo +# =============================================================================== + + +def main(data_file: str | None = None): + """ + Run the Redis-based ERE demo. + + Args: + data_file: Path to JSON file containing demo mentions. + If None, uses default (mentions_mixed_countries.json). + """ + logger = setup_logging() + + # Load configuration + logger.info("Loading configuration...") + config = load_env_file() + logger.info( + f"Redis config: host={config['REDIS_HOST']}, " + f"port={config['REDIS_PORT']}, db={config['REDIS_DB']}" + ) + logger.info( + f"Queue names: request={config['ERSYS_REQUEST_QUEUE']}, " + f"response={config['ERSYS_RESPONSE_QUEUE']}" + ) + + # Load demo mentions from JSON + try: + demo_mentions = load_demo_mentions(data_file) + logger.info( + f"Loaded {len(demo_mentions)} mentions from {data_file or DEFAULT_DATA_FILE}" + ) + except (FileNotFoundError, ValueError) as e: + logger.exception("Failed to load demo mentions") + return 1 + + # Check Redis connectivity + logger.info("Checking Redis connectivity...") + try: + redis_client = check_redis_connectivity( + host=config["REDIS_HOST"], + port=config["REDIS_PORT"], + db=config["REDIS_DB"], + password=config["REDIS_PASSWORD"], + ) + logger.info("✓ Redis is available") + except RuntimeError as e: + logger.exception("✗ Redis check failed") + return 1 + + # Clear queues + logger.info("Clearing request and response queues...") + redis_client.delete(config["ERSYS_REQUEST_QUEUE"], config["ERSYS_RESPONSE_QUEUE"]) + + # ⚠️ Check if DuckDB database is non-empty (stale from prior runs) + # This guards against corrupting demo results by mixing old and new mentions + duckdb_path = Path(os.environ.get("DUCKDB_PATH", "/data/app.duckdb")) + if duckdb_path.exists() and duckdb_path.stat().st_size > 0: + logger.warning( + f"⚠️ WARNING: DuckDB database file exists and is non-empty!\n" + f" This may contain mentions from a prior run.\n" + f" This will CORRUPT demo results by mixing old and new data.\n" + f" \n" + f" To reset the database:\n" + f" 1. docker volume rm ere-local_ere-data\n" + f" 2. make infra-rebuild\n" + ) + + # Send demo requests + logger.info(f"Sending {len(demo_mentions)} entity mentions...") + request_ids = [] + + for mention in demo_mentions: + request = create_entity_mention_request( + request_id=mention["request_id"], + source_id=mention["source_id"], + entity_type=mention["entity_type"], + legal_name=mention["legal_name"], + country_code=mention["country_code"], + nuts_code=mention.get("nuts_code"), + post_code=mention.get("post_code"), + post_name=mention.get("post_name"), + thoroughfare=mention.get("thoroughfare"), + ) + + message_json = json.dumps(request) + if logger.isEnabledFor(TRACE): + logger.log(TRACE, f"Full request message:\n{json.dumps(request, indent=2)}") + + message_bytes = message_json.encode("utf-8") + redis_client.rpush(config["ERSYS_REQUEST_QUEUE"], message_bytes) + request_ids.append(mention["request_id"]) + + logger.info( + f" → Sent request {mention['request_id']}: " + f"{mention['legal_name']} ({mention['country_code']}) " + f"[{mention.get('description', '')}]" + ) + + # Wait 1 second between messages to ensure sequential processing + if DELAY_BETWEEN_MESSAGES: + time.sleep(1) + + logger.info("") + logger.info("Listening for responses...") + logger.info("-" * 80) + + # Track mentions for summary: map request_id → (legal_name, cluster_id) + mention_tracking = {} + for mention in demo_mentions: + mention_tracking[mention["request_id"]] = { + "legal_name": mention["legal_name"], + "cluster_id": None, # Will be filled in from response + } + + # Listen for responses + responses_received = {} + start_time = time.time() + + while len(responses_received) < len(request_ids): + elapsed = time.time() - start_time + if GLOBAL_TIMEOUT > 0 and elapsed > GLOBAL_TIMEOUT: + logger.warning( + f"Timeout after {GLOBAL_TIMEOUT}s. Received {len(responses_received)}/{len(request_ids)} responses." + ) + break + + # Try to get a response with short timeout + result = redis_client.brpop(config["ERSYS_RESPONSE_QUEUE"], timeout=1) + + if result is not None: + _, response_bytes = result + response = parse_response(response_bytes) + + if logger.isEnabledFor(TRACE): + logger.log( + TRACE, f"Full response message:\n{json.dumps(response, indent=2)}" + ) + + req_id = response["entity_mention_id"]["request_id"] + responses_received[req_id] = response + + logger.info(f"\n✓ Response received for {req_id}:") + logger.info(f" Type: {response['type']}") + logger.info(f" Timestamp: {response['timestamp']}") + + source_id = response["entity_mention_id"]["source_id"] + entity_type = response["entity_mention_id"]["entity_type"] + logger.info(f" Mention: ({source_id}, {req_id}, {entity_type})") + + logger.info(f" Candidates:") + + # Track the top cluster assignment (first candidate is the assignment) + if response.get("candidates"): + top_candidate = response["candidates"][0] + assigned_cluster = top_candidate["cluster_id"] + mention_tracking[req_id]["cluster_id"] = assigned_cluster + logger.info(f" → Assigned to cluster: {assigned_cluster}") + + for i, candidate in enumerate(response.get("candidates", []), 1): + logger.info( + f" {i}. Cluster {candidate['cluster_id']}: " + f"confidence={candidate['confidence_score']:.4f}, " + f"similarity={candidate['similarity_score']:.4f}" + ) + + logger.info("-" * 80) + logger.info( + f"\nDemo complete. Received {len(responses_received)}/{len(request_ids)} responses." + ) + + # Build clustering summary as single block + summary_lines = [] + summary_lines.append("=" * 80) + summary_lines.append("CLUSTERING SUMMARY") + summary_lines.append("=" * 80) + + # Group mentions by assigned cluster + clusters = {} + unassigned = [] + + for req_id in request_ids: + tracking = mention_tracking.get(req_id) + if tracking: + cluster_id = tracking["cluster_id"] + legal_name = tracking["legal_name"] + + if cluster_id is None: + unassigned.append((req_id, legal_name)) + else: + if cluster_id not in clusters: + clusters[cluster_id] = [] + clusters[cluster_id].append((req_id, legal_name)) + + # Build cluster output + if clusters: + for cluster_id in sorted(clusters.keys()): + members = clusters[cluster_id] + summary_lines.append("") + summary_lines.append(f"{cluster_id} ({len(members)} members):") + for req_id, legal_name in members: + summary_lines.append(f" {req_id:4s} | {legal_name}") + else: + summary_lines.append("") + summary_lines.append("(No clusters formed)") + + # Add unassigned mentions + if unassigned: + summary_lines.append("") + summary_lines.append(f"Unassigned ({len(unassigned)} mentions):") + for req_id, legal_name in unassigned: + summary_lines.append(f" {req_id:4s} | {legal_name}") + + summary_lines.append("=" * 80) + + # Print entire summary in one log call + summary_block = "\n".join(summary_lines) + logger.info(f"\n{summary_block}") + + # Summary + if len(responses_received) == len(request_ids): + logger.info("✓ All responses received successfully!") + return 0 + else: + logger.warning( + f"✗ Missing {len(request_ids) - len(responses_received)} response(s)." + ) + return 1 + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser( + description="Redis-based ERE demo with parametrized mentions data." + ) + parser.add_argument( + "--data", + type=str, + default=None, + help=f"Path to JSON file with demo mentions (default: {DEFAULT_DATA_FILE})", + ) + args = parser.parse_args() + + sys.exit(main(data_file=args.data)) diff --git a/src/ere/__init__.py b/src/ere/__init__.py new file mode 100644 index 0000000..8b71965 --- /dev/null +++ b/src/ere/__init__.py @@ -0,0 +1,4 @@ +"""Entity Resolution Engine (ERE) - core package.""" + +# Initialize logging utilities (adds trace level to Logger) +from ere.utils.logging import configure_logging # noqa: F401 diff --git a/src/ere/adapters/__init__.py b/src/ere/adapters/__init__.py new file mode 100644 index 0000000..88a93fd --- /dev/null +++ b/src/ere/adapters/__init__.py @@ -0,0 +1,49 @@ +from abc import abstractmethod +from typing import Protocol + +from erspec.models.ere import ERERequest, EREResponse + +from ere.adapters.repositories import ( + ClusterRepository, + MentionRepository, + SimilarityRepository, +) +from ere.adapters.rdf_mapper_port import RDFMapper + + +class AbstractResolver(Protocol): + """ + ERE resolver abstraction. + + An ERE resolver deals with the core of the job, ie, it takes requests like + :class:`ere.models.ere.ERERequest` and computes results for them. + + A resolver doesn't deal with aspects like networking or asynchronous processing, these + are concerns for services and entrypoints, which wrap around resolvers. + + As you can see, it makes sense to define resolvers as :class:`Protocol` classes, so that, + for instance, even a simple lambda could be used as a resolver. + """ + + @abstractmethod + def process_request(self, request: ERERequest) -> EREResponse: + """ + Resolve an entity resolution request, returning the corresponding response. + + This only concerns the resolution logic, leaving out aspects like transport or + asynchronous processing. + + This should take care of wrapping exceptions into ErrorResponse results. + """ + + def __call__(self, request: ERERequest) -> EREResponse: + return self.process_request(request) + + +__all__ = [ + "AbstractResolver", + "ClusterRepository", + "MentionRepository", + "RDFMapper", + "SimilarityRepository", +] diff --git a/src/ere/adapters/duckdb_repositories.py b/src/ere/adapters/duckdb_repositories.py new file mode 100644 index 0000000..c65caa8 --- /dev/null +++ b/src/ere/adapters/duckdb_repositories.py @@ -0,0 +1,231 @@ +"""DuckDB-backed repository implementations for service layer.""" + +import duckdb +import pandas as pd + +from ere.models.resolver import ( + ClusterId, + ClusterMembership, + Mention, + MentionId, + MentionLink, +) +from ere.adapters.repositories import ( + ClusterRepository, + MentionRepository, + SimilarityRepository, +) + + +class DuckDBMentionRepository(MentionRepository): + """DuckDB-backed mention repository.""" + + def __init__(self, con: duckdb.DuckDBPyConnection, entity_fields: list[str]): + """ + Initialize with a DuckDB connection and entity field names. + + Args: + con: DuckDB connection (must have mentions table already created). + entity_fields: List of field names (e.g. ["legal_name", "country_code"]). + """ + self._con = con + self._entity_fields = entity_fields + + def save(self, mention: Mention) -> None: + """ + Persist a mention to storage. + + Uses parameterized INSERT with dynamic columns based on entity_fields. + """ + flat_dict = mention.to_flat_dict() + # Extract mention_id and entity field values in order + values = [flat_dict["mention_id"]] + [ + flat_dict.get(f) for f in self._entity_fields + ] + placeholders = ",".join(["?"] * (1 + len(self._entity_fields))) + col_names = ",".join(["mention_id"] + self._entity_fields) + + self._con.execute( + f"INSERT INTO mentions ({col_names}) VALUES ({placeholders})", values + ) + + def load_all(self) -> list[Mention]: + """ + Retrieve all persisted mentions. + + Reconstructs Mention objects from flat database rows. + """ + col_list = ", ".join(["mention_id"] + self._entity_fields) + rows = self._con.execute(f"SELECT {col_list} FROM mentions").fetchall() + mentions = [] + for row in rows: + # Reconstruct flat dict: {"mention_id": ..., "legal_name": ..., ...} + flat_dict = {"mention_id": row[0]} + for i, field in enumerate(self._entity_fields): + flat_dict[field] = row[i + 1] + mentions.append(Mention(**flat_dict)) + return mentions + + def count(self) -> int: + """Return the total number of mentions in storage.""" + row = self._con.execute("SELECT COUNT(*) FROM mentions").fetchone() + return row[0] + + def find_by_id(self, mention_id: MentionId) -> Mention | None: + """ + Retrieve a single mention by ID. + + Returns: + The Mention object if found, None otherwise. + """ + col_list = ", ".join(["mention_id"] + self._entity_fields) + rows = self._con.execute( + f"SELECT {col_list} FROM mentions WHERE mention_id = ?", + [mention_id.value], + ).fetchall() + if not rows: + return None + row = rows[0] + # Reconstruct flat dict: {"mention_id": ..., "legal_name": ..., ...} + flat_dict = {"mention_id": row[0]} + for i, field in enumerate(self._entity_fields): + flat_dict[field] = row[i + 1] + return Mention(**flat_dict) + + +class DuckDBSimilarityRepository(SimilarityRepository): + """DuckDB-backed similarity repository.""" + + def __init__(self, con: duckdb.DuckDBPyConnection): + """ + Initialize with a DuckDB connection. + + Args: + con: DuckDB connection (must have similarities table already created). + """ + self._con = con + + def save_all(self, links: list[MentionLink]) -> None: + """ + Persist multiple mention-links using vectorized INSERT. + + Skips if empty. Uses pandas DataFrame + temporary table registration for efficiency + (DuckDB optimizes vectorized INSERT SELECT operations). + """ + if not links: + return + + # Build DataFrame with columns: mention_id_l, mention_id_r, match_probability + rows = [ + { + "mention_id_l": link.left_id.value, + "mention_id_r": link.right_id.value, + "match_probability": link.score, + } + for link in links + ] + df = pd.DataFrame(rows) + + # Register DataFrame as temporary table and insert (optimized by DuckDB for vectorized operations) + self._con.register("df_temp", df) + self._con.execute("INSERT INTO similarities SELECT * FROM df_temp") + + def count(self) -> int: + """Return the total number of mention-links in storage.""" + row = self._con.execute("SELECT COUNT(*) FROM similarities").fetchone() + return row[0] + + def find_for(self, mention_id: MentionId) -> list[MentionLink]: + """ + Retrieve all mention-links involving the given mention. + + Returns all links where this mention appears on either side + (left_id or right_id). + """ + mention_id_str = mention_id.value + rows = self._con.execute( + """ + SELECT mention_id_l, mention_id_r, match_probability + FROM similarities + WHERE mention_id_l = ? OR mention_id_r = ? + """, + [mention_id_str, mention_id_str], + ).fetchall() + + links = [] + for left_str, right_str, score in rows: + links.append( + MentionLink( + left_id=MentionId(value=left_str), + right_id=MentionId(value=right_str), + score=score, + ) + ) + return links + + +class DuckDBClusterRepository(ClusterRepository): + """DuckDB-backed cluster repository.""" + + def __init__(self, con: duckdb.DuckDBPyConnection): + """ + Initialize with a DuckDB connection. + + Args: + con: DuckDB connection (must have clusters table already created). + """ + self._con = con + + def save(self, membership: ClusterMembership) -> None: + """Persist a cluster membership assignment.""" + self._con.execute( + "INSERT INTO clusters VALUES (?, ?)", + [membership.mention_id.value, membership.cluster_id.value], + ) + + def find_cluster_of(self, mention_id: MentionId) -> ClusterId: + """ + Look up the cluster a mention belongs to. + + Raises KeyError if the mention has no cluster assignment. + """ + row = self._con.execute( + "SELECT cluster_id FROM clusters WHERE mention_id = ?", + [mention_id.value], + ).fetchone() + + if row is None: + raise KeyError(f"No cluster assignment for mention {mention_id}") + + return ClusterId(value=row[0]) + + def count(self) -> int: + """Return the total number of distinct clusters in storage.""" + row = self._con.execute( + "SELECT COUNT(DISTINCT cluster_id) FROM clusters" + ).fetchone() + return row[0] + + def get_all_memberships(self) -> dict[ClusterId, list[MentionId]]: + """ + Retrieve the full cluster membership mapping. + + Returns dict mapping ClusterId -> list of MentionIds in that cluster, + sorted for determinism. + """ + rows = self._con.execute( + """ + SELECT cluster_id, array_agg(mention_id ORDER BY mention_id) AS members + FROM clusters + GROUP BY cluster_id + ORDER BY cluster_id + """ + ).fetchall() + + memberships: dict[ClusterId, list[MentionId]] = {} + for cluster_id_str, members_array in rows: + cluster_id = ClusterId(value=cluster_id_str) + member_ids = [MentionId(value=m) for m in members_array] + memberships[cluster_id] = member_ids + + return memberships diff --git a/src/ere/adapters/duckdb_schema.py b/src/ere/adapters/duckdb_schema.py new file mode 100644 index 0000000..6ded6e6 --- /dev/null +++ b/src/ere/adapters/duckdb_schema.py @@ -0,0 +1,41 @@ +"""Schema initialization for DuckDB adapter.""" + +import duckdb + + +def init_schema(con: duckdb.DuckDBPyConnection, entity_fields: list[str]) -> None: + """ + Create application tables if they do not already exist. + + This mirrors the standard database initialization logic, allowing adapters to be used + with a fresh connection. + + Args: + con: DuckDB connection. + entity_fields: List of field names (e.g. ["legal_name", "country_code"]). + """ + # mentions table: mention_id + dynamic entity fields (all TEXT) + col_defs = ",\n ".join(f"{f} TEXT" for f in entity_fields) + con.execute(f""" + CREATE TABLE IF NOT EXISTS mentions ( + mention_id TEXT, + {col_defs} + ) + """) + + # similarities table: mention pairs with match probability + con.execute(""" + CREATE TABLE IF NOT EXISTS similarities ( + mention_id_l TEXT, + mention_id_r TEXT, + match_probability REAL + ) + """) + + # clusters table: mention -> cluster_id mapping + con.execute(""" + CREATE TABLE IF NOT EXISTS clusters ( + mention_id TEXT, + cluster_id TEXT + ) + """) diff --git a/src/ere/adapters/factories.py b/src/ere/adapters/factories.py new file mode 100644 index 0000000..77cd8b3 --- /dev/null +++ b/src/ere/adapters/factories.py @@ -0,0 +1,29 @@ +"""Factory functions for concrete adapter instantiation. + +This module is responsible for instantiating concrete RDF mapper implementations. +It lives in the adapters layer because it owns the selection of concrete +implementations. + +Services never import from here; they receive fully-constructed instances instead. +This keeps the service layer free of concrete adapter dependencies and makes +swapping implementations safe and testable. +""" + +from pathlib import Path + +from ere.adapters.rdf_mapper_impl import TurtleRDFMapper +from ere.adapters.rdf_mapper_port import RDFMapper + + +def build_rdf_mapper(rdf_mapping_path: str | Path = None) -> RDFMapper: + """ + Factory: construct RDFMapper for entity mention parsing. + + Args: + rdf_mapping_path: Path to rdf_mapping.yaml config file. + If None, uses default path. + + Returns: + Fully-constructed RDFMapper implementation (TurtleRDFMapper). + """ + return TurtleRDFMapper(rdf_mapping_path) diff --git a/src/ere/adapters/rdf_mapper.py b/src/ere/adapters/rdf_mapper.py new file mode 100644 index 0000000..1f45fc1 --- /dev/null +++ b/src/ere/adapters/rdf_mapper.py @@ -0,0 +1,137 @@ +"""Config-driven RDF Turtle parser and entity attribute mapper.""" + +from pathlib import Path +from typing import Any + +import yaml +from rdflib import Graph, Namespace, RDF, URIRef + + +def load_entity_mappings(yaml_path: str | Path) -> dict[str, dict[str, Any]]: + """ + Load entity type mappings from rdf_mapping.yaml. + + Returns: + Dict keyed by entity_type string (e.g. "ORGANISATION") -> + {"rdf_type": URIRef, "fields": {field_name: [URIRef, ...]}} + where each value in "fields" is a list of resolved URIRefs (property path steps). + """ + yaml_path = Path(yaml_path) + with open(yaml_path, encoding="utf-8") as f: + config = yaml.safe_load(f) + + # Build namespace prefix registry + namespaces_config = config.get("namespaces", {}) + namespace_registry = { + prefix: Namespace(uri) for prefix, uri in namespaces_config.items() + } + + # Resolve entity type mappings + entity_types_config = config.get("entity_types", {}) + resolved_mappings = {} + + for entity_type, mapping in entity_types_config.items(): + rdf_type_str = mapping["rdf_type"] + rdf_type_uri = _resolve_prefixed_uri(rdf_type_str, namespace_registry) + + # Resolve field property paths + field_mappings = {} + for field_name, path_str in mapping["fields"].items(): + # Handle null fields (e.g. country_code for PROCEDURE) + if path_str is None: + field_mappings[field_name] = None + else: + # Split on "/" and resolve each segment + steps = path_str.split("/") + resolved_steps = [ + _resolve_prefixed_uri(step, namespace_registry) for step in steps + ] + field_mappings[field_name] = resolved_steps + + resolved_mappings[entity_type] = { + "rdf_type": rdf_type_uri, + "fields": field_mappings, + } + + return resolved_mappings + + +def extract_mention_attributes( + content: str, entity_type_config: dict[str, Any] +) -> dict[str, str | None]: + """ + Parse Turtle RDF content and extract attribute dict per config-specified property paths. + + Args: + content: Turtle RDF string (must be non-empty). + entity_type_config: Dict with "rdf_type" (URIRef) and "fields" (dict of field -> [URIRef, ...]). + + Returns: + Dict mapping field names to their extracted values (strings or None if not found). + + Raises: + ValueError: If content is empty, malformed, or no entity of rdf_type is found. + """ + if not content or not content.strip(): + raise ValueError("RDF content is empty or whitespace-only") + + # Parse Turtle + graph = Graph() + try: + graph.parse(data=content, format="turtle") + except Exception as exc: + raise ValueError(f"Failed to parse RDF Turtle: {exc}") from exc + + # Find the subject with the target RDF type + rdf_type = entity_type_config["rdf_type"] + entity_subject = graph.value(predicate=RDF.type, object=rdf_type) + + if entity_subject is None: + raise ValueError(f"No entity of type {rdf_type} found in RDF content") + + # Extract attributes per config + attributes = {} + for field_name, path_steps in entity_type_config["fields"].items(): + # Skip null field mappings (e.g. country_code for PROCEDURE) + if path_steps is None: + attributes[field_name] = None + continue + + current = entity_subject + for predicate in path_steps: + if current is None: + break + current = graph.value(current, predicate) + + # Convert to string if found + if current is not None: + attributes[field_name] = str(current) + else: + attributes[field_name] = None + + return attributes + + +def _resolve_prefixed_uri(prefixed_str: str, namespace_registry: dict) -> URIRef: + """ + Resolve a prefixed URI string like "org:Organization" to a URIRef. + + Args: + prefixed_str: String like "prefix:localName" or just "localName". + namespace_registry: Dict of prefix -> Namespace objects. + + Returns: + Resolved URIRef. + + Raises: + ValueError: If prefix is not in the registry. + """ + if ":" in prefixed_str: + prefix, local_name = prefixed_str.split(":", 1) + if prefix not in namespace_registry: + raise ValueError(f"Unknown namespace prefix: {prefix}") + namespace = namespace_registry[prefix] + return URIRef(namespace[local_name]) + else: + # Bare local name - return as-is (should not happen in practice) + return URIRef(prefixed_str) diff --git a/src/ere/adapters/rdf_mapper_impl.py b/src/ere/adapters/rdf_mapper_impl.py new file mode 100644 index 0000000..09bd35c --- /dev/null +++ b/src/ere/adapters/rdf_mapper_impl.py @@ -0,0 +1,102 @@ +"""Concrete RDF mapper implementation for Turtle RDF extraction. + +This adapter implements the RDFMapper port using the rdf_mapper utilities +for Turtle RDF parsing and attribute extraction per YAML configuration. +""" + +import hashlib +import logging +from pathlib import Path + +from erspec.models.core import EntityMention + +from ere.adapters.rdf_mapper import load_entity_mappings, extract_mention_attributes +from ere.adapters.rdf_mapper_port import RDFMapper +from ere.models.resolver import Mention, MentionId + +log = logging.getLogger(__name__) + + +class TurtleRDFMapper(RDFMapper): + """Concrete RDF mapper for Turtle RDF format.""" + + def __init__(self, rdf_mapping_path: str | Path = None): + """ + Initialize the RDF mapper with configuration. + + Args: + rdf_mapping_path: Path to rdf_mapping.yaml config file. + If None, uses default relative path. + """ + self._mappings = self._load_mappings(rdf_mapping_path) + + @staticmethod + def _load_mappings(rdf_mapping_path: str | Path = None) -> dict: + """ + Load entity mappings from rdf_mapping.yaml. + + Args: + rdf_mapping_path: Path to rdf_mapping.yaml. If None, uses default. + + Returns: + dict: Entity type mappings from config. + """ + if rdf_mapping_path is None: + rdf_mapping_path = ( + Path(__file__).parent.parent.parent + / "config" + / "rdf_mapping.yaml" + ) + else: + rdf_mapping_path = Path(rdf_mapping_path) + return load_entity_mappings(rdf_mapping_path) + + def map_entity_mention_to_domain(self, entity_mention: EntityMention) -> Mention: + """ + Map EntityMention (erspec) to Mention (domain). + + Performs RDF parsing and attribute extraction per config. + + Args: + entity_mention: EntityMention from erspec. + + Returns: + Mention: Domain object with id and attributes. + + Raises: + ValueError: If RDF parsing fails or entity type is unknown. + """ + eid = entity_mention.identifiedBy + entity_type_config = self._mappings.get(eid.entity_type) + if entity_type_config is None: + raise ValueError( + f"No rdf_mapping configured for entity_type '{eid.entity_type}'" + ) + + mention_id = MentionId( + value=self._derive_mention_id( + eid.source_id, eid.request_id, eid.entity_type + ) + ) + attributes = extract_mention_attributes( + entity_mention.content, entity_type_config + ) + return Mention(id=mention_id, attributes=attributes) + + @staticmethod + def _derive_mention_id(source_id: str, request_id: str, entity_type: str) -> str: + """ + Derive a stable MentionId from source_id, request_id, and entity_type. + + Per ERE spec section 4, the mention ID is deterministic and reproducible. + """ + raw = source_id + request_id + entity_type + mention_id = hashlib.sha256(raw.encode("utf-8")).hexdigest() + log.trace( + "Deterministic ID assigned: %s for triad (%s, %s, %s)", + mention_id, + source_id, + request_id, + entity_type, + ) + return mention_id diff --git a/src/ere/adapters/rdf_mapper_port.py b/src/ere/adapters/rdf_mapper_port.py new file mode 100644 index 0000000..db47686 --- /dev/null +++ b/src/ere/adapters/rdf_mapper_port.py @@ -0,0 +1,41 @@ +"""RDF mapper port interface (abstract base class). + +This ABC defines the contract for RDF extraction and mention mapping. +The resolution service layer depends only on this port, not on concrete +implementations. This enables testing with different RDF formats and +swapping extraction strategies without changing service logic. +""" + +from abc import ABC, abstractmethod + +from erspec.models.core import EntityMention + +from ere.models.resolver import Mention + + +class RDFMapper(ABC): + """ + Port: abstract interface for RDF extraction and entity mention mapping. + + Responsibilities: + - Parse RDF content (Turtle, RDF/XML, etc.) + - Extract entity attributes + - Map erspec EntityMention to domain Mention + """ + + @abstractmethod + def map_entity_mention_to_domain(self, entity_mention: EntityMention) -> Mention: + """ + Map EntityMention (erspec) to Mention (domain). + + Performs RDF parsing and attribute extraction per configuration. + + Args: + entity_mention: EntityMention with identifiedBy and content (RDF). + + Returns: + Mention: Domain object with id and attributes. + + Raises: + ValueError: If RDF parsing fails or entity type is unknown. + """ diff --git a/src/ere/adapters/redis_client.py b/src/ere/adapters/redis_client.py new file mode 100644 index 0000000..65c86b3 --- /dev/null +++ b/src/ere/adapters/redis_client.py @@ -0,0 +1,65 @@ +"""Redis connection configuration and factory for the ERE service.""" + +import logging +import os +from dataclasses import dataclass + +import redis + +log = logging.getLogger(__name__) + + +@dataclass +class RedisConnectionConfig: + """Holds Redis connection parameters and creates the sync client.""" + + host: str + port: int + db: int + password: str | None = None + tls: bool = False + + @classmethod + def from_env(cls) -> "RedisConnectionConfig": + """Build config from environment variables. + + Reads REDIS_HOST, REDIS_PORT, REDIS_DB, REDIS_PASSWORD, REDIS_TLS. + All have sensible defaults so the service starts without any configuration. + + Returns: + RedisConnectionConfig populated from the environment. + """ + return cls( + host=os.environ.get("REDIS_HOST", "localhost"), + port=int(os.environ.get("REDIS_PORT", "6379")), + db=int(os.environ.get("REDIS_DB", "0")), + password=os.environ.get("REDIS_PASSWORD"), + tls=os.environ.get("REDIS_TLS", "false").lower() == "true", + ) + + def create_client(self) -> redis.Redis: + """Create and return a sync Redis client for this configuration. + + Returns: + A redis.Redis instance ready for use. + """ + log.info( + "Connecting to Redis: host=%s, port=%d, db=%d, tls=%s", + self.host, + self.port, + self.db, + self.tls, + ) + return redis.Redis( + host=self.host, + port=self.port, + db=self.db, + password=self.password, + ssl=self.tls, + decode_responses=False, + ) + + def __str__(self) -> str: + return ( + f'RedisConnectionConfig ( host: "{self.host}", port: "{self.port}", db: "{self.db}", tls: "{self.tls}" )' + ) diff --git a/src/ere/adapters/repositories.py b/src/ere/adapters/repositories.py new file mode 100644 index 0000000..2a99e6d --- /dev/null +++ b/src/ere/adapters/repositories.py @@ -0,0 +1,169 @@ +"""Repository port interfaces (abstract base classes) for data persistence. + +These ABCs define what infrastructure the entity resolution algorithm needs +for persisting mentions, similarities, and cluster assignments. +The resolver algorithm (EntityResolver) depends only on these ports, not on +concrete implementations. This enables testing with in-memory stubs and +swapping infrastructure without changing resolver logic. +""" + +from abc import ABC, abstractmethod + +from ere.models.resolver import ( + ClusterId, + ClusterMembership, + Mention, + MentionId, + MentionLink, +) + + +class MentionRepository(ABC): + """ + Port: persistence layer for mentions (entity records). + + Responsibilities: + - Save new mentions + - Retrieve all mentions for introspection + - Count total mentions + """ + + @abstractmethod + def save(self, mention: Mention) -> None: + """ + Persist a mention to storage. + + Args: + mention: The Mention to persist. + """ + + @abstractmethod + def load_all(self) -> list[Mention]: + """ + Retrieve all persisted mentions. + + Returns: + List of all Mention objects. + """ + + @abstractmethod + def count(self) -> int: + """ + Return the total number of mentions in storage. + + Returns: + Non-negative integer count. + """ + + @abstractmethod + def find_by_id(self, mention_id: MentionId) -> Mention | None: + """ + Retrieve a single mention by ID. + + Args: + mention_id: The MentionId to look up. + + Returns: + The Mention object if found, None otherwise. + """ + + +class SimilarityRepository(ABC): + """ + Port: persistence layer for pairwise mention similarities. + + Responsibilities: + - Save similarity scores (mention-links) + - Retrieve links for a given mention + - Count total links + """ + + @abstractmethod + def save_all(self, links: list[MentionLink]) -> None: + """ + Persist multiple mention-links (similarity scores). + + Args: + links: List of MentionLink objects to save. + """ + + @abstractmethod + def count(self) -> int: + """ + Return the total number of mention-links in storage. + + Returns: + Non-negative integer count. + """ + + @abstractmethod + def find_for(self, mention_id: MentionId) -> list[MentionLink]: + """ + Retrieve all mention-links involving the given mention. + + Returns all links where this mention appears on either side + (left_id or right_id). + + Note: N+1 pattern. The DuckDB adapter can override this + to delegate to an efficient SQL JOIN; the service sees no difference. + + Args: + mention_id: The MentionId to find links for. + + Returns: + List of MentionLink objects (may be empty). + """ + + +class ClusterRepository(ABC): + """ + Port: persistence layer for cluster membership. + + Responsibilities: + - Save cluster assignments (mention -> cluster) + - Look up which cluster a mention belongs to + - Retrieve full membership mappings for introspection + """ + + @abstractmethod + def save(self, membership: ClusterMembership) -> None: + """ + Persist a cluster membership assignment. + + Args: + membership: ClusterMembership object (mention_id -> cluster_id). + """ + + @abstractmethod + def find_cluster_of(self, mention_id: MentionId) -> ClusterId: + """ + Look up the cluster a mention belongs to. + + Args: + mention_id: The MentionId to look up. + + Returns: + The ClusterId this mention is assigned to. + + Raises: + KeyError: If the mention has no cluster assignment. + """ + + @abstractmethod + def count(self) -> int: + """ + Return the total number of cluster assignments in storage. + + Returns: + Non-negative integer count. + """ + + @abstractmethod + def get_all_memberships(self) -> dict[ClusterId, list[MentionId]]: + """ + Retrieve the full cluster membership mapping. + + Returns: + Dict mapping ClusterId -> list of MentionIds in that cluster, + sorted for determinism. + """ diff --git a/src/ere/adapters/splink_linker_impl.py b/src/ere/adapters/splink_linker_impl.py new file mode 100644 index 0000000..283432a --- /dev/null +++ b/src/ere/adapters/splink_linker_impl.py @@ -0,0 +1,659 @@ +"""Splink-backed similarity linker adapter (concrete implementation of SimilarityLinker port).""" + +from __future__ import annotations + +import logging +import threading + +import duckdb +import pandas as pd +from splink import Linker, SettingsCreator, block_on +import splink.comparison_library as cl +from splink.backends.duckdb import DuckDBAPI + +from ere.models.resolver import Mention, MentionId, MentionLink +from ere.models.ports.linker import SimilarityLinker + +log = logging.getLogger(__name__) + + +def build_tf_df(mentions: list[Mention], entity_fields: list[str]) -> pd.DataFrame: + """ + Convert a list of Mention objects to a TF DataFrame suitable for Splink's initial_df. + + Empty list produces a zero-row DataFrame with pd.StringDtype() columns (required to avoid + DuckDB integer-inference bug on empty DataFrames). + + Args: + mentions: List of Mention objects to include in the search space. + entity_fields: List of field names to extract from mentions (e.g. ["legal_name", "country_code"]). + + Returns: + DataFrame with columns: mention_id, entity_fields..., __splink_salt. + """ + cols = ["mention_id"] + entity_fields + + if not mentions: + # Empty DataFrame: use pd.StringDtype() to avoid DuckDB integer-inference bug + schema = {c: pd.array([], dtype=pd.StringDtype()) for c in cols} + schema["__splink_salt"] = pd.array([], dtype="float64") + return pd.DataFrame(schema) + + # Non-empty: build from mention data + rows = [] + for mention in mentions: + flat_dict = mention.to_flat_dict() + row = { + "mention_id": flat_dict["mention_id"], + **{ + f: flat_dict.get(f) or "" for f in entity_fields + }, # Convert None to empty string + "__splink_salt": 0.5, + } + rows.append(row) + + df = pd.DataFrame(rows) + # Explicitly cast all entity field columns to StringDtype to prevent DuckDB type inference issues + for col in entity_fields: + if col in df.columns: + df[col] = df[col].astype(pd.StringDtype()) + + return df + + +class SpLinkSimilarityLinker(SimilarityLinker): + """ + Splink-backed implementation of SimilarityLinker port. + + Wraps Splink's Linker and maintains: + - _splink_con: in-memory DuckDB connection (Splink temporary tables only) + - _db_api: DuckDBAPI for Splink operations + - _tf_df: in-memory DataFrame (search space of registered mentions) + - _linker: Splink Linker instance + + Supports warm starts via initial_df parameter and incremental registration of new mentions. + """ + + def __init__( + self, + entity_fields: list[str], + config: dict, + initial_df: pd.DataFrame | None = None, + ) -> None: + """ + Initialize the Splink linker. + + Args: + entity_fields: List of field names (e.g. ["legal_name", "country_code"]). + config: Full resolver configuration dict (needs match_weight_threshold and splink section). + initial_df: Pre-built TF DataFrame for warm starts; None means fresh (empty) start. + """ + self._entity_fields = entity_fields + self._config = config + self._match_weight_threshold = config.get("match_weight_threshold", -10) + + # In-memory connection for Splink operations (avoids file I/O) + self._splink_con = duckdb.connect() + self._db_api = DuckDBAPI(connection=self._splink_con) + + # Initialize TF DataFrame from parameter or empty + if initial_df is not None: + self._tf_df = initial_df.copy() + else: + self._tf_df = build_tf_df([], entity_fields) + + # Create and initialize Splink linker + settings = self._build_settings() + self._linker = Linker(self._tf_df, settings, db_api=self._db_api) + # Always register even when empty so Splink's cache has correct schema + self._linker.table_management.register_table_input_nodes_concat_with_tf( + self._tf_df, overwrite=True + ) + + # Apply cold-start parameters (before training) + self._apply_cold_start_params() + + # Threading synchronization for safe linker swaps during training + self._linker_swap_lock = threading.Lock() + self._training_in_progress = threading.Event() + + def find_matches(self, mention: Mention) -> list[MentionLink]: + """ + Score a mention against previously registered mentions. + + Returns all mention-links above match_weight_threshold (including below-threshold + links needed for candidate discovery). + + Filters self-links (left_id == right_id) which can occur during warm-start + when the mention already exists in the search space. + + Args: + mention: The Mention to score against the search space. + + Returns: + List of MentionLink objects (empty if no matches or search space is empty). + """ + # Grab a local reference to the linker under lock to ensure we don't hold + # the lock while Splink is running (which could block training threads). + with self._linker_swap_lock: + linker = self._linker + + # Log mention data being sent to Splink + mention_dict = mention.to_flat_dict() + log.trace( + "find_matches: Comparing mention %s with %d records in search space. " + "Mention data: %s, Blocking rules: %s, Match weight threshold: %.2f", + mention.id.value, + len(self._tf_df), + mention_dict, + [str(r) for r in self._get_blocking_rules()], + self._match_weight_threshold, + ) + + # Convert None values to empty strings to prevent DuckDB type inference issues + # (None values can be inferred as INTEGER, causing type mismatches in comparisons) + mention_dict = {k: (v or "") for k, v in mention_dict.items()} + + # Splink's find_matches_to_new_records expects a list of dicts + df = linker.inference.find_matches_to_new_records( + [mention_dict], + blocking_rules=self._get_blocking_rules(), + match_weight_threshold=self._match_weight_threshold, + ).as_pandas_dataframe() + + if df.empty: + log.trace( + "find_matches: No matches found for mention %s (search space empty or no matches above threshold)", + mention.id.value, + ) + return [] + + log.trace( + "find_matches: Splink returned %d matches for mention %s. Available columns: %s", + len(df), + mention.id.value, + list(df.columns), + ) + + # Build MentionLink objects, filtering self-links + links = [] + for idx, row in df.iterrows(): + left_id = MentionId(value=str(row["mention_id_l"])) + right_id = MentionId(value=str(row["mention_id_r"])) + score = float(row["match_probability"]) + + # Skip self-links (can occur in warm-start scenarios) + if left_id == right_id: + log.trace( + "find_matches: Skipping self-link for mention %s", + mention.id.value, + ) + continue + + # Log ALL row data for all pairs (critical for debugging the two-score bug) + log.trace( + "find_matches: Row %d - Mention %s vs %s: ALL DATA: %s", + idx, + left_id.value[:16], + right_id.value[:16], + dict(row), + ) + + # Extract detailed comparison scores + # FIXME to be deleted + jw_score = row.get("jaro_winkler_legal_name", None) + country_match = row.get("exact_match_country_code", None) + match_weight = row.get("match_weight", None) + + log.trace( + "find_matches: Mention %s vs %s: " + "match_probability=%.6f, match_weight=%.4f, " + "jaro_winkler_legal_name=%s, exact_match_country_code=%s", + left_id.value[:16], + right_id.value[:16], + score, + float(match_weight) if match_weight else 0.0, + jw_score, + country_match, + ) + + links.append(MentionLink(left_id=left_id, right_id=right_id, score=score)) + + log.trace( + "find_matches: Returning %d links for mention %s", + len(links), + mention.id.value, + ) + + return links + + def register_mention(self, mention: Mention) -> None: + """ + Add a mention to the search space for future find_matches() calls. + + Appends the mention to the TF DataFrame and re-registers it with Splink. + Uses tf_incremental strategy (append only, no reload from database). + + Args: + mention: The Mention to add to the search space. + """ + flat_dict = mention.to_flat_dict() + + log.trace( + "register_mention: Adding mention %s to search space. Data: %s. " + "Current search space size: %d", + mention.id.value, + flat_dict, + len(self._tf_df), + ) + + # Build new row with same schema as _tf_df + new_row = pd.DataFrame( + [ + { + "mention_id": flat_dict["mention_id"], + **{f: flat_dict.get(f) for f in self._entity_fields}, + "__splink_salt": 0.5, + } + ] + ) + + # Cast string columns to pd.StringDtype() to prevent type drift on None values + for col in self._entity_fields: + if col in new_row.columns: + new_row[col] = new_row[col].astype(pd.StringDtype()) + + # Append to search space + self._tf_df = pd.concat([self._tf_df, new_row], ignore_index=True) + + log.trace( + "register_mention: Mention %s registered. New search space size: %d", + mention.id.value, + len(self._tf_df), + ) + + # Re-register with Splink + self._linker.table_management.register_table_input_nodes_concat_with_tf( + self._tf_df, overwrite=True + ) + + def train(self) -> None: + """ + Estimate model parameters via EM (non-blocking, thread-safe). + + Safe to call multiple times (retraining is idempotent). Prevents concurrent + training runs via _training_in_progress event. + + Uses copy-then-swap pattern: snapshots current TF DataFrame, trains on a new + Linker instance, then swaps under lock. This allows find_matches() calls to + proceed with the current linker while training happens asynchronously. + + Training failures (e.g., insufficient data for convergence) are caught silently, + leaving cold-start defaults intact. + """ + # Prevent concurrent training runs + if self._training_in_progress.is_set(): + return + self._training_in_progress.set() + try: + self._train_safe() + finally: + self._training_in_progress.clear() + + # ------------------------------------------------------------------ + # Private helpers + # ------------------------------------------------------------------ + + def _get_blocking_rules(self) -> list: + """Build Splink blocking rule objects from config.""" + rules = [] + for rule in self._config["splink"]["blocking_rules"]: + fields = rule if isinstance(rule, list) else [rule] + rules.append(block_on(*fields)) + return rules + + def _build_settings(self) -> SettingsCreator: + """Translate the config dict into a Splink SettingsCreator.""" + splink_cfg = self._config["splink"] + + log.trace( + "_build_settings: Building Splink settings. Entity fields: %s", + self._entity_fields, + ) + + comparisons = [] + for comp in splink_cfg["comparisons"]: + if comp["type"] == "jaro_winkler": + thresholds = comp.get("thresholds", [0.9, 0.8]) + log.trace( + "_build_settings: Adding JaroWinkler comparison on field '%s' with thresholds %s", + comp["field"], + thresholds, + ) + comparisons.append( + cl.JaroWinklerAtThresholds(comp["field"], thresholds) + ) + elif comp["type"] == "exact_match": + log.trace( + "_build_settings: Adding ExactMatch comparison on field '%s'", + comp["field"], + ) + comparisons.append(cl.ExactMatch(comp["field"])) + else: + raise ValueError(f"Unknown comparison type: {comp['type']!r}") + + blocking_rules = self._get_blocking_rules() + log.trace( + "_build_settings: Blocking rules: %s", + [str(r) for r in blocking_rules], + ) + + kwargs = { + "link_type": "dedupe_only", + "unique_id_column_name": "mention_id", + "comparisons": comparisons, + "blocking_rules_to_generate_predictions": blocking_rules, + } + prior = self._config["splink"].get("probability_two_random_records_match") + if prior is not None: + kwargs["probability_two_random_records_match"] = prior + log.trace( + "_build_settings: Prior probability (P(match)): %.4f", + prior, + ) + + return SettingsCreator(**kwargs) + + def _get_em_training_rule(self): + """ + Derive the EM training rule from config. + + Uses the first blocking rule, extracting the first field if it's a list + (compound rule). This ensures EM training matches the blocking strategy. + + For config.yaml: first rule is "country_code" → block_on("country_code") + For config_compound.yaml: first rule is [country_code, city] → block_on("country_code") + For config_multirule.yaml: first rule is "country_code" → block_on("country_code") + """ + first_rule = self._config["splink"]["blocking_rules"][0] + em_field = first_rule[0] if isinstance(first_rule, list) else first_rule + return block_on(em_field) + + def _train_safe(self) -> None: + """ + Thread-safe training via copy-then-swap pattern. + + 1. Snapshot the current TF DataFrame (may grow during training). + 2. Create a new Linker on a fresh in-memory DuckDB connection. + 3. Run EM training on the new linker. + 4. Re-register the current (possibly grown) TF DataFrame. + 5. Swap the linker reference under lock. + + Training failures are caught silently, leaving cold-start defaults intact. + """ + try: + # Snapshot current TF DataFrame at training start + tf_df_snapshot = self._tf_df.copy() + mention_count = len(tf_df_snapshot) + + log.info( + "EM training STARTING: %d mentions available for parameter estimation", + mention_count, + ) + + # Create new linker on fresh in-memory connection (no shared state) + splink_con_new = duckdb.connect() + db_api_new = DuckDBAPI(connection=splink_con_new) + settings = self._build_settings() + linker_new = Linker(tf_df_snapshot, settings, db_api=db_api_new) + linker_new.table_management.register_table_input_nodes_concat_with_tf( + tf_df_snapshot, overwrite=True + ) + + # Run EM training on the new linker + log.info("EM training: estimating u-probabilities via random sampling") + linker_new.training.estimate_u_using_random_sampling(max_pairs=1e6) + + log.info( + "EM training: estimating m-probabilities and lambda via EM algorithm" + ) + linker_new.training.estimate_parameters_using_expectation_maximisation( + self._get_em_training_rule(), estimate_without_term_frequencies=True + ) + + # Extract trained parameters for logging (final state confirmation) + self._log_trained_parameters(linker_new) + + # Re-register current TF DataFrame (which may have grown during training) + linker_new.table_management.register_table_input_nodes_concat_with_tf( + self._tf_df, overwrite=True + ) + + # Swap linker reference under lock (held for microseconds only) + with self._linker_swap_lock: + self._linker = linker_new + self._splink_con = splink_con_new + self._db_api = db_api_new + + log.info( + "EM training COMPLETE: Linker updated with trained parameters. " + "This is FINAL STATE (not transient) - model will now use trained parameters for scoring." + ) + + except Exception as e: # pylint: disable=broad-exception-caught # Splink may raise undocumented exception types + # Training failure: silently ignore, cold-start defaults remain active + log.warning( + "EM training FAILED or INCOMPLETE: %s. Model will continue using cold-start parameters. " + "This is FINAL STATE (not transient) - training will be retried if resolve() is called again.", + e, + ) + + def _apply_cold_start_params(self) -> None: + """ + Apply cold-start m/u probability defaults to Splink linker. + + Reads splink.cold_start.comparisons from config and sets m/u probabilities + on each comparison level in the linker's settings object. + + If cold_start section is absent, uses Splink's built-in defaults. + + Skips null levels (Splink's internal null-value handling level). + + INITIALIZATION STATE: Linker starts using these cold-start defaults for scoring. + Once EM training completes, these are replaced with trained parameters. + """ + # Check if cold_start config exists + cold_start_cfg = self._config.get("splink", {}).get("cold_start", {}) + if not cold_start_cfg: + log.info( + "Linker initializing: No cold_start config found, using Splink defaults" + ) + return + + comparisons_cfg = cold_start_cfg.get("comparisons", {}) + if not comparisons_cfg: + log.info( + "Linker initializing: No comparisons config in cold_start, using Splink defaults" + ) + return + + log.info( + "Linker initializing: Applying cold-start parameters from config. " + "These are INITIAL STATE defaults - will be replaced by EM-trained parameters once training completes. " + "Fields: %s", + list(comparisons_cfg.keys()), + ) + + # Iterate through comparison levels and apply m/u probabilities + # pylint: disable=protected-access # Splink exposes no public API for settings introspection + for _, comparison in enumerate(self._linker._settings_obj.comparisons): + # Get the field name from the comparison + field_name = None + if hasattr(comparison, "output_column_name"): + field_name = comparison.output_column_name + elif hasattr(comparison, "_field_names") and comparison._field_names: + field_name = comparison._field_names[0] + # pylint: enable=protected-access + + if field_name not in comparisons_cfg: + continue + + field_cfg = comparisons_cfg[field_name] + + log.trace( + "_apply_cold_start_params: Field '%s' has %d comparison levels", + field_name, + len(comparison.comparison_levels), + ) + + # Collect non-null levels to properly map cold-start probabilities + non_null_levels = [ + (i, level) + for i, level in enumerate(comparison.comparison_levels) + if not (hasattr(level, "is_null_level") and level.is_null_level) + ] + log.trace( + "_apply_cold_start_params: Field '%s' has %d non-null levels: %s", + field_name, + len(non_null_levels), + [i for i, _ in non_null_levels], + ) + + # Apply m-probabilities to non-null levels in order + if "m_probabilities" in field_cfg: + m_probs = field_cfg["m_probabilities"] + for config_idx, m_prob in enumerate(m_probs): + if config_idx < len(non_null_levels): + actual_level_idx, level = non_null_levels[config_idx] + try: + level.m_probability = m_prob + log.trace( + "_apply_cold_start_params: Set %s (actual level %d) m_prob=%.4f", + field_name, + actual_level_idx, + m_prob, + ) + except (AttributeError, ValueError) as e: + # If setting fails, skip this level gracefully + log.trace( + "_apply_cold_start_params: Failed to set m_prob for %s level %d: %s", + field_name, + actual_level_idx, + e, + ) + + # Apply u-probabilities to non-null levels in order + if "u_probabilities" in field_cfg: + u_probs = field_cfg["u_probabilities"] + for config_idx, u_prob in enumerate(u_probs): + if config_idx < len(non_null_levels): + actual_level_idx, level = non_null_levels[config_idx] + try: + level.u_probability = u_prob + log.trace( + "_apply_cold_start_params: Set %s (actual level %d) u_prob=%.4f", + field_name, + actual_level_idx, + u_prob, + ) + except (AttributeError, ValueError) as e: + # If setting fails, skip this level gracefully + log.trace( + "_apply_cold_start_params: Failed to set u_prob for %s level %d: %s", + field_name, + actual_level_idx, + e, + ) + + def _log_trained_parameters(self, linker: Linker) -> None: + """ + Extract and log all trained parameters from a trained Splink linker. + + Displays: + - Fellegi-Sunter prior (lambda): P(match) for any two random records + - m-probabilities: likelihood of observing comparison level when records match + - u-probabilities: likelihood of observing comparison level when records don't match + - Which fields were fully trained vs partially/not trained + + This is called AFTER EM completes, providing visibility into what the model learned. + """ + try: + # Get the Fellegi-Sunter prior (lambda) + prior = None + # pylint: disable=protected-access # Splink exposes no public API for settings introspection + if hasattr(linker._settings_obj, "probability_two_random_records_match"): + prior = linker._settings_obj.probability_two_random_records_match + log.info( + "EM trained parameter: lambda (P(match)) = %.6f", + prior, + ) + + # Iterate through comparisons and extract trained m/u probabilities + for comparison in linker._settings_obj.comparisons: + # Get field name + field_name = None + if hasattr(comparison, "output_column_name"): + field_name = comparison.output_column_name + elif hasattr(comparison, "_field_names") and comparison._field_names: + field_name = comparison._field_names[0] + # pylint: enable=protected-access + + if not field_name: + continue + + log.info( + "EM trained parameters for field '%s':", + field_name, + ) + + # Collect non-null levels + non_null_levels = [ + (i, level) + for i, level in enumerate(comparison.comparison_levels) + if not (hasattr(level, "is_null_level") and level.is_null_level) + ] + + # Log m and u probabilities for each level + for config_idx, (_, level) in enumerate(non_null_levels): + m_prob = None + u_prob = None + trained_m = False + trained_u = False + + # Extract m-probability + if ( + hasattr(level, "m_probability") + and level.m_probability is not None + ): + m_prob = level.m_probability + # Check if it was trained (non-cold-start values have specific patterns) + # Cold-start values are typically set exactly; trained values may vary + trained_m = True + + # Extract u-probability + if ( + hasattr(level, "u_probability") + and level.u_probability is not None + ): + u_prob = level.u_probability + trained_u = True + + # Log level details + level_desc = getattr(level, "label", f"Level {config_idx}") + m_status = "✓ trained" if trained_m else "✗ cold-start" + u_status = "✓ trained" if trained_u else "✗ cold-start" + + log.info( + " Level '%s': m_prob=%.6f (%s), u_prob=%.6f (%s)", + level_desc, + m_prob if m_prob is not None else 0.0, + m_status, + u_prob if u_prob is not None else 0.0, + u_status, + ) + + except Exception as e: # pylint: disable=broad-exception-caught # Splink may raise undocumented exception types + log.warning( + "_log_trained_parameters: Could not extract trained parameters: %s", + e, + ) diff --git a/src/ere/adapters/utils.py b/src/ere/adapters/utils.py new file mode 100644 index 0000000..c1535ae --- /dev/null +++ b/src/ere/adapters/utils.py @@ -0,0 +1,103 @@ +# These are used by get_message_object() to map 'type' fields in JSON representations to +# domain model (LinkML) classes. +# +# TODO: open-closed principle. For now, we don't see much need to extend these +# TODO: move to a utils module +# pylint: disable=C0104 +# +import json + +from linkml_runtime.loaders import JSONLoader + +from erspec.models.ere import ( + EntityMentionResolutionRequest, + EntityMentionResolutionResponse, + EREErrorResponse, + # FullRebuildRequest, # TODO: Not yet implemented in erspec.models.ere + # FullRebuildResponse, # TODO: Not yet implemented in erspec.models.ere + ERERequest, + EREMessage, + EREResponse, +) + +SUPPORTED_REQUEST_CLASSES = { + cls.__name__: cls + for cls in [ + EntityMentionResolutionRequest + ] +} +""" +Explicit list of supported Request classes, used in utilities like :meth:`get_request_from_message`. + +TODO: Refactor according to the open-closed principle. For now, we don't expect many extensions to these +types, so, we keep it simple. + +Note: FullRebuildRequest not yet implemented in erspec; add when available. +""" + +SUPPORTED_RESPONSE_CLASSES = { + cls.__name__: cls + for cls in [ + EntityMentionResolutionResponse, + EREErrorResponse, + ] +} +""" +Explicit list of supported Response classes, used in utilities like :meth:`get_response_from_message`. + +TODO: open-closed principle, see above. + +Note: FullRebuildResponse not yet implemented in erspec; add when available. +""" + +_linkml_loader = JSONLoader() # Just to cache it + + +def get_message_object( + raw_msg: bytes, + supported_classes: dict[str, EREMessage], + character_encoding: str = "utf-8", +) -> EREMessage: + """ + Helper to parse a raw message (bytes) coming from places like a Redis queue into a Request/Response object. + + This parses the initial input into JSON, then it uses the LinkML facilities to create domain model + instances from the JSON. This requires the :param:`supported_classes` dict to map the 'type' field + in the JSON to the corresponding class. + """ + + msg_str = raw_msg.decode(character_encoding) + msg_json = json.loads(msg_str) + + message_type = msg_json.get("type") + if not message_type: + raise ValueError("ERE: message without 'type' field") + + cls = supported_classes.get(message_type) + if not cls: + raise ValueError(f'ERE: unsupported message class: "{message_type}"') + + return _linkml_loader.load_any(source=msg_json, target_class=cls) + + +def get_response_from_message( + raw_msg: bytes, character_encoding: str = "utf-8" +) -> EREResponse: + """ + Helper to parse a raw message (bytes) coming from places like a Redis queue into a Response object. + + This is a simple wrapper around :meth:`get_message_object`. + """ + return get_message_object(raw_msg, SUPPORTED_RESPONSE_CLASSES, character_encoding) + + +def get_request_from_message( + raw_msg: bytes, character_encoding: str = "utf-8" +) -> ERERequest: + """ + Helper to parse a raw message (bytes) coming from places like a Redis queue into a Request object. + + This is a simple wrapper around :meth:`get_message_object`. + """ + + return get_message_object(raw_msg, SUPPORTED_REQUEST_CLASSES, character_encoding) diff --git a/src/ere/entrypoints/__init__.py b/src/ere/entrypoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ere/entrypoints/app.py b/src/ere/entrypoints/app.py new file mode 100644 index 0000000..8b43723 --- /dev/null +++ b/src/ere/entrypoints/app.py @@ -0,0 +1,165 @@ +""" +ERE service launcher — entrypoint for local development & Docker. + +Reads entity resolution requests from a Redis queue, logs them to stdout, +and produces responses back to another Redis queue. + +Configuration is read from environment variables or CLI arguments. + +Environment variables: + ERSYS_REQUEST_QUEUE Redis queue for inbound requests (default: ere_requests) + ERSYS_RESPONSE_QUEUE Redis queue for outbound responses (default: ere_responses) + REDIS_HOST Redis hostname (default: localhost) + REDIS_PORT Redis port (default: 6379) + REDIS_DB Redis DB index (default: 0) + REDIS_PASSWORD Redis authentication password (default: unset) + REDIS_TLS Enable TLS for Redis connection (default: false) + ERE_LOG_LEVEL Python log level name (default: INFO) — supports TRACE + RDF_MAPPING_PATH Path to rdf_mapping.yaml config file + RESOLVER_CONFIG_PATH Path to resolver.yaml config file + DUCKDB_PATH Path to persistent DuckDB file (overrides resolver.yaml) + +CLI arguments: + --log-level Python log level name (overrides LOG_LEVEL env var) + --rdf-mapping-path Path to rdf_mapping.yaml config file + --resolver-config-path Path to resolver.yaml config file +""" + +import argparse +import logging +import os +import signal +import sys + +from ere.adapters.factories import build_rdf_mapper +from ere.adapters.redis_client import RedisConnectionConfig +from ere.entrypoints.queue_worker import RedisQueueWorker +from ere.services.factories import ( + build_entity_resolver, + build_entity_resolution_service, +) +from ere.utils.logging import configure_logging + +log = logging.getLogger(__name__) + + +def main() -> None: + """Main entry point: orchestrate service setup and run queue worker.""" + # Parse CLI arguments + parser = argparse.ArgumentParser( + description="ERE service: Entity Resolution Engine" + ) + parser.add_argument( + "--log-level", + default=None, + help="Python log level name (DEBUG, INFO, WARNING, ERROR, CRITICAL, TRACE)", + ) + parser.add_argument( + "--rdf-mapping-path", + default=None, + help="Path to rdf_mapping.yaml config file", + ) + parser.add_argument( + "--resolver-config-path", + default=None, + help="Path to resolver.yaml config file", + ) + args = parser.parse_args() + + configure_logging(log_level=args.log_level) + log.info("ERE service starting") + + # Read configuration from environment or CLI + redis_config = RedisConnectionConfig.from_env() + request_queue = os.environ.get("ERSYS_REQUEST_QUEUE", "ere_requests") + response_queue = os.environ.get("ERSYS_RESPONSE_QUEUE", "ere_responses") + + # Config file paths: CLI takes precedence over environment + rdf_mapping_path = args.rdf_mapping_path or os.environ.get("RDF_MAPPING_PATH") + resolver_config_path = args.resolver_config_path or os.environ.get( + "RESOLVER_CONFIG_PATH" + ) + duckdb_path = os.environ.get("DUCKDB_PATH") + + log.info( + "Configuration: redis=%s:%d/%d, tls=%s, request_queue=%s, response_queue=%s", + redis_config.host, + redis_config.port, + redis_config.db, + redis_config.tls, + request_queue, + response_queue, + ) + log.info( + "Config paths: rdf_mapping=%s, resolver_config=%s", + rdf_mapping_path or "(default)", + resolver_config_path or "(default)", + ) + + # Connect to Redis + try: + client = redis_config.create_client() + client.ping() + log.info("Connected to Redis") + except Exception: # pylint: disable=broad-exception-caught + log.exception("Failed to connect to Redis") + sys.exit(1) + + # Build resolver, mapper, and service once before the loop + resolver = None + try: + log.info("Building entity resolution components") + resolver = build_entity_resolver( + resolver_config_path=resolver_config_path, + duckdb_path=duckdb_path, + ) + mapper = build_rdf_mapper(rdf_mapping_path=rdf_mapping_path) + service = build_entity_resolution_service(resolver, mapper) + log.info("Entity resolution service ready") + except Exception: # pylint: disable=broad-exception-caught + log.exception("Failed to build entity resolution service") + sys.exit(1) + + # Create queue worker + worker = RedisQueueWorker( + redis_client=client, + entity_resolution_service=service, + request_queue=request_queue, + response_queue=response_queue, + ) + + # Set up signal handling for graceful shutdown + running = True + + def _handle_shutdown(sig, _frame): + nonlocal running + log.info("Received signal %s — stopping service", sig) + running = False + + signal.signal(signal.SIGTERM, _handle_shutdown) + signal.signal(signal.SIGINT, _handle_shutdown) + + # Main service loop + log.info("ERE service ready, listening for requests") + try: + while running: + worker.process_single_message() + except KeyboardInterrupt: + log.info("Service interrupted") + except Exception as e: # pylint: disable=broad-exception-caught + log.exception("Unexpected error in service loop: %s", e) + finally: + # Close DuckDB connection if it was created + if resolver is not None: + # Access the underlying connection through the repositories + # TODO: expose via public API + mention_repo = resolver._mention_repo # pylint: disable=protected-access + if hasattr(mention_repo, "_con"): + mention_repo._con.close() # pylint: disable=protected-access + log.info("DuckDB connection closed") + client.close() + log.info("ERE service stopped") + + +if __name__ == "__main__": + main() diff --git a/src/ere/entrypoints/queue_worker.py b/src/ere/entrypoints/queue_worker.py new file mode 100644 index 0000000..30029e5 --- /dev/null +++ b/src/ere/entrypoints/queue_worker.py @@ -0,0 +1,104 @@ +"""Redis queue entrypoint driver for entity resolution requests.""" + +import json +import logging +from datetime import datetime, timezone + +from linkml_runtime.dumpers import JSONDumper +from erspec.models.ere import EREErrorResponse, EREResponse + +from ere.adapters.utils import get_request_from_message +from ere.services.entity_resolution_service import EntityResolutionService + +log = logging.getLogger(__name__) + + +class RedisQueueWorker: + """Entrypoint: Process entity resolution requests from Redis queue. + + Acts as a driver between Redis infrastructure and the service layer. + Dependency injection enables testing with mock Redis and services. + """ + + def __init__( # pylint: disable=too-many-positional-arguments # redis, service, 3 queue config params; no natural grouping + self, + redis_client, + entity_resolution_service: EntityResolutionService, + request_queue: str = "ere_requests", + response_queue: str = "ere_responses", + queue_timeout: int = 1, + ): + """Initialize worker with dependencies.""" + self.redis_client = redis_client + self.service = entity_resolution_service + self.request_queue = request_queue + self.response_queue = response_queue + self.queue_timeout = queue_timeout + self._dumper = JSONDumper() + + def process_single_message(self) -> bool: + """ + Process one message from request queue. + + Returns: + True if a message was processed, False if timeout. + + Raises: + Exception: Propagates connection errors. + """ + # Wait for a request + queue_message = self.redis_client.brpop( + self.request_queue, timeout=self.queue_timeout + ) + if not queue_message: + return False # Timeout + + _, raw_msg = queue_message + + # Decode and log + request_str = raw_msg.decode("utf-8") + log.info("Received request: %s", request_str) + + # Try to extract request ID from raw message for error responses + request_id = "unknown" + try: + msg_json = json.loads(request_str) + request_id = msg_json.get("ere_request_id", "unknown") + except Exception: # pylint: disable=broad-exception-caught + pass # If JSON parse fails, we'll use "unknown" in error response + + # Parse and process + try: + request = get_request_from_message(raw_msg) + response = self.service.process_request(request) + except Exception as e: # pylint: disable=broad-exception-caught + log.exception("Failed to parse or process request") + response = self._build_error_response(str(e), request_id) + + # Send response + self._send_response(response) + return True + + def _send_response(self, response: EREResponse) -> None: + """Serialize and push response to queue.""" + response_str = self._dumper.dumps(response) + try: + self.redis_client.lpush(self.response_queue, response_str) + request_id = getattr(response, "ere_request_id", "unknown") + log.info("Sent response for request_id=%s", request_id) + except Exception: # pylint: disable=broad-exception-caught + log.exception("Failed to send response") + + @staticmethod + def _build_error_response( + error_detail: str, ere_request_id: str = "unknown" + ) -> EREErrorResponse: + """Build error response for request processing failures.""" + log.error("Building error response: %s", error_detail) + return EREErrorResponse( + ere_request_id=ere_request_id, + error_type="ProcessingError", + error_title="Request processing error", + error_detail=error_detail, + timestamp=datetime.now(timezone.utc), + ) diff --git a/src/ere/models/__init__.py b/src/ere/models/__init__.py new file mode 100644 index 0000000..07deaf3 --- /dev/null +++ b/src/ere/models/__init__.py @@ -0,0 +1,6 @@ +"""ERE domain models: resolver-specific concepts.""" + +from . import resolver +from .exceptions import ConflictError + +__all__ = ["resolver", "ConflictError"] diff --git a/src/ere/models/exceptions.py b/src/ere/models/exceptions.py new file mode 100644 index 0000000..2d648d4 --- /dev/null +++ b/src/ere/models/exceptions.py @@ -0,0 +1,16 @@ +"""Domain exceptions for entity resolution.""" + + +class ConflictError(Exception): + """Raised when the same mention_id is submitted with different content.""" + + def __init__( + self, mention_id: str, existing_attributes: dict, incoming_attributes: dict + ): + super().__init__( + f"Mention '{mention_id}' was already resolved with different content. " + f"Existing: {existing_attributes!r}, Incoming: {incoming_attributes!r}" + ) + self.mention_id = mention_id + self.existing_attributes = existing_attributes + self.incoming_attributes = incoming_attributes diff --git a/src/ere/models/ports/__init__.py b/src/ere/models/ports/__init__.py new file mode 100644 index 0000000..76c815f --- /dev/null +++ b/src/ere/models/ports/__init__.py @@ -0,0 +1 @@ +"""Port interfaces for external dependencies (infrastructure boundaries).""" diff --git a/src/ere/models/ports/linker.py b/src/ere/models/ports/linker.py new file mode 100644 index 0000000..724a5b0 --- /dev/null +++ b/src/ere/models/ports/linker.py @@ -0,0 +1,60 @@ +"""Similarity linker port interface (abstract base class). + +This ABC defines the external dependency for pairwise similarity scoring +(e.g. Splink). The resolver algorithm (EntityResolver) depends only on this +port, not on concrete implementations. This enables testing with stub linkers +and swapping the matching algorithm without changing resolver logic. +""" + +from abc import ABC, abstractmethod + +from ere.models.resolver import Mention, MentionLink + + +class SimilarityLinker(ABC): + """ + Port: external dependency for pairwise similarity scoring (e.g. Splink). + + Responsibilities: + - Score a new mention against previously registered mentions + - Train the scoring model (EM, estimate parameters) + - Maintain the search space of mention records + """ + + @abstractmethod + def find_matches(self, mention: Mention) -> list[MentionLink]: + """ + Score a mention against previously registered mentions. + + Returns all mention-links (pairs) above match_weight_threshold, + regardless of cluster threshold. Below-threshold links are included + so they can be used for candidate discovery in genCand(). + + Args: + mention: The Mention to score against the search space. + + Returns: + List of MentionLink objects. Empty if no candidates exist or + all pairs are below match_weight_threshold. + """ + + @abstractmethod + def register_mention(self, mention: Mention) -> None: + """ + Add a mention to the search space for future find_matches() calls. + + After this call, future find_matches() invocations will include this + mention as a candidate for scoring. + + Args: + mention: The Mention to add to the search space. + """ + + @abstractmethod + def train(self) -> None: + """ + Estimate model parameters via EM or other training algorithm. + + Safe to call multiple times (retraining is idempotent). + Implementations handle insufficient data gracefully (e.g., via cold-start defaults). + """ diff --git a/src/ere/models/resolver/__init__.py b/src/ere/models/resolver/__init__.py new file mode 100644 index 0000000..cc9a2fb --- /dev/null +++ b/src/ere/models/resolver/__init__.py @@ -0,0 +1,18 @@ +"""Domain model: named, typed concepts for entity resolution.""" + +from .ids import ClusterId, MentionId +from .mention import Mention +from .similarity import MentionLink +from .cluster import CandidateCluster, ClusterMembership, ResolutionResult +from .state import ResolverState + +__all__ = [ + "MentionId", + "ClusterId", + "Mention", + "MentionLink", + "ClusterMembership", + "CandidateCluster", + "ResolutionResult", + "ResolverState", +] diff --git a/src/ere/models/resolver/cluster.py b/src/ere/models/resolver/cluster.py new file mode 100644 index 0000000..9a840e9 --- /dev/null +++ b/src/ere/models/resolver/cluster.py @@ -0,0 +1,72 @@ +"""Cluster domain models: membership, candidates, and resolution results.""" + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, field_validator + +from .ids import ClusterId, MentionId + + +class ClusterMembership(BaseModel): + """ + One mention's assignment to one cluster. + + One record per mention in the resolver's state. + """ + + model_config = ConfigDict(frozen=True) + + mention_id: MentionId + cluster_id: ClusterId + + +class CandidateCluster(BaseModel): + """ + A cluster reference in the resolution output, with its score. + + Represents the algorithm's confidence that a mention belongs to this cluster. + """ + + model_config = ConfigDict(frozen=True) + + cluster_id: ClusterId + score: float + + def as_tuple(self) -> tuple[str, float]: + """Return backward-compatible tuple form: (cluster_id_str, score).""" + return (self.cluster_id.value, self.score) + + +class ResolutionResult(BaseModel): + """ + Non-empty, descending-score ranked list of CandidateCluster references. + + Pruned to top-N by the service layer before construction. + + Invariant: len(candidates) >= 1 (enforced at construction time). + """ + + model_config = ConfigDict(frozen=True) + + candidates: tuple[CandidateCluster, ...] + + @field_validator("candidates") + @classmethod + def _must_be_non_empty(cls, v: tuple) -> tuple: + """Enforce that candidates list is non-empty.""" + if len(v) == 0: + raise ValueError("ResolutionResult candidates must be non-empty") + return v + + def as_tuples(self) -> list[tuple[str, float]]: + """ + Return backward-compatible list-of-tuples form. + + Current API contract: list[tuple[str, float]]. + """ + return [c.as_tuple() for c in self.candidates] + + @property + def top(self) -> CandidateCluster: + """Return the algorithm's implied best cluster for this mention.""" + return self.candidates[0] diff --git a/src/ere/models/resolver/ids.py b/src/ere/models/resolver/ids.py new file mode 100644 index 0000000..5278fcc --- /dev/null +++ b/src/ere/models/resolver/ids.py @@ -0,0 +1,25 @@ +"""Value-object identifiers for mentions and clusters.""" + +from pydantic import BaseModel, ConfigDict + + +class MentionId(BaseModel): + """Unique identifier for a mention (entity record).""" + + model_config = ConfigDict(frozen=True) + + value: str + + def __str__(self) -> str: + return self.value + + +class ClusterId(BaseModel): + """Identifier for a cluster. Always derived from the MentionId of the founding mention.""" + + model_config = ConfigDict(frozen=True) + + value: str + + def __str__(self) -> str: + return self.value diff --git a/src/ere/models/resolver/mention.py b/src/ere/models/resolver/mention.py new file mode 100644 index 0000000..4e5cd05 --- /dev/null +++ b/src/ere/models/resolver/mention.py @@ -0,0 +1,53 @@ +"""Mention domain model: an entity record being resolved.""" + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, model_validator + +from .ids import MentionId + + +class Mention(BaseModel): + """ + A mention: the entity being resolved. + + Has an ID and a flat dict of attributes (legal_name, country_code, city, ...). + Accepts both structured form and legacy flat-dict form for backward compatibility. + """ + + model_config = ConfigDict(frozen=True) + + id: MentionId + attributes: dict[str, str | None] + + @model_validator(mode="before") + @classmethod + def _from_flat_dict(cls, raw_input: object) -> object: + """ + Accept the legacy flat-dict format used throughout the codebase: + {"mention_id": "m1", "legal_name": "Acme", "country_code": "US"} + and convert to the structured form expected by the model. + """ + if ( + isinstance(raw_input, dict) + and "mention_id" in raw_input + and "id" not in raw_input + ): + return { + "id": MentionId(value=raw_input["mention_id"]), + "attributes": {k: v for k, v in raw_input.items() if k != "mention_id"}, + } + return raw_input + + def get(self, key: str) -> str | None: + """Get an attribute value by key, returning None if absent.""" + return self.attributes.get(key) + + def to_flat_dict(self) -> dict: + """ + Return a flat dict representation of the mention. + + Reconstructs the legacy format: {"mention_id": "m1", ...attributes}. + Used by adapters and external systems that need a flat representation. + """ + return {"mention_id": self.id.value, **self.attributes} diff --git a/src/ere/models/resolver/similarity.py b/src/ere/models/resolver/similarity.py new file mode 100644 index 0000000..03d569b --- /dev/null +++ b/src/ere/models/resolver/similarity.py @@ -0,0 +1,47 @@ +"""Similarity domain model: pairwise mention links.""" + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, model_validator + +from .ids import MentionId + + +class MentionLink(BaseModel): + """ + A pairwise similarity score between two mentions. + + Stored regardless of threshold - below-threshold links are used by genCand() + to discover candidate clusters. + + Invariant: left_id != right_id (enforced at construction time). + """ + + model_config = ConfigDict(frozen=True) + + left_id: MentionId + right_id: MentionId + score: float + + @model_validator(mode="after") + def _validate_ids_differ(self) -> MentionLink: + """Enforce that left and right mentions are different.""" + if self.left_id == self.right_id: + raise ValueError("left_id and right_id must differ") + return self + + def other(self, from_id: MentionId) -> MentionId: + """ + Return the mention on the other side of this link. + + Raises ValueError if from_id is not part of this link. + """ + if from_id == self.left_id: + return self.right_id + if from_id == self.right_id: + return self.left_id + raise ValueError(f"{from_id!r} is not part of this link") + + def meets_threshold(self, threshold: float) -> bool: + """Check if this link's score meets or exceeds the threshold.""" + return self.score >= threshold diff --git a/src/ere/models/resolver/state.py b/src/ere/models/resolver/state.py new file mode 100644 index 0000000..85cff53 --- /dev/null +++ b/src/ere/models/resolver/state.py @@ -0,0 +1,44 @@ +"""Resolver state domain model: introspection snapshot.""" + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict + +from .ids import ClusterId, MentionId + + +class ResolverState(BaseModel): + """ + Introspection snapshot returned by EntityResolver.state(). + + Provides high-level counts and detailed cluster membership mapping. + """ + + model_config = ConfigDict(frozen=True) + + mention_count: int + similarity_count: int + cluster_count: int + cluster_membership: dict[ClusterId, list[MentionId]] + + def as_dict(self) -> dict: + """ + Return backward-compatible dict form. + + Current state() API contract: + { + "mentions": int, + "similarities": int, + "clusters": int, + "cluster_membership": {cluster_id_str: [mention_id_str, ...], ...} + } + """ + return { + "mentions": self.mention_count, + "similarities": self.similarity_count, + "clusters": self.cluster_count, + "cluster_membership": { + k.value: [m.value for m in v] + for k, v in self.cluster_membership.items() + }, + } diff --git a/src/ere/services/__init__.py b/src/ere/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ere/services/entity_resolution_service.py b/src/ere/services/entity_resolution_service.py new file mode 100644 index 0000000..dbc5e36 --- /dev/null +++ b/src/ere/services/entity_resolution_service.py @@ -0,0 +1,506 @@ +"""Main service layer: entity resolution resolver and public API service.""" + +import logging +import threading +from datetime import datetime, timezone + +from erspec.models.core import ClusterReference, EntityMention +from erspec.models.ere import ( + EntityMentionResolutionRequest, + EntityMentionResolutionResponse, + EREErrorResponse, + ERERequest, + EREResponse, +) + +from ere.adapters import AbstractResolver +from ere.adapters.rdf_mapper_port import RDFMapper +from ere.adapters.repositories import ( + ClusterRepository, + MentionRepository, + SimilarityRepository, +) +from ere.models.resolver import ( + CandidateCluster, + ClusterId, + ClusterMembership, + Mention, + MentionId, + MentionLink, + ResolutionResult, + ResolverState, +) +from ere.services.resolver_config import ResolverConfig +from ere.services.linker import SimilarityLinker + +log = logging.getLogger(__name__) + + +class EntityResolver: + """ + Core entity resolution algorithm: orchestration of domain objects via ports. + + The resolver implements the entity resolution algorithm using only domain types + and port interfaces. This enables testing with in-memory stubs and swapping + infrastructure without changing algorithm logic. + + The resolver is stateless - all state is held in repositories and the linker. + """ + + def __init__( # pylint: disable=too-many-positional-arguments # 5 domain dependencies; extracting a container would obscure intent + self, + mention_repo: MentionRepository, + similarity_repo: SimilarityRepository, + cluster_repo: ClusterRepository, + linker: SimilarityLinker, + config: ResolverConfig, + ): + """ + Initialize the entity resolution service. + + Args: + mention_repo: Repository for persisting mentions. + similarity_repo: Repository for persisting mention-links (similarities). + cluster_repo: Repository for persisting cluster membership. + linker: Port for pairwise similarity scoring (e.g. Splink). + config: Resolver configuration (threshold, top_n, etc.). + """ + self._mention_repo = mention_repo + self._similarity_repo = similarity_repo + self._cluster_repo = cluster_repo + self._linker = linker + self._config = config + + # ----------------------------------------------------------------------- + # Core algorithm + # ----------------------------------------------------------------------- + + def resolve(self, mention: Mention) -> ResolutionResult: + """ + Resolve a mention: score against existing mentions, assign to a cluster, + and return ranked cluster references. + + Implements the resolution flow: + 1. Score new mention against existing search space via linker. + 2. Persist all pairwise scores (mention-link graph). + 3. Assign to best-matching cluster (ext) or create singleton (newCl). + 4. Insert mention into search space and repositories. + 5. Return genCand output: ranked (cluster_id, score) pairs. + + Args: + mention: The Mention to resolve. + + Returns: + ResolutionResult: Non-empty, ranked list of CandidateCluster objects, + pruned to top-N. The first entry is the algorithm's + implied best cluster for this mention. + """ + # Step 1: Score mention against existing search space. + # The linker sees mention as-is (not yet persisted), so it can find + # matches without the mention being in the mentions table yet. + links = self._linker.find_matches(mention) + + # Step 2: Persist all pairwise scores into the similarities repository. + if links: + self._similarity_repo.save_all(links) + + # Step 3: Cluster assignment - greedy online, best match only, threshold-gated. + # This implements the greedy online clustering approach: the incoming mention + # is compared only against existing records, and it joins the cluster of the + # single best-scoring match (if that score meets the threshold). No + # retrospective re-clustering is performed. + # + # Consequence: order of arrival matters. This is the fundamental trade-off + # of the online greedy approach. + best_id, best_sim = self._find_best_match(links, mention.id) + + if best_id is not None and best_sim >= self._config.threshold: + # ext: join the cluster of the best match + cluster_id = self._cluster_repo.find_cluster_of(best_id) + log.trace( + "Mention %s assigned to cluster %s (similarity score=%.4f)", + mention.id.value, + cluster_id.value, + best_sim, + ) + else: + # newCl: create a new singleton cluster with this mention's ID + cluster_id = ClusterId(value=mention.id.value) + log.trace("New cluster generated for mention with id=%s", mention.id.value) + + self._cluster_repo.save( + ClusterMembership(mention_id=mention.id, cluster_id=cluster_id) + ) + + # Log cluster contents after assignment + all_memberships = self._cluster_repo.get_all_memberships() + cluster_members = all_memberships.get(cluster_id, []) + member_ids = ", ".join([m.value for m in cluster_members]) + log.trace( + "Cluster %s now contains %d mentions: %s", + cluster_id.value, + len(cluster_members), + member_ids, + ) + + # Step 4: Persist mention and update the linker's search space. + self._mention_repo.save(mention) + self._linker.register_mention(mention) + + # Trigger auto-training if threshold is reached (non-blocking background thread). + count = self._mention_repo.count() + if ( + self._config.auto_train_threshold > 0 + and count == self._config.auto_train_threshold + ): + log.info( + "Auto-training triggered: %d mentions reached (threshold=%d). " + "Starting background EM training thread. Scoring continues with current parameters.", + count, + self._config.auto_train_threshold, + ) + threading.Thread( + target=self._linker.train, daemon=True, name="linker-training" + ).start() + + # Step 5: Return cluster references (non-empty, always top-N). + return self._gen_cand(mention.id) + + def train(self) -> None: + """ + Train the linker model (estimate parameters via EM or other algorithm). + + Safe to call multiple times (retraining is idempotent). + The linker handles insufficient data gracefully (uses cold-start defaults). + """ + self._linker.train() + + def state(self) -> ResolverState: + """ + Return a snapshot of the resolver's persisted state. + + Includes counts for all repositories and current cluster membership mapping. + + Returns: + ResolverState: Immutable snapshot with mention/similarity/cluster counts + and full cluster membership mapping. + """ + return ResolverState( + mention_count=self._mention_repo.count(), + similarity_count=self._similarity_repo.count(), + cluster_count=self._cluster_repo.count(), + cluster_membership=self._cluster_repo.get_all_memberships(), + ) + + def find_cluster_for(self, mention_id: MentionId) -> ResolutionResult | None: + """ + Return stored resolution candidates for a mention, or None if not yet resolved. + + When a mention was already resolved, this re-runs _gen_cand() against the current + state of the similarity table. If new mentions have since been added to the cluster, + the returned scores reflect the updated state - which is the correct behavior for + an idempotent re-query (the cluster assignment is unchanged, only scores may update). + + Used by resolution.py for idempotency: avoids re-running resolve() (which would add + duplicate rows) while still returning a valid, current ResolutionResult. + + Args: + mention_id: The MentionId to look up. + + Returns: + ResolutionResult if the mention was found, None otherwise. + """ + try: + self._cluster_repo.find_cluster_of(mention_id) # KeyError if not found + return self._gen_cand(mention_id) + except KeyError: + return None + + def check_conflict(self, mention: Mention) -> None: + """ + Raise ConflictError if the same mention_id exists with different attributes. + + Called before idempotency check to ensure that re-submissions with different + content are rejected, even if cached in the cluster repo. + + Args: + mention: The Mention being submitted for resolution. + + Raises: + ConflictError: If mention_id already exists with different attributes. + """ + from ere.models.exceptions import ConflictError + + existing = self._mention_repo.find_by_id(mention.id) + if existing is not None and existing.attributes != mention.attributes: + raise ConflictError( + mention_id=mention.id.value, + existing_attributes=existing.attributes, + incoming_attributes=mention.attributes, + ) + + # ----------------------------------------------------------------------- + # Helpers + # ----------------------------------------------------------------------- + + def _find_best_match( + self, links: list[MentionLink], mention_id: MentionId + ) -> tuple[MentionId | None, float]: + """ + Find the highest-scoring match from a list of mention-links. + + Returns: + Tuple of (best_other_id, best_score). If links is empty, + returns (None, 0.0). + """ + if not links: + return None, 0.0 + best = max(links, key=lambda l: l.score) + return best.other(mention_id), best.score + + def _gen_cand(self, mention_id: MentionId) -> ResolutionResult: + """ + Generate cluster references for a mention (genCand from algorithm). + + For each stored mention-link involving this mention, identify the other + mention and look up its cluster. Group by cluster and take the maximum + similarity as the cluster-level score. Always include the mention's own + assigned cluster (with score 0.0 if no link to it exists). Sort descending, + prune to top-N. + + The own cluster is always present because it is the algorithm's actual + cluster assignment for the mention. + + Implementation note: This uses N+1 repository calls (one find_for(), + then N cluster lookups). This is intentional for testability and + separation of concerns. The DuckDB adapter can optimize by + overriding the same port contract with a single SQL JOIN; the service + sees no difference. + + Args: + mention_id: The MentionId to generate candidates for. + + Returns: + ResolutionResult: Non-empty tuple of CandidateCluster objects, + sorted descending by score, pruned to top_n. + Always includes the mention's own cluster. + """ + links = self._similarity_repo.find_for(mention_id) + + # Group by cluster and take the max score per cluster + cluster_scores: dict[ClusterId, float] = {} + for link in links: + other_id = link.other(mention_id) + cid = self._cluster_repo.find_cluster_of(other_id) + cluster_scores[cid] = max(cluster_scores.get(cid, 0.0), link.score) + + # Always include the mention's own assigned cluster + own_cluster_id = self._cluster_repo.find_cluster_of(mention_id) + cluster_scores.setdefault(own_cluster_id, 0.0) + + # Sort by score (descending), prune to top_n, build candidates + sorted_pairs = sorted(cluster_scores.items(), key=lambda x: x[1], reverse=True) + candidates = tuple( + CandidateCluster(cluster_id=cid, score=score) + for cid, score in sorted_pairs[: self._config.top_n] + ) + + return ResolutionResult(candidates=candidates) + + +# ----------------------------------------------------------------------- +# Public resolution API +# ----------------------------------------------------------------------- + + +def resolve_to_result( + entity_mention: EntityMention, + resolver: EntityResolver, + mapper: RDFMapper, +) -> ResolutionResult: + """ + Core resolution pipeline: RDF parsing -> domain mapping -> resolver resolution. + + Args: + entity_mention: EntityMention from erspec. + resolver: EntityResolver instance (core algorithm). + mapper: RDFMapper implementation for entity mention parsing. + + Returns: + ResolutionResult: Domain object with (cluster_id, score) candidates. + + Raises: + ValueError: If RDF parsing fails or entity type is unknown. + """ + mention = mapper.map_entity_mention_to_domain(entity_mention) + + # Log properties after RDF mapping + log.trace( + "Entity resolver will use the following properties of %s: %s", + entity_mention.identifiedBy.request_id, + mention.attributes, + ) + + # Conflict guard: same mention_id, different content → reject + resolver.check_conflict(mention) + + # Idempotency: if already resolved, return current state + cached = resolver.find_cluster_for(mention.id) + if cached is not None: + log.trace("Returning result for already resolved mention: %s", mention.id.value) + return cached + + return resolver.resolve(mention) + + +def resolve_entity_mention( + entity_mention: EntityMention, + resolver: EntityResolver = None, + mapper: RDFMapper = None, +) -> ClusterReference: + """ + Resolve an entity mention to a Cluster (public API - returns top candidate). + + Args: + entity_mention: EntityMention with identifiedBy and content (Turtle RDF). + resolver: EntityResolver instance. If None, raises ValueError. + (In tests, inject the fixture; in production, use build_entity_resolver() factory) + mapper: RDFMapper implementation. If None, raises ValueError. + (In tests, inject the fixture; in production, use build_rdf_mapper() factory) + + Returns: + ClusterReference with cluster_id, confidence_score, similarity_score. + + Raises: + ValueError: If RDF parsing fails, mapping fails, resolver/mapper is None, or entity type is unknown. + """ + if resolver is None: + raise ValueError( + "resolver must be provided (inject EntityResolver fixture in tests, " + "or use build_entity_resolver() factory in production)" + ) + if mapper is None: + raise ValueError( + "mapper must be provided (inject RDFMapper fixture in tests, " + "or use build_rdf_mapper() factory in production)" + ) + + cluster_ref = resolve_to_result(entity_mention, resolver, mapper) + top = cluster_ref.top + + # For singleton founders (no prior mentions), top.score = 0.0. + # 0.0 reflects genuine uncertainty: the cluster is unconfirmed (single member). + return ClusterReference( + cluster_id=top.cluster_id.value, + confidence_score=top.score, + similarity_score=top.score, + ) + + +# ----------------------------------------------------------------------- +# Adapter resolver for pub/sub service +# ----------------------------------------------------------------------- + + +class EntityResolutionService(AbstractResolver): + """ + Public API service for entity resolution via pub/sub request/response. + + Handles EntityMentionResolutionRequest -> EntityMentionResolutionResponse. + Returns EREErrorResponse for unknown request types or resolution errors. + + This service receives a pre-constructed resolver and mapper at initialization + time, avoiding the cost of rebuilding them on every request. + """ + + def __init__(self, resolver: EntityResolver, mapper: RDFMapper): + """ + Initialize the service with injected dependencies. + + Args: + resolver: EntityResolver instance (pre-built core resolver). + mapper: RDFMapper implementation (pre-built). + """ + self._resolver = resolver + self._mapper = mapper + + def process_request(self, request: ERERequest) -> EREResponse: + """ + Process a resolution request and return a response. + + Args: + request: ERERequest (could be EntityMentionResolutionRequest or other type). + + Returns: + EntityMentionResolutionResponse if request is EntityMentionResolutionRequest, + EREErrorResponse for unknown request types or resolution errors. + """ + now = datetime.now(timezone.utc) + + if not isinstance(request, EntityMentionResolutionRequest): + log.error( + "Unsupported request type: %s", + type(request).__name__, + ) + return EREErrorResponse( + ere_request_id=getattr(request, "ere_request_id", "unknown"), + error_type="UnsupportedRequestType", + error_title="Unsupported request type", + error_detail=f"EntityResolutionService does not handle {type(request).__name__}", + timestamp=now, + ) + + try: + entity_mention = request.entity_mention + entity_type = entity_mention.identifiedBy.entity_type + log.trace( + "Mention of type %s submitted for resolution: %s", + entity_type, + entity_mention.identifiedBy.request_id, + ) + + resolution_outcome = resolve_to_result( + entity_mention, self._resolver, self._mapper + ) + + # Log resolution result with candidates + candidate_info = [ + (c.cluster_id.value, c.score, c.score) + for c in resolution_outcome.candidates + ] + log.trace( + "Resolution result for mention %s: %s", + entity_mention.identifiedBy.request_id, + candidate_info, + ) + + candidates = [ + ClusterReference( + cluster_id=c.cluster_id.value, + confidence_score=c.score, + similarity_score=c.score, + ) + for c in resolution_outcome.candidates + ] + return EntityMentionResolutionResponse( + entity_mention_id=entity_mention.identifiedBy, + candidates=candidates, + ere_request_id=request.ere_request_id, + timestamp=now, + ) + except Exception as exc: # pylint: disable=broad-exception-caught + log.exception( + "Resolution error for mention %s", + request.ere_request_id, + ) + return EREErrorResponse( + ere_request_id=request.ere_request_id, + error_type=type(exc).__name__, + error_title="Resolution error", + error_detail=str(exc), + timestamp=now, + ) + + def __call__(self, request: ERERequest) -> EREResponse: + """Make the service callable.""" + return self.process_request(request) diff --git a/src/ere/services/factories.py b/src/ere/services/factories.py new file mode 100644 index 0000000..4550209 --- /dev/null +++ b/src/ere/services/factories.py @@ -0,0 +1,111 @@ +"""Factory functions for service instantiation. + +This module is responsible for constructing entity resolution components with +all their adapter dependencies. It lives in the services layer because it +orchestrates service-level concerns. The service layer receives fully-constructed +instances without knowing the concrete implementation details. +""" + +from pathlib import Path + +import duckdb +import yaml + +from ere.adapters.duckdb_repositories import ( + DuckDBClusterRepository, + DuckDBMentionRepository, + DuckDBSimilarityRepository, +) +from ere.adapters.duckdb_schema import init_schema +from ere.adapters.rdf_mapper_port import RDFMapper +from ere.adapters.splink_linker_impl import SpLinkSimilarityLinker +from ere.services.entity_resolution_service import ( + EntityResolver, + EntityResolutionService, +) +from ere.services.resolver_config import ResolverConfig + + +def build_entity_resolver( + entity_fields: list[str] = None, + resolver_config_path: str | Path = None, + duckdb_path: str = None, +) -> EntityResolver: + """ + Factory: construct EntityResolver with all concrete adapter dependencies. + + This factory instantiates DuckDB repositories and Splink linker, wiring them + together with configuration. The service layer never directly instantiates + these concrete types; it receives them pre-built via dependency injection. + + Args: + entity_fields: Field names for entity attributes (e.g. ["legal_name", "country_code"]). + If None, reads from resolver.yaml config. + resolver_config_path: Path to resolver.yaml config file. + If None, uses default path. + duckdb_path: Path to DuckDB file (overrides resolver.yaml duckdb.path). + If None, uses path from resolver.yaml config. + + Returns: + Fully-constructed EntityResolver with DuckDB backend and Splink linker. + """ + if resolver_config_path is None: + config_path = ( + Path(__file__).parent.parent.parent + / "config" + / "resolver.yaml" + ) + else: + config_path = Path(resolver_config_path) + + with open(config_path, encoding="utf-8") as f: + raw_config = yaml.safe_load(f) + + resolver_config = ResolverConfig.from_dict(raw_config) + + # Use entity_fields from config; parameter overrides config if provided + if entity_fields is None: + entity_fields = resolver_config.entity_fields + + # Create DuckDB connection based on configured type + if resolver_config.duckdb.type == "in-memory": # pylint: disable=no-member # Pydantic model attribute; pylint cannot resolve dynamically + con = duckdb.connect(":memory:") + elif resolver_config.duckdb.type == "persistent": # pylint: disable=no-member # Pydantic model attribute; pylint cannot resolve dynamically + # DUCKDB_PATH env var takes precedence over the passed argument + db_path = duckdb_path or resolver_config.duckdb.path # pylint: disable=no-member # Pydantic model attribute; pylint cannot resolve dynamically + con = duckdb.connect(db_path) + else: + raise ValueError( + f"Invalid duckdb type: {resolver_config.duckdb.type}. " # pylint: disable=no-member # Pydantic model attribute; pylint cannot resolve dynamically + f"Must be 'in-memory' or 'persistent'." + ) + + init_schema(con, entity_fields) + + mention_repo = DuckDBMentionRepository(con, entity_fields) + similarity_repo = DuckDBSimilarityRepository(con) + cluster_repo = DuckDBClusterRepository(con) + linker = SpLinkSimilarityLinker(entity_fields, raw_config) + + return EntityResolver( + mention_repo, similarity_repo, cluster_repo, linker, resolver_config + ) + + +def build_entity_resolution_service( + resolver: EntityResolver, mapper: RDFMapper +) -> EntityResolutionService: + """ + Factory: construct EntityResolutionService with pre-built resolver and mapper. + + This factory wires the core resolver and RDF mapper together into the public + API service, avoiding repeated instantiation on every request. + + Args: + resolver: EntityResolver instance (pre-built core resolver). + mapper: RDFMapper implementation (pre-built). + + Returns: + Fully-constructed EntityResolutionService ready for request processing. + """ + return EntityResolutionService(resolver, mapper) diff --git a/src/ere/services/linker.py b/src/ere/services/linker.py new file mode 100644 index 0000000..8e6a6e4 --- /dev/null +++ b/src/ere/services/linker.py @@ -0,0 +1,5 @@ +"""Re-export SimilarityLinker port from models for backward compatibility.""" + +from ere.models.ports.linker import SimilarityLinker + +__all__ = ["SimilarityLinker"] diff --git a/src/ere/services/resolver_config.py b/src/ere/services/resolver_config.py new file mode 100644 index 0000000..50b49bb --- /dev/null +++ b/src/ere/services/resolver_config.py @@ -0,0 +1,76 @@ +"""Resolver configuration: typed extraction from YAML.""" + +from pydantic import BaseModel, ConfigDict, Field + + +class DuckDBConfig(BaseModel): + """DuckDB database configuration.""" + + type: str = "in-memory" # "in-memory" or "persistent" + path: str = ( + ":memory:" # Database path: ":memory:" for in-memory, file path for persistent + ) + + +class ResolverConfig(BaseModel): + """ + Typed resolver configuration extracted from YAML dict. + + Attributes: + threshold: Cluster assignment probability cutoff (0.0-1.0). + A mention joins an existing cluster only if match_probability >= threshold. + match_weight_threshold: Splink output pre-filter (log-odds). + Controls which scored pairs are stored in the similarities table. + -10 includes pairs with match_probability >= ~0.001. + top_n: Maximum number of cluster references returned per resolution request. + cache_strategy: Strategy for maintaining Splink search space cache. + Default: "tf_incremental" (incremental cache updates). + auto_train_threshold: Number of mentions at which to trigger background training. + Default: 50 (0 = disabled). + entity_fields: List of entity field names to extract from RDF (e.g. ["legal_name", "country_code"]). + Must match fields defined in rdf_mapping.yaml. + duckdb: DuckDB database configuration (type and path). + Default: in-memory database. + """ + + model_config = ConfigDict(frozen=True) + + threshold: float + match_weight_threshold: float + top_n: int + entity_fields: list[str] + cache_strategy: str = "tf_incremental" + auto_train_threshold: int = 50 + duckdb: DuckDBConfig = Field(default_factory=DuckDBConfig) + + @classmethod + def from_dict(cls, d: dict) -> "ResolverConfig": + """ + Load configuration from YAML-parsed dict. + + Args: + d: Dict with keys: threshold, match_weight_threshold, top_n, entity_fields, + cache_strategy (optional), auto_train_threshold (optional), + duckdb (optional). + + Returns: + ResolverConfig instance. + + Raises: + ValidationError: If required keys are missing or values are invalid. + """ + duckdb_config_dict = d.get("duckdb", {}) + duckdb_config = DuckDBConfig( + type=duckdb_config_dict.get("type", "in-memory"), + path=duckdb_config_dict.get("path", ":memory:"), + ) + + return cls( + threshold=d["threshold"], + match_weight_threshold=d["match_weight_threshold"], + top_n=d["top_n"], + entity_fields=d["entity_fields"], + cache_strategy=d.get("cache_strategy", "tf_incremental"), + auto_train_threshold=d.get("auto_train_threshold", 50), + duckdb=duckdb_config, + ) diff --git a/src/ere/utils/__init__.py b/src/ere/utils/__init__.py new file mode 100644 index 0000000..6b948d3 --- /dev/null +++ b/src/ere/utils/__init__.py @@ -0,0 +1,6 @@ +"""Utilities for ERE.""" +# pylint: disable=C0104 + +from ere.utils.logging import TRACE_LEVEL_NUM, configure_logging + +__all__ = ["TRACE_LEVEL_NUM", "configure_logging"] diff --git a/src/ere/utils/logging.py b/src/ere/utils/logging.py new file mode 100644 index 0000000..70e36a3 --- /dev/null +++ b/src/ere/utils/logging.py @@ -0,0 +1,48 @@ +"""Logging utilities for ERE.""" + +import os +import sys + +import logging + +# Add TRACE level (below DEBUG) +TRACE_LEVEL_NUM = 5 +logging.addLevelName(TRACE_LEVEL_NUM, "TRACE") + + +def _trace(self, message, *args, **kwargs): + """Log at TRACE level.""" + if self.isEnabledFor(TRACE_LEVEL_NUM): + self._log(TRACE_LEVEL_NUM, message, args, **kwargs) # pylint: disable=protected-access + + +# Add trace method to Logger class +logging.Logger.trace = _trace + + +def configure_logging(log_level: str = None) -> None: + """ + Set up logging to stdout with ISO 8601 timestamps. + + Args: + log_level: Log level name (e.g., 'DEBUG', 'INFO', 'TRACE'). + If None, reads from ERE_LOG_LEVEL environment variable (default: INFO). + """ + if log_level is None: + log_level = os.environ.get("ERE_LOG_LEVEL", "INFO").upper() + else: + log_level = log_level.upper() + + # Handle TRACE level + if log_level == "TRACE": + level = TRACE_LEVEL_NUM + else: + level = getattr(logging, log_level, logging.INFO) + + logging.basicConfig( + level=level, + format="%(asctime)s %(levelname)-8s %(name)s %(message)s", + datefmt="%Y-%m-%dT%H:%M:%S", + stream=sys.stdout, + ) + logging.getLogger(__name__).info("Logging configured at level %s", log_level) diff --git a/src/filters/fortify-exclusion.properties b/src/filters/fortify-exclusion.properties new file mode 100644 index 0000000..1db3bd3 --- /dev/null +++ b/src/filters/fortify-exclusion.properties @@ -0,0 +1 @@ +excludePatterns=**/docs/**/*,**/test/**/* diff --git a/src/filters/odc-exclusion.properties b/src/filters/odc-exclusion.properties new file mode 100644 index 0000000..1db3bd3 --- /dev/null +++ b/src/filters/odc-exclusion.properties @@ -0,0 +1 @@ +excludePatterns=**/docs/**/*,**/test/**/* diff --git a/src/infra/.env.example b/src/infra/.env.example new file mode 100644 index 0000000..ea0bb09 --- /dev/null +++ b/src/infra/.env.example @@ -0,0 +1,27 @@ +# ERE local development environment +# Copy to infra/.env and customise: cp infra/.env.example infra/.env +# +# Compatible with the ERSys unified environment (infra/.env.example). +# When running ERE standalone, use this file with infra/compose.dev.yaml. +# When running inside the full ERSys stack, the parent project's .env covers these. + +# --- Redis --- +# When running the demo from the host machine (poetry run python demo/demo.py), +# the Docker service name 'ersys-redis' is not resolvable from the host. Set +# REDIS_HOST=localhost here before running the demo. The ERE container reads this +# file at startup, so restore the original value before restarting the stack. +REDIS_HOST=ersys-redis +REDIS_PORT=6379 +REDIS_DB=0 +REDIS_PASSWORD=changeme + +# --- Queues --- +ERSYS_REQUEST_QUEUE=ere_requests +ERSYS_RESPONSE_QUEUE=ere_responses + +# --- Storage --- +DUCKDB_PATH=/data/app.duckdb + +# --- Logging --- +# ERE_LOG_LEVEL is read directly by the application (src/ere/utils/logging.py). +ERE_LOG_LEVEL=INFO diff --git a/src/infra/Dockerfile b/src/infra/Dockerfile new file mode 100644 index 0000000..cf92f40 --- /dev/null +++ b/src/infra/Dockerfile @@ -0,0 +1,81 @@ +# Multi-stage build for the Entity Resolution Engine. +# Build context: repository root (one level above /infra) + +# ============================================================================= +# Fetcher stage: resolve dependencies and build wheels +# ============================================================================= +FROM docker.io/library/python:3.12-slim AS fetcher + +ARG POETRY_VERSION=">=2.0.0,<3.0.0" + +ENV POETRY_NO_INTERACTION=1 \ + PYTHONDONTWRITEBYTECODE=1 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends git \ + && rm -rf /var/lib/apt/lists/* + +RUN pip install --no-cache-dir "poetry${POETRY_VERSION}" poetry-plugin-export + +WORKDIR /app +COPY src/pyproject.toml src/poetry.lock ./ + +# Export dependencies, build wheels (including git repos), then clean the requirements file +RUN poetry export -f requirements.txt --output requirements.txt --without-hashes \ + && pip wheel -r requirements.txt -w /wheels \ + && sed -i 's/ @ git.*//' requirements.txt + +# ============================================================================= +# Builder stage: install wheels into a virtual environment +# ============================================================================= +FROM docker.io/library/python:3.12-slim AS builder + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +WORKDIR /app + +# Create a virtual environment +RUN python -m venv /app/.venv +ENV PATH="/app/.venv/bin:${PATH}" + +# Copy wheels and requirements from fetcher +COPY --from=fetcher /wheels /wheels +COPY --from=fetcher /app/requirements.txt /requirements.txt + +# Install dependencies without using the network +RUN pip install --no-cache-dir --no-index --find-links=/wheels -r /requirements.txt + +COPY README.md /README.md +COPY src/pyproject.toml src/poetry.lock ./ +COPY src/ere ere/ +COPY src/config config/ + +# Install the application itself without re-triggering dependency resolution +RUN pip install --no-deps . + + +# ============================================================================= +# Runtime stage: minimal production image +# ============================================================================= +FROM docker.io/library/python:3.12-slim AS runtime + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PATH="/app/.venv/bin:${PATH}" + +RUN groupadd --gid 1000 appuser && \ + useradd --uid 1000 --gid appuser --shell /bin/bash --create-home appuser + +WORKDIR /app + +# Copy only the virtual environment and necessary app files +COPY --from=builder /app/.venv /app/.venv +COPY --from=builder /app/ere /app/ere +COPY --from=builder /app/config /app/config +# Volume mount point for DuckDB persistent storage +RUN mkdir -p /data && chown appuser:appuser /data + +USER appuser + +CMD ["python", "-m", "ere.entrypoints.app"] diff --git a/src/infra/README.md b/src/infra/README.md new file mode 100644 index 0000000..db68b06 --- /dev/null +++ b/src/infra/README.md @@ -0,0 +1,71 @@ +# Infrastructure + +Deployment and infrastructure files for the Entity Resolution Engine. + +## Structure + +``` +infra/ +├── .env.example # Environment variable template +├── compose.dev.yaml # Docker Compose for local development +├── Dockerfile # Multi-stage build (builder + runtime) +└── README.md +``` + +## Services + +| Service | Purpose | Port | +|---|---|---| +| `ere` | Entity Resolution Engine (Redis queue worker) | — (no HTTP API) | +| `redis` | Message queue for ERE requests/responses | 6379 | +| `redisinsight` | Redis GUI (development tool) | 5540 | + +## Usage + +All commands run from the repo root via `make`: + +```bash +make infra-build # Build the ERE Docker image +make infra-up # Start services (docker compose up -d) +make infra-down # Stop and remove containers and networks +make infra-down-volumes # Stop services and remove volumes (clean slate) +make infra-rebuild # Rebuild images and start services +make infra-rebuild-clean # Rebuild from scratch (no cache) +make infra-logs # Follow service logs +make infra-watch # Start services with file watching (sync src/ and config/) +``` + +### File watching (development) + +`make infra-watch` uses Docker Compose's `watch` feature to sync source code and +configuration changes into the running container without a full rebuild: + +- **Source changes** (`src/`) are synced live into the container +- **Config changes** (`config/`) are synced live into the container +- **Dependency changes** (`pyproject.toml`, `poetry.lock`) trigger a full rebuild + +> **Note:** ERE is a long-running queue worker, not an HTTP server with hot-reload. +> After syncing, restart the container to pick up changes: `docker compose -f infra/compose.dev.yaml restart ere` + +### Manual build + +```bash +docker build -f infra/Dockerfile -t ere:latest . +``` + +## Configuration + +Environment variables are loaded from `infra/.env`. See `infra/.env.example` for available options. To set up: + +```bash +cp infra/.env.example infra/.env +``` + +### Resolver configuration + +Entity resolution behaviour is configured via YAML files in the top-level `config/` directory: + +- **[resolver.yaml](../config/resolver.yaml)** — Splink comparisons, cold-start parameters, blocking rules, thresholds +- **[rdf_mapping.yaml](../config/rdf_mapping.yaml)** — RDF namespace bindings, field extraction rules, entity type definitions + +See the [configuration README](../config/README.md) for detailed tuning guidance. diff --git a/src/infra/compose.dev.yaml b/src/infra/compose.dev.yaml new file mode 100644 index 0000000..4bee0b2 --- /dev/null +++ b/src/infra/compose.dev.yaml @@ -0,0 +1,77 @@ +# Docker Compose configuration for local development + +name: ere-local + +services: + ersys-redis: + image: redis:7.4.4-alpine + container_name: "ersys-redis" + restart: unless-stopped + command: redis-server --requirepass ${REDIS_PASSWORD:-changeme} + ports: + - "6379:6379" + healthcheck: + test: ["CMD", "sh", "-c", "redis-cli --no-auth-warning -a $REDIS_PASSWORD ping"] + interval: 5s + timeout: 3s + retries: 5 + environment: + - REDIS_PASSWORD=${REDIS_PASSWORD:-changeme} + networks: + - ersys-local + + redisinsight: + image: redis/redisinsight:3.2.0 + container_name: "redisinsight" + restart: unless-stopped + ports: + - "5540:5540" + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:5540/api/health"] + interval: 5s + timeout: 3s + retries: 5 + networks: + - ersys-local + + ere: + build: + context: ../.. + dockerfile: src/infra/Dockerfile + container_name: "ere" + env_file: .env + restart: unless-stopped + environment: + - DUCKDB_PATH=${DUCKDB_PATH:-/data/app.duckdb} + - RDF_MAPPING_PATH=/app/config/rdf_mapping.yaml + - RESOLVER_CONFIG_PATH=/app/config/resolver.yaml + # Remaining REDIS_* and queue vars inherited from env_file + healthcheck: + test: ["CMD", "sh", "-c", "test -f /proc/1/cmdline"] + interval: 10s + timeout: 3s + retries: 3 + volumes: + - ere-data:/data + - ../../src/config:/app/config + develop: + watch: + - action: sync + path: ../../src/ere + target: /app/ere + - action: sync + path: ../../src/config + target: /app/config + - action: rebuild + path: ../../src/pyproject.toml + - action: rebuild + path: ../../src/poetry.lock + networks: + - ersys-local + +volumes: + ere-data: + +networks: + ersys-local: + external: true diff --git a/src/poetry.lock b/src/poetry.lock new file mode 100644 index 0000000..28adf51 --- /dev/null +++ b/src/poetry.lock @@ -0,0 +1,2606 @@ +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. + +[[package]] +name = "altair" +version = "6.1.0" +description = "Vega-Altair: A declarative statistical visualization library for Python." +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "altair-6.1.0-py3-none-any.whl", hash = "sha256:fdf5fd939512e5b2fc4441c82dfd2635e706defbd037db0ac429ef5ddce66c3b"}, + {file = "altair-6.1.0.tar.gz", hash = "sha256:dda699216cf85b040d968ae5a569ad45957616811e38760a85e5118269daca67"}, +] + +[package.dependencies] +jinja2 = "*" +jsonschema = ">=3.0" +narwhals = ">=2.4.0" +packaging = "*" +typing-extensions = {version = ">=4.12.0", markers = "python_version < \"3.15\""} + +[package.extras] +all = ["altair-tiles (>=0.3.0)", "anywidget (>=0.9.0)", "numpy", "pandas (>=1.1.3)", "pyarrow (>=11)", "vegafusion (>=2.0.3)", "vl-convert-python (>=1.9.0)"] +dev = ["duckdb (>=1.0)", "geopandas (>=0.14.3)", "hatch (>=1.13.0)", "ipykernel", "ipython", "mistune", "mypy", "pandas (>=1.1.3)", "pandas-stubs (<2.3.3)", "polars (>=0.20.3)", "pyarrow-stubs", "pytest", "pytest-cov", "pytest-xdist[psutil] (>=3.5,<4.0)", "ruff (>=0.9.5)", "taskipy (>=1.14.1)", "tomli (>=2.2.1)", "types-jsonschema", "types-setuptools"] +doc = ["docutils", "jinja2", "myst-parser", "numpydoc", "pillow", "pydata-sphinx-theme (>=0.14.1)", "scipy", "scipy-stubs ; python_version >= \"3.10\"", "sphinx", "sphinx-autobuild", "sphinx-copybutton", "sphinx-design", "sphinxext-altair"] +save = ["vl-convert-python (>=1.9.0)"] + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "assertpy" +version = "1.1" +description = "Simple assertion library for unit testing in python with a fluent API" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "assertpy-1.1.tar.gz", hash = "sha256:acc64329934ad71a3221de185517a43af33e373bb44dc05b5a9b174394ef4833"}, +] + +[[package]] +name = "astroid" +version = "3.3.11" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec"}, + {file = "astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce"}, +] + +[[package]] +name = "attrs" +version = "26.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"}, + {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"}, +] + +[[package]] +name = "cachetools" +version = "7.0.6" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "cachetools-7.0.6-py3-none-any.whl", hash = "sha256:4e94956cfdd3086f12042cdd29318f5ced3893014f7d0d059bf3ead3f85b7f8b"}, + {file = "cachetools-7.0.6.tar.gz", hash = "sha256:e5d524d36d65703a87243a26ff08ad84f73352adbeafb1cde81e207b456aaf24"}, +] + +[[package]] +name = "certifi" +version = "2026.2.25" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"}, + {file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"}, +] + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win32.whl", hash = "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win32.whl", hash = "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c"}, + {file = "charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d"}, + {file = "charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5"}, +] + +[[package]] +name = "click" +version = "8.3.2" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d"}, + {file = "click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "dev"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +markers = {main = "platform_system == \"Windows\" or sys_platform == \"win32\""} + +[[package]] +name = "coverage" +version = "7.13.5" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5"}, + {file = "coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0"}, + {file = "coverage-7.13.5-cp310-cp310-win32.whl", hash = "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58"}, + {file = "coverage-7.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8"}, + {file = "coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf"}, + {file = "coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9"}, + {file = "coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c"}, + {file = "coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf"}, + {file = "coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810"}, + {file = "coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17"}, + {file = "coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85"}, + {file = "coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b"}, + {file = "coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2"}, + {file = "coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a"}, + {file = "coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819"}, + {file = "coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0"}, + {file = "coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc"}, + {file = "coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633"}, + {file = "coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a"}, + {file = "coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215"}, + {file = "coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43"}, + {file = "coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45"}, + {file = "coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61"}, + {file = "coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179"}, +] + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "curies" +version = "0.13.6" +description = "Idiomatic conversion between URIs and compact URIs (CURIEs)" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "curies-0.13.6-py3-none-any.whl", hash = "sha256:fb9b86198a3f25cf20f9bb63b6a8367ec7f33b35b7bd82c61cc05df262d0fa46"}, + {file = "curies-0.13.6.tar.gz", hash = "sha256:90ade24612054c404469610132260ae2aa161670ec685f96ea1ed28765be2f55"}, +] + +[package.dependencies] +pydantic = ">=2.0" +pystow = ">=0.8.0" +typing-extensions = "*" + +[package.extras] +fastapi = ["defusedxml", "fastapi", "httpx", "python-multipart", "uvicorn"] +flask = ["defusedxml", "flask"] +pandas = ["pandas"] +rdflib = ["rdflib"] +sqlalchemy = ["sqlalchemy"] +sqlmodel = ["sqlmodel"] + +[[package]] +name = "deprecated" +version = "1.3.1" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main"] +files = [ + {file = "deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f"}, + {file = "deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223"}, +] + +[package.dependencies] +wrapt = ">=1.10,<3" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] + +[[package]] +name = "dill" +version = "0.4.1" +description = "serialize all of Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "dill-0.4.1-py3-none-any.whl", hash = "sha256:1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d"}, + {file = "dill-0.4.1.tar.gz", hash = "sha256:423092df4182177d4d8ba8290c8a5b640c66ab35ec7da59ccfa00f6fa3eea5fa"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "distlib" +version = "0.4.0" +description = "Distribution utilities" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, + {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, +] + +[[package]] +name = "docker" +version = "7.1.0" +description = "A Python library for the Docker Engine API." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"}, + {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, +] + +[package.dependencies] +pywin32 = {version = ">=304", markers = "sys_platform == \"win32\""} +requests = ">=2.26.0" +urllib3 = ">=1.26.0" + +[package.extras] +dev = ["coverage (==7.2.7)", "pytest (==7.4.2)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.1.0)", "ruff (==0.1.8)"] +docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] +ssh = ["paramiko (>=2.4.3)"] +websockets = ["websocket-client (>=1.3.0)"] + +[[package]] +name = "duckdb" +version = "1.5.2" +description = "DuckDB in-process database" +optional = false +python-versions = ">=3.10.0" +groups = ["main"] +files = [ + {file = "duckdb-1.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:63bf8687feefeed51adf45fa3b062ab8b1b1c350492b7518491b86bae68b1da1"}, + {file = "duckdb-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84b193aca20565dedb3172de15f843c659c3a6c773bf14843a9bd781c850e7db"}, + {file = "duckdb-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5596bbfc31b1b259db69c8d847b42d036ce2c4804f9ccb28f9fc46a16de7bc53"}, + {file = "duckdb-1.5.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8dbd7e31e5dc157bfe8803fa7d2652336265c6c19926c5a4a9b40f8222868d08"}, + {file = "duckdb-1.5.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9cd5e71702d446613750405cde03f66ed268f4c321da071b0472759dad19536"}, + {file = "duckdb-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:ce17670bb392ea1b3650537db02bd720908776b5b95f6d2472d31a7de59d1dc1"}, + {file = "duckdb-1.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f69164b048e498b9e9140a24343108a5ae5f17bfb3485185f55fdf9b1aa924d"}, + {file = "duckdb-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81fc4fbf0b5e25840b39ba2a10b78c6953c0314d5d0434191e7898f34ab1bba3"}, + {file = "duckdb-1.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56d38b3c4e0ef2abb58898d0fd423933999ed535c45e75e9d9f72e1d5fed69b8"}, + {file = "duckdb-1.5.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:376856066c65ccd55fcb3a380bbe33a71ce089fc4623d229ffc6e82251afdb6d"}, + {file = "duckdb-1.5.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c69907354ffee94ba8cf782daf0480dab7557f21ce27fffa6c0ea8f74ed4b8e2"}, + {file = "duckdb-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:d9b4f5430bf4f05d4c0dc4c55c75def3a5af4be0343be20fa2bfc577343fbfc9"}, + {file = "duckdb-1.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:2323c1195c10fb2bb982fc0218c730b43d1b92a355d61e68e3c5f3ac9d44c34f"}, + {file = "duckdb-1.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e6495b00cad16888384119842797c49316a96ae1cb132bb03856d980d95afee1"}, + {file = "duckdb-1.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d72b8856b1839d35648f38301b058f6232f4d36b463fe4dc8f4d3fdff2df1a2e"}, + {file = "duckdb-1.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a1de4f4d454b8c97aec546c82003fc834d3422ce4bc6a19902f3462ef293bed"}, + {file = "duckdb-1.5.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce0b8141a10d37ecef729c45bc41d334854013f4389f1488bd6035c5579aaac1"}, + {file = "duckdb-1.5.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99ef73a277c8921bc0a1f16dee38d924484251d9cfd20951748c20fcd5ed855"}, + {file = "duckdb-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:8d599758b4e48bf12e18c9b960cf491d219f0c4972d19a45489c05cc5ab36f83"}, + {file = "duckdb-1.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:fc85a5dbcbe6eccac1113c72370d1d3aacfdd49198d63950bdf7d8638a307f00"}, + {file = "duckdb-1.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4420b3f47027a7849d0e1815532007f377fa95ee5810b47ea717d35525c12f79"}, + {file = "duckdb-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bb42e6ed543902e14eae647850da24103a89f0bc2587dec5601b1c1f213bd2ed"}, + {file = "duckdb-1.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:98c0535cd6d901f61a5ea3c2e26a1fd28482953d794deb183daf568e3aa5dda6"}, + {file = "duckdb-1.5.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:486c862bf7f163c0110b6d85b3e5c031d224a671cca468f12ebb1d3a348f6b39"}, + {file = "duckdb-1.5.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70631c847ca918ee710ec874241b00cf9d2e5be90762cbb2a0389f17823c08f7"}, + {file = "duckdb-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:52a21823f3fbb52f0f0e5425e20b07391ad882464b955879499b5ff0b45a376b"}, + {file = "duckdb-1.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:411ad438bd4140f189a10e7f515781335962c5d18bd07837dc6d202e3985253d"}, + {file = "duckdb-1.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6b0fe75c148000f060aa1a27b293cacc0ea08cc1cad724fbf2143d56070a3785"}, + {file = "duckdb-1.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35579b8e3a064b5eaf15b0eafc558056a13f79a0a62e34cc4baf57119daecfec"}, + {file = "duckdb-1.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea58ff5b0880593a280cf5511734b17711b32ee1f58b47d726e8600848358160"}, + {file = "duckdb-1.5.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef461bca07313412dc09961c4a4757a851f56b95ac01c58fac6007632b7b94f2"}, + {file = "duckdb-1.5.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be37680ddb380015cb37318e378c53511c45c4f0d8fac5599d22b7d092b9217a"}, + {file = "duckdb-1.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:0b291786014df1133f8f18b9df4d004484613146e858d71a21791e0fcca16cf4"}, + {file = "duckdb-1.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:c9f3e0b71b8a50fccfb42794899285d9d318ce2503782b9dd54868e5ecd0ad31"}, + {file = "duckdb-1.5.2.tar.gz", hash = "sha256:638da0d5102b6cb6f7d47f83d0600708ac1d3cb46c5e9aaabc845f9ba4d69246"}, +] + +[package.extras] +all = ["adbc-driver-manager", "fsspec", "ipython", "numpy", "pandas", "pyarrow"] + +[[package]] +name = "ers-spec" +version = "1.1.0" +description = " The core components for the Entity Resolution System (ERS) components.\n\n The ERS is a pluggable entity resolution system for data transformation pipelines.\n" +optional = false +python-versions = ">=3.12,<4.0" +groups = ["main"] +files = [] +develop = false + +[package.dependencies] +pydantic = ">=2.10.6,<3.0.0" + +[package.source] +type = "git" +url = "https://github.com/OP-TED/entity-resolution-spec.git" +reference = "release/1.1.0" +resolved_reference = "0565b2ddf3d5a11851128a80abed08f4de950080" +subdirectory = "src" + +[[package]] +name = "filelock" +version = "3.29.0" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258"}, + {file = "filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90"}, +] + +[[package]] +name = "gherkin-official" +version = "29.0.0" +description = "Gherkin parser (official, by Cucumber team)" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "gherkin_official-29.0.0-py3-none-any.whl", hash = "sha256:26967b0d537a302119066742669e0e8b663e632769330be675457ae993e1d1bc"}, + {file = "gherkin_official-29.0.0.tar.gz", hash = "sha256:dbea32561158f02280d7579d179b019160d072ce083197625e2f80a6776bb9eb"}, +] + +[[package]] +name = "grimp" +version = "3.14" +description = "Builds a queryable graph of the imports within one or more Python packages." +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "grimp-3.14-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:17364365c27c111514fd9d17844f275ed074ec9feca0d6cf9bd5bf9218db2412"}, + {file = "grimp-3.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:25273ea53ac1492e7343bd9d9d9b60445f707bc0d162eca85288c7325579ee47"}, + {file = "grimp-3.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53b8f69bdf070fddbbc13f60a5cdb42efb102516770b34f076456ec4ce960627"}, + {file = "grimp-3.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1aa397596bb6d616200be1fd6570e87ddc225c192845c649d4f6015175b77bc6"}, + {file = "grimp-3.14-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2892ca934fc19c6d51d6c0a609d4db7e97c4721cc9a609f2bab8fe8e1ec1821"}, + {file = "grimp-3.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e9367b9fa9c97cb8d1974a164d5981852b498977a097ad7335fc012ab96498b"}, + {file = "grimp-3.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87f398915c716c13736460a54f8dc5d70494d7d616039f547c0093f252307109"}, + {file = "grimp-3.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5551a825b14e52642428ef7c4a5790819bfaee0fdae94f89ce248cff3d7109bb"}, + {file = "grimp-3.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6ee7a2fab52ce0c6ae81fa1f2319bad5bd361110994567477f26be018043d63d"}, + {file = "grimp-3.14-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6d1434172a02cd97425126260dec80a8fd0491d9467b822d871498199c296c91"}, + {file = "grimp-3.14-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9a85bf0a8c4b58db12184fe53a469a7189b4c63397a2eaca0d9efe410f6f68e7"}, + {file = "grimp-3.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:53d9ed23fb7da4c886affeb6b8bce7c19d8b09f2e1631a482c9446a20d504bdf"}, + {file = "grimp-3.14-cp310-cp310-win32.whl", hash = "sha256:d05110b9afda361ff8d90740a8344ccfd2d59a5a1977d517b9bce178738ed34f"}, + {file = "grimp-3.14-cp310-cp310-win_amd64.whl", hash = "sha256:fad2a819756b5c0441b8841c2e6f541960b13edd09b672e6e199232dcf9bcb7a"}, + {file = "grimp-3.14-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f1c91e3fa48c2196bf62e3c71492140d227b2bfcd6d15e735cbc0b3e2d5308e0"}, + {file = "grimp-3.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6291c8f1690a9fe21b70923c60b075f4a89676541999e3d33084cbc69ac06a1"}, + {file = "grimp-3.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ec312383935c2d09e4085c8435780ada2e13ebef14e105609c2988a02a5b2ce"}, + {file = "grimp-3.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f43cbf640e73ee703ad91639591046828d20103a1c363a02516e77a66a4ac07"}, + {file = "grimp-3.14-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a93c9fddccb9ff16f5c6b5fca44227f5f86cba7cffc145d2176119603d2d7c7"}, + {file = "grimp-3.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5653a2769fdc062cb7598d12200352069c9c6559b6643af6ada3639edb98fcc3"}, + {file = "grimp-3.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:071c7ddf5e5bb7b2fdf79aefdf6e1c237cd81c095d6d0a19620e777e85bf103c"}, + {file = "grimp-3.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e01b7a4419f535b667dfdcb556d3815b52981474f791fb40d72607228389a31"}, + {file = "grimp-3.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c29682f336151d1d018d0c3aa9eeaa35734b970e4593fa396b901edca7ef5c79"}, + {file = "grimp-3.14-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a5c4fd71f363ea39e8aab0630010ced77a8de9789f27c0acdd0d7e6269d4a8ef"}, + {file = "grimp-3.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:766911e3ba0b13d833fdd03ad1f217523a8a2b2527b5507335f71dca1153183d"}, + {file = "grimp-3.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:154e84a2053e9f858ae48743de23a5ad4eb994007518c29371276f59b8419036"}, + {file = "grimp-3.14-cp311-cp311-win32.whl", hash = "sha256:3189c86c3e73016a1907ee3ba9f7a6ca037e3601ad09e60ce9bf12b88877f812"}, + {file = "grimp-3.14-cp311-cp311-win_amd64.whl", hash = "sha256:201f46a6a4e5ee9dfba4a2f7d043f7deab080d1d84233f4a1aee812678c25307"}, + {file = "grimp-3.14-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ffabc6940301214753bad89ec0bfe275892fa1f64b999e9a101f6cebfc777133"}, + {file = "grimp-3.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:075d9a1c78d607792d0ed8d4d3d7754a621ef04c8a95eaebf634930dc9232bb2"}, + {file = "grimp-3.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06ff52addeb20955a4d6aa097bee910573ffc9ef0d3c8a860844f267ad958156"}, + {file = "grimp-3.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d10e0663e961fcbe8d0f54608854af31f911f164c96a44112d5173050132701f"}, + {file = "grimp-3.14-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ab874d7ddddc7a1291259cf7c31a4e7b5c612e9da2e24c67c0eb1a44a624e67"}, + {file = "grimp-3.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54fec672ec83355636a852177f5a470c964bede0f6730f9ba3c7b5c8419c9eab"}, + {file = "grimp-3.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9e221b5e8070a916c780e88c877fee2a61c95a76a76a2a076396e459511b0bb"}, + {file = "grimp-3.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eea6b495f9b4a8d82f5ce544921e76d0d12017f5d1ac3a3bd2f5ac88ab055b1c"}, + {file = "grimp-3.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:655e8d3f79cd99bb859e09c9dd633515150e9d850879ca71417d5ac31809b745"}, + {file = "grimp-3.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a14f10b1b71c6c37647a76e6a49c226509648107abc0f48c1e3ecd158ba05531"}, + {file = "grimp-3.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:81685111ee24d3e25f8ed9e77ed00b92b58b2414e1a1c2937236026900972744"}, + {file = "grimp-3.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce8352a8ea0e27b143136ea086582fc6653419aa8a7c15e28ed08c898c42b185"}, + {file = "grimp-3.14-cp312-cp312-win32.whl", hash = "sha256:3fc0f98b3c60d88e9ffa08faff3200f36604930972f8b29155f323b76ea25a06"}, + {file = "grimp-3.14-cp312-cp312-win_amd64.whl", hash = "sha256:6bca77d1d50c8dc402c96af21f4e28e2f1e9938eeabd7417592a22bd83cde3c3"}, + {file = "grimp-3.14-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:af8a625554beea84530b98cc471902155b5fc042b42dc47ec846fa3e32b0c615"}, + {file = "grimp-3.14-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0dd1942ffb419ad342f76b0c3d3d2d7f312b264ddc578179d13ce8d5acec1167"}, + {file = "grimp-3.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:537f784ce9b4acf8657f0b9714ab69a6c72ffa752eccc38a5a85506103b1a194"}, + {file = "grimp-3.14-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78ab18c08770aa005bef67b873bc3946d33f65727e9f3e508155093db5fa57d6"}, + {file = "grimp-3.14-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28ca58728c27e7292c99f964e6ece9295c2f9cfdefc37c18dea0679c783ffb6f"}, + {file = "grimp-3.14-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b5577de29c6c5ae6e08d4ca0ac361b45dba323aa145796e6b320a6ea35414b7"}, + {file = "grimp-3.14-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d7d1f9f42306f455abcec34db877e4887ff15f2777a43491f7ccbd6936c449b"}, + {file = "grimp-3.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39bd5c9b7cef59ee30a05535e9cb4cbf45a3c503f22edce34d0aa79362a311a9"}, + {file = "grimp-3.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7fec3116b4f780a1bc54176b19e6b9f2e36e2ef3164b8fc840660566af35df88"}, + {file = "grimp-3.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0233a35a5bbb23688d63e1736b54415fa9994ace8dfeb7de8514ed9dee212968"}, + {file = "grimp-3.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e46b2fef0f1da7e7e2f8129eb93c7e79db716ff7810140a22ce5504e10ed86df"}, + {file = "grimp-3.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e6d9b50623ee1c3d2a1927ec3f5d408995ea1f92f3e91ed996c908bb40e856f"}, + {file = "grimp-3.14-cp313-cp313-win32.whl", hash = "sha256:fd57c56f5833c99320ec77e8ba5508d56f6fb48ec8032a942f7931cc6ebb80ce"}, + {file = "grimp-3.14-cp313-cp313-win_amd64.whl", hash = "sha256:173307cf881a126fe5120b7bbec7d54384002e3c83dcd8c4df6ce7f0fee07c53"}, + {file = "grimp-3.14-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebe29f8f13fbd7c314908ed535183a36e6db71839355b04869b27f23c58fa082"}, + {file = "grimp-3.14-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073d285b00100153fd86064c7726bb1b6d610df1356d33bb42d3fd8809cb6e72"}, + {file = "grimp-3.14-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6d6efc37e1728bbfcd881b89467be5f7b046292597b3ebe5f8e44e89ea8b6cb"}, + {file = "grimp-3.14-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5337d65d81960b712574c41e85b480d4480bbb5c6f547c94e634f6c60d730889"}, + {file = "grimp-3.14-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:84a7fea63e352b325daa89b0b7297db411b7f0036f8d710c32f8e5090e1fc3ca"}, + {file = "grimp-3.14-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d0b19a3726377165fe1f7184a8af317734d80d32b371b6c5578747867ab53c0b"}, + {file = "grimp-3.14-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9caa4991f530750f88474a3f5ecf6ef9f0d064034889d92db00cfb4ecb78aa24"}, + {file = "grimp-3.14-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1876efc119b99332a5cc2b08a6bdaada2f0ad94b596f0372a497e2aa8bda4d94"}, + {file = "grimp-3.14-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3ccf03e65864d6bc7bf1c003c319f5330a7627b3677f31143f11691a088464c2"}, + {file = "grimp-3.14-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9ecd58fa58a270e7523f8bec9e6452f4fdb9c21e4cd370640829f1e43fa87a69"}, + {file = "grimp-3.14-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d75d1f8f7944978b39b08d870315174f1ffcd5123be6ccff8ce90467ace648a"}, + {file = "grimp-3.14-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6f70bbb1dd6055d08d29e39a78a11c4118c1778b39d17cd8271e18e213524ca7"}, + {file = "grimp-3.14-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f21b7c003626c902669dc26ede83a91220cf0a81b51b27128370998c2f247b4"}, + {file = "grimp-3.14-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80d9f056415c936b45561310296374c4319b5df0003da802c84d2830a103792a"}, + {file = "grimp-3.14-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0332963cd63a45863775d4237e59dedf95455e0a1ea50c356be23100c5fc1d7c"}, + {file = "grimp-3.14-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4144350d074f2058fe7c89230a26b34296b161f085b0471a692cb2fe27036f"}, + {file = "grimp-3.14-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e148e67975e92f90a8435b1b4c02180b9a3f3d725b7a188ba63793f1b1e445a0"}, + {file = "grimp-3.14-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:1093f7770cb5f3ca6f99fb152f9c949381cc0b078dfdfe598c8ab99abaccda3b"}, + {file = "grimp-3.14-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a213f45ec69e9c2b28ffd3ba5ab12cc9859da17083ba4dc39317f2083b618111"}, + {file = "grimp-3.14-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f003ac3f226d2437a49af0b6036f26edba57f8a32d329275dbde1b2b2a00a56"}, + {file = "grimp-3.14-cp314-cp314-win32.whl", hash = "sha256:eec81be65a18f4b2af014b1e97296cc9ee20d1115529bf70dd7e06f457eac30b"}, + {file = "grimp-3.14-cp314-cp314-win_amd64.whl", hash = "sha256:cd3bab6164f1d5e313678f0ab4bf45955afe7f5bdb0f2f481014aa9cca7e81ba"}, + {file = "grimp-3.14-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b1df33de479be4d620f69633d1876858a8e64a79c07907d47cf3aaf896af057"}, + {file = "grimp-3.14-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07096d4402e9d5a2c59c402ea3d601f4b7f99025f5e32f077468846fc8d3821b"}, + {file = "grimp-3.14-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:712bc28f46b354316af50c469c77953ba3d6cb4166a62b8fb086436a8b05d301"}, + {file = "grimp-3.14-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abe2bbef1cf8e27df636c02f60184319f138dee4f3a949405c21a4b491980397"}, + {file = "grimp-3.14-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2f9ae3fabb7a7a8468ddc96acc84ecabd84f168e7ca508ee94d8f32ea9bd5de2"}, + {file = "grimp-3.14-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:efaf11ea73f7f12d847c54a5d6edcbe919e0369dce2d1aabae6c50792e16f816"}, + {file = "grimp-3.14-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e089c9ab8aa755ff5af88c55891727783b4eb6b228e7bdf278e17209d954aa1e"}, + {file = "grimp-3.14-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a424ad14d5deb56721ac24ab939747f72ab3d378d42e7d1f038317d33b052b77"}, + {file = "grimp-3.14-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1d4f96c0159b33647295ad36683fe7be55fa620de6e54e970c913cb88d0a5a6"}, + {file = "grimp-3.14-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e715f78fda0019b493459f97efc48462912b4c5b5d261215d94c05115511d311"}, + {file = "grimp-3.14-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d0a885b04edbe908cd6f2f8cb0999dd2a348091d241bd9842f9ea593fabdce5"}, + {file = "grimp-3.14-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6995b20574313ba66b73d288f431af24b9d23d60c861e8f5cbf0d0e26ad9c49"}, + {file = "grimp-3.14-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d2a170deb9f4790221dcde8c47e60be7fcd52999062241ac944ce556efa1d24d"}, + {file = "grimp-3.14-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1d4a28e2545a83c853a6357ccf4a5105e3f74419a75312b5ebaf0435085cd938"}, + {file = "grimp-3.14-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:9aa74d848c083725add12e0e6d42a01ddfd8ee84e9504ad7254204985e3c5c92"}, + {file = "grimp-3.14-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:acf0acedaf105c8d3747abf073c6a2dd1379bafcb5807926fd6d5fe4b0980698"}, + {file = "grimp-3.14-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c8a8aab9b4310a7e69d7d845cac21cf14563aa0520ea322b948eadeae56d303"}, + {file = "grimp-3.14-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d781943b27e5875a41c8f9cfc80f8f0a349f864379192b8c3faa0e6a22593313"}, + {file = "grimp-3.14-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9630d4633607aff94d0ac84b9c64fef1382cdb05b00d9acbde47f8745e264871"}, + {file = "grimp-3.14-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cb00e1bcca583668554a8e9e1e4229a1d11b0620969310aae40148829ff6a32"}, + {file = "grimp-3.14-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3389da4ceaaa7f7de24a668c0afc307a9f95997bd90f81ec359a828a9bd1d270"}, + {file = "grimp-3.14-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd7a32970ef97e42d4e7369397c7795287d84a736d788ccb90b6c14f0561d975"}, + {file = "grimp-3.14-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:fd1278623fa09f62abc0fd8a6500f31b421a1fd479980f44c2926020a0becf02"}, + {file = "grimp-3.14-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:9cfa52c89333d3d8fe9dc782529e888270d060231c3783e036d424044671dde0"}, + {file = "grimp-3.14-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:48a5be4a12fca6587e6885b4fc13b9e242ab8bf874519292f0f13814aecf52cc"}, + {file = "grimp-3.14-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:3fcc332466783a12a42cd317fd344c30fe734ba4fa2362efff132dc3f8d36da7"}, + {file = "grimp-3.14.tar.gz", hash = "sha256:645fbd835983901042dae4e1b24fde3a89bf7ac152f9272dd17a97e55cb4f871"}, +] + +[package.dependencies] +typing-extensions = ">=3.10.0.0" + +[[package]] +name = "hbreader" +version = "0.9.1" +description = "Honey Badger reader - a generic file/url/string open and read tool" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "hbreader-0.9.1-py3-none-any.whl", hash = "sha256:9a6e76c9d1afc1b977374a5dc430a1ebb0ea0488205546d4678d6e31cc5f6801"}, + {file = "hbreader-0.9.1.tar.gz", hash = "sha256:d2c132f8ba6276d794c66224c3297cec25c8079d0a4cf019c061611e0a3b94fa"}, +] + +[[package]] +name = "idna" +version = "3.12" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "idna-3.12-py3-none-any.whl", hash = "sha256:60ffaa1858fac94c9c124728c24fcde8160f3fb4a7f79aa8cdd33a9d1af60a67"}, + {file = "idna-3.12.tar.gz", hash = "sha256:724e9952cc9e2bd7550ea784adb098d837ab5267ef67a1ab9cf7846bdbdd8254"}, +] + +[package.extras] +all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "igraph" +version = "1.0.0" +description = "High performance graph data structures and algorithms" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "igraph-1.0.0-cp39-abi3-macosx_10_15_x86_64.whl", hash = "sha256:c2cbc415e02523e5a241eecee82319080bf928a70b1ba299f3b3e25bf029b6d4"}, + {file = "igraph-1.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a27753cd80680a8f676c2d5a467aaa4a95e510b30748398ec4e4aeb982130e8"}, + {file = "igraph-1.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a55dc3a2a4e3fc3eba42479910c1511bfc3ecb33cdf5f0406891fd85f14b5aee"}, + {file = "igraph-1.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2d04c2c76f686fb1f554ee35dfd3085f5e73b7965ba6b4cf06d53e66b1955522"}, + {file = "igraph-1.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2b52dc1757fff0fed29a9f7a276d971a11db4211569ed78b9eab36288dfcc9d"}, + {file = "igraph-1.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:05c79a2a8fca695b2f217a6fa7f2549f896f757d4db41be32a055400cb19cc30"}, + {file = "igraph-1.0.0-cp39-abi3-win32.whl", hash = "sha256:c2bce3cd472fec3dd9c4d8a3ea5b6b9be65fb30edf760beb4850760dd4f2d479"}, + {file = "igraph-1.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:faeff8ede0cf15eb4ded44b0fcea6e1886740146e60504c24ad2da14e0939563"}, + {file = "igraph-1.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:b607cafc24b10a615e713ee96e58208ef27e0764af80140c7cc45d4724a3f2df"}, + {file = "igraph-1.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3189c1a8e8a8f58009f3f729040eb3701254d074ed37245691d529869ec940c5"}, + {file = "igraph-1.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ebe9502689b946301584b3cfacdbc70c58c4d664d804e39b6daa31be5c20bf46"}, + {file = "igraph-1.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f117683108c54330d6dc67a708e3724c13c9989885122a29781296872989a222"}, + {file = "igraph-1.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:077dbff0edb8b4ce0f9fefdf325200346d9d5db02de31872b41743de08e67a16"}, + {file = "igraph-1.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fe7c693b2a84a4e03ca31e65aa05a2ecd8728137fa9909ccbf6453b4200b856d"}, + {file = "igraph-1.0.0.tar.gz", hash = "sha256:2414d0be2e4d77ee5357807d100974b40f6082bb1bb71988ec46cfb6728651ee"}, +] + +[package.dependencies] +texttable = ">=1.6.2" + +[package.extras] +cairo = ["cairocffi (>=1.2.0)"] +doc = ["Sphinx (>=7.0.0)", "pydoctor (>=23.4.0)", "sphinx-gallery (>=0.14.0)", "sphinx-rtd-theme (>=1.3.0)"] +matplotlib = ["matplotlib (>=3.6.0) ; platform_python_implementation != \"PyPy\""] +plotly = ["plotly (>=5.3.0)"] +plotting = ["cairocffi (>=1.2.0)"] +test = ["Pillow (>=9) ; platform_python_implementation != \"PyPy\"", "cairocffi (>=1.2.0)", "matplotlib (>=3.6.0) ; platform_python_implementation != \"PyPy\"", "networkx (>=2.5)", "numpy (>=1.19.0) ; platform_python_implementation != \"PyPy\"", "pandas (>=1.1.0) ; platform_python_implementation != \"PyPy\"", "plotly (>=5.3.0)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)", "scipy (>=1.5.0) ; platform_python_implementation != \"PyPy\""] +test-musl = ["cairocffi (>=1.2.0)", "networkx (>=2.5)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)"] +test-win-arm64 = ["cairocffi (>=1.2.0)", "networkx (>=2.5)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)"] + +[[package]] +name = "import-linter" +version = "2.11" +description = "Lint your Python architecture" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "import_linter-2.11-py3-none-any.whl", hash = "sha256:3dc54cae933bae3430358c30989762b721c77aa99d424f56a08265be0eeaa465"}, + {file = "import_linter-2.11.tar.gz", hash = "sha256:5abc3394797a54f9bae315e7242dc98715ba485f840ac38c6d3192c370d0085e"}, +] + +[package.dependencies] +click = ">=6" +grimp = ">=3.14" +rich = ">=14.2.0" +typing-extensions = ">=3.10.0.0" + +[package.extras] +ui = ["fastapi (>=0.113)", "uvicorn (>=0.17.1)"] + +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + +[[package]] +name = "isort" +version = "6.1.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "isort-6.1.0-py3-none-any.whl", hash = "sha256:58d8927ecce74e5087aef019f778d4081a3b6c98f15a80ba35782ca8a2097784"}, + {file = "isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481"}, +] + +[package.extras] +colors = ["colorama"] +plugins = ["setuptools"] + +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "json-flattener" +version = "0.1.9" +description = "Python library for denormalizing nested dicts or json objects to tables and back" +optional = false +python-versions = ">=3.7.0" +groups = ["main"] +files = [ + {file = "json_flattener-0.1.9-py3-none-any.whl", hash = "sha256:6b027746f08bf37a75270f30c6690c7149d5f704d8af1740c346a3a1236bc941"}, + {file = "json_flattener-0.1.9.tar.gz", hash = "sha256:84cf8523045ffb124301a602602201665fcb003a171ece87e6f46ed02f7f0c15"}, +] + +[package.dependencies] +click = "*" +pyyaml = "*" + +[[package]] +name = "jsonasobj2" +version = "1.0.4" +description = "JSON as python objects - version 2" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "jsonasobj2-1.0.4-py3-none-any.whl", hash = "sha256:12e86f86324d54fcf60632db94ea74488d5314e3da554c994fe1e2c6f29acb79"}, + {file = "jsonasobj2-1.0.4.tar.gz", hash = "sha256:f50b1668ef478004aa487b2d2d094c304e5cb6b79337809f4a1f2975cc7fbb4e"}, +] + +[package.dependencies] +hbreader = "*" + +[[package]] +name = "jsonschema" +version = "4.26.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce"}, + {file = "jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.3.6" +referencing = ">=0.28.4" +rpds-py = ">=0.25.0" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "rfc3987-syntax (>=1.1.0)", "uri-template", "webcolors (>=24.6.0)"] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, + {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "linkml-runtime" +version = "1.10.0" +description = "Runtime environment for LinkML, the Linked open data modeling language" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "linkml_runtime-1.10.0-py3-none-any.whl", hash = "sha256:b7caf806e1b49bf62005d8f398b070c282742c5f6626469fdc1660add0c9da58"}, + {file = "linkml_runtime-1.10.0.tar.gz", hash = "sha256:899889d584ce8056c5c44512b2d247bdc84a8484c3aa228aeb2db283e3a9d2ec"}, +] + +[package.dependencies] +click = "*" +curies = ">=0.5.4" +deprecated = "*" +hbreader = "*" +json-flattener = ">=0.1.9" +jsonasobj2 = ">=1.0.4,<2.dev0" +jsonschema = ">=3.2.0" +prefixcommons = ">=0.1.12" +prefixmaps = ">=0.1.4" +pydantic = ">=1.10.2,<3.0.0" +pyyaml = "*" +rdflib = ">=6.0.0" +requests = "*" + +[package.extras] +dev = ["coverage", "requests-cache"] + +[[package]] +name = "mako" +version = "1.3.11" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "mako-1.3.11-py3-none-any.whl", hash = "sha256:e372c6e333cf004aa736a15f425087ec977e1fcbd2966aae7f17c8dc1da27a77"}, + {file = "mako-1.3.11.tar.gz", hash = "sha256:071eb4ab4c5010443152255d77db7faa6ce5916f35226eb02dc34479b6858069"}, +] + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + +[[package]] +name = "mando" +version = "0.7.1" +description = "Create Python CLI apps with little to no effort at all!" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "mando-0.7.1-py2.py3-none-any.whl", hash = "sha256:26ef1d70928b6057ee3ca12583d73c63e05c49de8972d620c278a7b206581a8a"}, + {file = "mando-0.7.1.tar.gz", hash = "sha256:18baa999b4b613faefb00eac4efadcf14f510b59b924b66e08289aa1de8c3500"}, +] + +[package.dependencies] +six = "*" + +[package.extras] +restructuredtext = ["rst2ansi"] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"}, + {file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins (>=0.5.0)"] +profiling = ["gprof2dot"] +rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "requests"] + +[[package]] +name = "markupsafe" +version = "3.0.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "narwhals" +version = "2.20.0" +description = "Extremely lightweight compatibility layer between dataframe libraries" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "narwhals-2.20.0-py3-none-any.whl", hash = "sha256:16e750ea5507d4ba6e8d03455b5f93a535e0405976561baea235bca5dc9f475d"}, + {file = "narwhals-2.20.0.tar.gz", hash = "sha256:c10994975fa7dc5a68c2cffcddbd5908fc8ebb2d463c5bab085309c0ee1f551e"}, +] + +[package.extras] +cudf = ["cudf-cu12 (>=24.10.0)"] +dask = ["dask[dataframe] (>=2024.8)"] +duckdb = ["duckdb (>=1.1)"] +ibis = ["ibis-framework (>=6.0.0)", "packaging", "pyarrow-hotfix", "rich"] +modin = ["modin"] +pandas = ["pandas (>=1.1.3)"] +polars = ["polars (>=0.20.4)"] +pyarrow = ["pyarrow (>=13.0.0)"] +pyspark = ["pyspark (>=3.5.0)"] +pyspark-connect = ["pyspark[connect] (>=3.5.0)"] +sql = ["duckdb (>=1.1)", "sqlparse"] +sqlframe = ["sqlframe (>=3.22.0,!=3.39.3)"] + +[[package]] +name = "numpy" +version = "2.4.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.11" +groups = ["main"] +files = [ + {file = "numpy-2.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f983334aea213c99992053ede6168500e5f086ce74fbc4acc3f2b00f5762e9db"}, + {file = "numpy-2.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72944b19f2324114e9dc86a159787333b77874143efcf89a5167ef83cfee8af0"}, + {file = "numpy-2.4.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:86b6f55f5a352b48d7fbfd2dbc3d5b780b2d79f4d3c121f33eb6efb22e9a2015"}, + {file = "numpy-2.4.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:ba1f4fc670ed79f876f70082eff4f9583c15fb9a4b89d6188412de4d18ae2f40"}, + {file = "numpy-2.4.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a87ec22c87be071b6bdbd27920b129b94f2fc964358ce38f3822635a3e2e03d"}, + {file = "numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df3775294accfdd75f32c74ae39fcba920c9a378a2fc18a12b6820aa8c1fb502"}, + {file = "numpy-2.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d4e437e295f18ec29bc79daf55e8a47a9113df44d66f702f02a293d93a2d6dd"}, + {file = "numpy-2.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6aa3236c78803afbcb255045fbef97a9e25a1f6c9888357d205ddc42f4d6eba5"}, + {file = "numpy-2.4.4-cp311-cp311-win32.whl", hash = "sha256:30caa73029a225b2d40d9fae193e008e24b2026b7ee1a867b7ee8d96ca1a448e"}, + {file = "numpy-2.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:6bbe4eb67390b0a0265a2c25458f6b90a409d5d069f1041e6aff1e27e3d9a79e"}, + {file = "numpy-2.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:fcfe2045fd2e8f3cb0ce9d4ba6dba6333b8fa05bb8a4939c908cd43322d14c7e"}, + {file = "numpy-2.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15716cfef24d3a9762e3acdf87e27f58dc823d1348f765bbea6bef8c639bfa1b"}, + {file = "numpy-2.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23cbfd4c17357c81021f21540da84ee282b9c8fba38a03b7b9d09ba6b951421e"}, + {file = "numpy-2.4.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b3b60bb7cba2c8c81837661c488637eee696f59a877788a396d33150c35d842"}, + {file = "numpy-2.4.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e4a010c27ff6f210ff4c6ef34394cd61470d01014439b192ec22552ee867f2a8"}, + {file = "numpy-2.4.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9e75681b59ddaa5e659898085ae0eaea229d054f2ac0c7e563a62205a700121"}, + {file = "numpy-2.4.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:81f4a14bee47aec54f883e0cad2d73986640c1590eb9bfaaba7ad17394481e6e"}, + {file = "numpy-2.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:62d6b0f03b694173f9fcb1fb317f7222fd0b0b103e784c6549f5e53a27718c44"}, + {file = "numpy-2.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fbc356aae7adf9e6336d336b9c8111d390a05df88f1805573ebb0807bd06fd1d"}, + {file = "numpy-2.4.4-cp312-cp312-win32.whl", hash = "sha256:0d35aea54ad1d420c812bfa0385c71cd7cc5bcf7c65fed95fc2cd02fe8c79827"}, + {file = "numpy-2.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:b5f0362dc928a6ecd9db58868fca5e48485205e3855957bdedea308f8672ea4a"}, + {file = "numpy-2.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:846300f379b5b12cc769334464656bc882e0735d27d9726568bc932fdc49d5ec"}, + {file = "numpy-2.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50"}, + {file = "numpy-2.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115"}, + {file = "numpy-2.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af"}, + {file = "numpy-2.4.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c"}, + {file = "numpy-2.4.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103"}, + {file = "numpy-2.4.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83"}, + {file = "numpy-2.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed"}, + {file = "numpy-2.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959"}, + {file = "numpy-2.4.4-cp313-cp313-win32.whl", hash = "sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed"}, + {file = "numpy-2.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf"}, + {file = "numpy-2.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d"}, + {file = "numpy-2.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5"}, + {file = "numpy-2.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7"}, + {file = "numpy-2.4.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93"}, + {file = "numpy-2.4.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e"}, + {file = "numpy-2.4.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40"}, + {file = "numpy-2.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e"}, + {file = "numpy-2.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392"}, + {file = "numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008"}, + {file = "numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8"}, + {file = "numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233"}, + {file = "numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0"}, + {file = "numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a"}, + {file = "numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a"}, + {file = "numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b"}, + {file = "numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a"}, + {file = "numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d"}, + {file = "numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252"}, + {file = "numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f"}, + {file = "numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc"}, + {file = "numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74"}, + {file = "numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb"}, + {file = "numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e"}, + {file = "numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113"}, + {file = "numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d"}, + {file = "numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d"}, + {file = "numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f"}, + {file = "numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0"}, + {file = "numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150"}, + {file = "numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871"}, + {file = "numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e"}, + {file = "numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7"}, + {file = "numpy-2.4.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:58c8b5929fcb8287cbd6f0a3fae19c6e03a5c48402ae792962ac465224a629a4"}, + {file = "numpy-2.4.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:eea7ac5d2dce4189771cedb559c738a71512768210dc4e4753b107a2048b3d0e"}, + {file = "numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:51fc224f7ca4d92656d5a5eb315f12eb5fe2c97a66249aa7b5f562528a3be38c"}, + {file = "numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:28a650663f7314afc3e6ec620f44f333c386aad9f6fc472030865dc0ebb26ee3"}, + {file = "numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19710a9ca9992d7174e9c52f643d4272dcd1558c5f7af7f6f8190f633bd651a7"}, + {file = "numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b2aec6af35c113b05695ebb5749a787acd63cafc83086a05771d1e1cd1e555f"}, + {file = "numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119"}, + {file = "numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0"}, +] + +[[package]] +name = "packaging" +version = "26.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f"}, + {file = "packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de"}, +] + +[[package]] +name = "pandas" +version = "2.3.3" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c"}, + {file = "pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4"}, + {file = "pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151"}, + {file = "pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084"}, + {file = "pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493"}, + {file = "pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3"}, + {file = "pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c503ba5216814e295f40711470446bc3fd00f0faea8a086cbc688808e26f92a2"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a637c5cdfa04b6d6e2ecedcb81fc52ffb0fd78ce2ebccc9ea964df9f658de8c8"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:854d00d556406bffe66a4c0802f334c9ad5a96b4f1f868adf036a21b11ef13ff"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf1f8a81d04ca90e32a0aceb819d34dbd378a98bf923b6398b9a3ec0bf44de29"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:23ebd657a4d38268c7dfbdf089fbc31ea709d82e4923c5ffd4fbd5747133ce73"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5554c929ccc317d41a5e3d1234f3be588248e61f08a74dd17c9eabb535777dc9"}, + {file = "pandas-2.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:d3e28b3e83862ccf4d85ff19cf8c20b2ae7e503881711ff2d534dc8f761131aa"}, + {file = "pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b"}, +] + +[package.dependencies] +numpy = {version = ">=1.26.0", markers = "python_version >= \"3.12\""} +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.7" + +[package.extras] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] + +[[package]] +name = "parse" +version = "1.21.1" +description = "parse() is the opposite of format()" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "parse-1.21.1-py2.py3-none-any.whl", hash = "sha256:55339ca698019815df3b8e8b550e5933933527e623b0cdf1ca2f404da35ffb47"}, + {file = "parse-1.21.1.tar.gz", hash = "sha256:825e1a88e9d9fb481b8d2ca709c6195558b6eaa97c559ad3a9a20aa2d12815a3"}, +] + +[[package]] +name = "parse-type" +version = "0.6.6" +description = "Simplifies to build parse types based on the parse module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,>=2.7" +groups = ["dev"] +files = [ + {file = "parse_type-0.6.6-py2.py3-none-any.whl", hash = "sha256:3ca79bbe71e170dfccc8ec6c341edfd1c2a0fc1e5cfd18330f93af938de2348c"}, + {file = "parse_type-0.6.6.tar.gz", hash = "sha256:513a3784104839770d690e04339a8b4d33439fcd5dd99f2e4580f9fc1097bfb2"}, +] + +[package.dependencies] +parse = {version = ">=1.18.0", markers = "python_version >= \"3.0\""} +six = ">=1.15" + +[package.extras] +develop = ["build (>=0.5.1)", "coverage (>=4.4)", "pylint", "pytest (<5.0) ; python_version < \"3.0\"", "pytest (>=5.0) ; python_version >= \"3.0\"", "pytest-cov", "pytest-html (>=1.19.0)", "ruff ; python_version >= \"3.7\"", "setuptools", "setuptools-scm", "tox (>=2.8,<4.0)", "twine (>=1.13.0)", "virtualenv (<20.22.0) ; python_version <= \"3.6\"", "virtualenv (>=20.0.0) ; python_version > \"3.6\"", "wheel"] +docs = ["Sphinx (>=1.6)", "sphinx_bootstrap_theme (>=0.6.0)"] +testing = ["pytest (<5.0) ; python_version < \"3.0\"", "pytest (>=5.0) ; python_version >= \"3.0\"", "pytest-html (>=1.19.0)"] + +[[package]] +name = "platformdirs" +version = "4.9.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917"}, + {file = "platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a"}, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "prefixcommons" +version = "0.1.12" +description = "A python API for working with ID prefixes" +optional = false +python-versions = ">=3.7,<4.0" +groups = ["main"] +files = [ + {file = "prefixcommons-0.1.12-py3-none-any.whl", hash = "sha256:16dbc0a1f775e003c724f19a694fcfa3174608f5c8b0e893d494cf8098ac7f8b"}, + {file = "prefixcommons-0.1.12.tar.gz", hash = "sha256:22c4e2d37b63487b3ab48f0495b70f14564cb346a15220f23919eb0c1851f69f"}, +] + +[package.dependencies] +click = ">=8.1.3,<9.0.0" +pytest-logging = ">=2015.11.4,<2016.0.0" +PyYAML = ">=6.0,<7.0" +requests = ">=2.28.1,<3.0.0" + +[[package]] +name = "prefixmaps" +version = "0.2.6" +description = "A python library for retrieving semantic prefix maps" +optional = false +python-versions = "<4.0,>=3.8" +groups = ["main"] +files = [ + {file = "prefixmaps-0.2.6-py3-none-any.whl", hash = "sha256:f6cef28a7320fc6337cf411be212948ce570333a0ce958940ef684c7fb192a62"}, + {file = "prefixmaps-0.2.6.tar.gz", hash = "sha256:7421e1244eea610217fa1ba96c9aebd64e8162a930dc0626207cd8bf62ecf4b9"}, +] + +[package.dependencies] +curies = ">=0.5.3" +pyyaml = ">=5.3.1" + +[[package]] +name = "pydantic" +version = "2.13.3" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927"}, + {file = "pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.46.3" +typing-extensions = ">=4.14.1" +typing-inspection = ">=0.4.2" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.46.3" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic_core-2.46.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1da3786b8018e60349680720158cc19161cc3b4bdd815beb0a321cd5ce1ad5b1"}, + {file = "pydantic_core-2.46.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc0988cb29d21bf4a9d5cf2ef970b5c0e38d8d8e107a493278c05dc6c1dda69f"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f9067c3bfadd04c55484b89c0d267981b2f3512850f6f66e1e74204a4e4ce3"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a642ac886ecf6402d9882d10c405dcf4b902abeb2972cd5fb4a48c83cd59279a"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79f561438481f28681584b89e2effb22855e2179880314bcddbf5968e935e807"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57a973eae4665352a47cf1a99b4ee864620f2fe663a217d7a8da68a1f3a5bfda"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83d002b97072a53ea150d63e0a3adfae5670cef5aa8a6e490240e482d3b22e57"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b40ddd51e7c44b28cfaef746c9d3c506d658885e0a46f9eeef2ee815cbf8e045"}, + {file = "pydantic_core-2.46.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac5ec7fb9b87f04ee839af2d53bcadea57ded7d229719f56c0ed895bff987943"}, + {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a3b11c812f61b3129c4905781a2601dfdfdea5fe1e6c1cfb696b55d14e9c054f"}, + {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1108da631e602e5b3c38d6d04fe5bb3bfa54349e6918e3ca6cf570b2e2b2f9d4"}, + {file = "pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de885175515bcfa98ae618c1df7a072f13d179f81376c8007112af20567fd08a"}, + {file = "pydantic_core-2.46.3-cp310-cp310-win32.whl", hash = "sha256:d11058e3201527d41bc6b545c79187c9e4bf85e15a236a6007f0e991518882b7"}, + {file = "pydantic_core-2.46.3-cp310-cp310-win_amd64.whl", hash = "sha256:3612edf65c8ea67ac13616c4d23af12faef1ae435a8a93e5934c2a0cbbdd1fd6"}, + {file = "pydantic_core-2.46.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ab124d49d0459b2373ecf54118a45c28a1e6d4192a533fbc915e70f556feb8e5"}, + {file = "pydantic_core-2.46.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cca67d52a5c7a16aed2b3999e719c4bcf644074eac304a5d3d62dd70ae7d4b2c"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c024e08c0ba23e6fd68c771a521e9d6a792f2ebb0fa734296b36394dc30390e"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6645ce7eec4928e29a1e3b3d5c946621d105d3e79f0c9cddf07c2a9770949287"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a712c7118e6c5ea96562f7b488435172abb94a3c53c22c9efc1412264a45cbbe"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a868ef3ff206343579021c40faf3b1edc64b1cc508ff243a28b0a514ccb050"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7e8c32db809aa0f6ea1d6869ebc8518a65d5150fdfad8bcae6a49ae32a22e2"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3481bd1341dc85779ee506bc8e1196a277ace359d89d28588a9468c3ecbe63fa"}, + {file = "pydantic_core-2.46.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8690eba565c6d68ffd3a8655525cbdd5246510b44a637ee2c6c03a7ebfe64d3c"}, + {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4de88889d7e88d50d40ee5b39d5dac0bcaef9ba91f7e536ac064e6b2834ecccf"}, + {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:e480080975c1ef7f780b8f99ed72337e7cc5efea2e518a20a692e8e7b278eb8b"}, + {file = "pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de3a5c376f8cd94da9a1b8fd3dd1c16c7a7b216ed31dc8ce9fd7a22bf13b836e"}, + {file = "pydantic_core-2.46.3-cp311-cp311-win32.whl", hash = "sha256:fc331a5314ffddd5385b9ee9d0d2fee0b13c27e0e02dad71b1ae5d6561f51eeb"}, + {file = "pydantic_core-2.46.3-cp311-cp311-win_amd64.whl", hash = "sha256:b5b9c6cf08a8a5e502698f5e153056d12c34b8fb30317e0c5fd06f45162a6346"}, + {file = "pydantic_core-2.46.3-cp311-cp311-win_arm64.whl", hash = "sha256:5dfd51cf457482f04ec49491811a2b8fd5b843b64b11eecd2d7a1ee596ea78a6"}, + {file = "pydantic_core-2.46.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b11b59b3eee90a80a36701ddb4576d9ae31f93f05cb9e277ceaa09e6bf074a67"}, + {file = "pydantic_core-2.46.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af8653713055ea18a3abc1537fe2ebc42f5b0bbb768d1eb79fd74eb47c0ac089"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75a519dab6d63c514f3a81053e5266c549679e4aa88f6ec57f2b7b854aceb1b0"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6cd87cb1575b1ad05ba98894c5b5c96411ef678fa2f6ed2576607095b8d9789"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f80a55484b8d843c8ada81ebf70a682f3f00a3d40e378c06cf17ecb44d280d7d"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3861f1731b90c50a3266316b9044f5c9b405eecb8e299b0a7120596334e4fe9c"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb528e295ed31570ac3dcc9bfdd6e0150bc11ce6168ac87a8082055cf1a67395"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:367508faa4973b992b271ba1494acaab36eb7e8739d1e47be5035fb1ea225396"}, + {file = "pydantic_core-2.46.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ad3c826fe523e4becf4fe39baa44286cff85ef137c729a2c5e269afbfd0905d"}, + {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ec638c5d194ef8af27db69f16c954a09797c0dc25015ad6123eb2c73a4d271ca"}, + {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:28ed528c45446062ee66edb1d33df5d88828ae167de76e773a3c7f64bd14e976"}, + {file = "pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aed19d0c783886d5bd86d80ae5030006b45e28464218747dcf83dabfdd092c7b"}, + {file = "pydantic_core-2.46.3-cp312-cp312-win32.whl", hash = "sha256:06d5d8820cbbdb4147578c1fe7ffcd5b83f34508cb9f9ab76e807be7db6ff0a4"}, + {file = "pydantic_core-2.46.3-cp312-cp312-win_amd64.whl", hash = "sha256:c3212fda0ee959c1dd04c60b601ec31097aaa893573a3a1abd0a47bcac2968c1"}, + {file = "pydantic_core-2.46.3-cp312-cp312-win_arm64.whl", hash = "sha256:f1f8338dd7a7f31761f1f1a3c47503a9a3b34eea3c8b01fa6ee96408affb5e72"}, + {file = "pydantic_core-2.46.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:12bc98de041458b80c86c56b24df1d23832f3e166cbaff011f25d187f5c62c37"}, + {file = "pydantic_core-2.46.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:85348b8f89d2c3508b65b16c3c33a4da22b8215138d8b996912bb1532868885f"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1105677a6df914b1fb71a81b96c8cce7726857e1717d86001f29be06a25ee6f8"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87082cd65669a33adeba5470769e9704c7cf026cc30afb9cc77fd865578ebaad"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e5f66e12c4f5212d08522963380eaaeac5ebd795826cfd19b2dfb0c7a52b9c"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6cdf19bf84128d5e7c37e8a73a0c5c10d51103a650ac585d42dd6ae233f2b7f"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031bb17f4885a43773c8c763089499f242aee2ea85cf17154168775dccdecf35"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:bcf2a8b2982a6673693eae7348ef3d8cf3979c1d63b54fca7c397a635cc68687"}, + {file = "pydantic_core-2.46.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28e8cf2f52d72ced402a137145923a762cbb5081e48b34312f7a0c8f55928ec3"}, + {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:17eaface65d9fc5abb940003020309c1bf7a211f5f608d7870297c367e6f9022"}, + {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:93fd339f23408a07e98950a89644f92c54d8729719a40b30c0a30bb9ebc55d23"}, + {file = "pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:23cbdb3aaa74dfe0837975dbf69b469753bbde8eacace524519ffdb6b6e89eb7"}, + {file = "pydantic_core-2.46.3-cp313-cp313-win32.whl", hash = "sha256:610eda2e3838f401105e6326ca304f5da1e15393ae25dacae5c5c63f2c275b13"}, + {file = "pydantic_core-2.46.3-cp313-cp313-win_amd64.whl", hash = "sha256:68cc7866ed863db34351294187f9b729964c371ba33e31c26f478471c52e1ed0"}, + {file = "pydantic_core-2.46.3-cp313-cp313-win_arm64.whl", hash = "sha256:f64b5537ac62b231572879cd08ec05600308636a5d63bcbdb15063a466977bec"}, + {file = "pydantic_core-2.46.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:afa3aa644f74e290cdede48a7b0bee37d1c35e71b05105f6b340d484af536d9b"}, + {file = "pydantic_core-2.46.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ced3310e51aa425f7f77da8bbbb5212616655bedbe82c70944320bc1dbe5e018"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e29908922ce9da1a30b4da490bd1d3d82c01dcfdf864d2a74aacee674d0bfa34"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c9ff69140423eea8ed2d5477df3ba037f671f5e897d206d921bc9fdc39613e7"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b675ab0a0d5b1c8fdb81195dc5bcefea3f3c240871cdd7ff9a2de8aa50772eb2"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0087084960f209a9a4af50ecd1fb063d9ad3658c07bb81a7a53f452dacbfb2ba"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed42e6cc8e1b0e2b9b96e2276bad70ae625d10d6d524aed0c93de974ae029f9f"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f1771ce258afb3e4201e67d154edbbae712a76a6081079fe247c2f53c6322c22"}, + {file = "pydantic_core-2.46.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a7610b6a5242a6c736d8ad47fd5fff87fcfe8f833b281b1c409c3d6835d9227f"}, + {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ff5e7783bcc5476e1db448bf268f11cb257b1c276d3e89f00b5727be86dd0127"}, + {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9d2e32edcc143bc01e95300671915d9ca052d4f745aa0a49c48d4803f8a85f2c"}, + {file = "pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d83d1c6b87fa56b521479cff237e626a292f3b31b6345c15a99121b454c1"}, + {file = "pydantic_core-2.46.3-cp314-cp314-win32.whl", hash = "sha256:07bc6d2a28c3adb4f7c6ae46aa4f2d2929af127f587ed44057af50bf1ce0f505"}, + {file = "pydantic_core-2.46.3-cp314-cp314-win_amd64.whl", hash = "sha256:8940562319bc621da30714617e6a7eaa6b98c84e8c685bcdc02d7ed5e7c7c44e"}, + {file = "pydantic_core-2.46.3-cp314-cp314-win_arm64.whl", hash = "sha256:5dcbbcf4d22210ced8f837c96db941bdb078f419543472aca5d9a0bb7cddc7df"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d0fe3dce1e836e418f912c1ad91c73357d03e556a4d286f441bf34fed2dbeecf"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9ce92e58abc722dac1bf835a6798a60b294e48eb0e625ec9fd994b932ac5feee"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03e6467f0f5ab796a486146d1b887b2dc5e5f9b3288898c1b1c3ad974e53e4a"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2798b6ba041b9d70acfb9071a2ea13c8456dd1e6a5555798e41ba7b0790e329c"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9be3e221bdc6d69abf294dcf7aff6af19c31a5cdcc8f0aa3b14be29df4bd03b1"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13936129ce841f2a5ddf6f126fea3c43cd128807b5a59588c37cf10178c2e64"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b5f2ef03416facccb1c6ef744c69793175fd27e44ef15669201601cf423acb"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:830d1247d77ad23852314f069e9d7ddafeec5f684baf9d7e7065ed46a049c4e6"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0793c90c1a3c74966e7975eaef3ed30ebdff3260a0f815a62a22adc17e4c01c"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d2d0aead851b66f5245ec0c4fb2612ef457f8bbafefdf65a2bf9d6bac6140f47"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:2f40e4246676beb31c5ce77c38a55ca4e465c6b38d11ea1bd935420568e0b1ab"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:cf489cf8986c543939aeee17a09c04d6ffb43bfef8ca16fcbcc5cfdcbed24dba"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-win32.whl", hash = "sha256:ffe0883b56cfc05798bf994164d2b2ff03efe2d22022a2bb080f3b626176dd56"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-win_amd64.whl", hash = "sha256:706d9d0ce9cf4593d07270d8e9f53b161f90c57d315aeec4fb4fd7a8b10240d8"}, + {file = "pydantic_core-2.46.3-cp314-cp314t-win_arm64.whl", hash = "sha256:77706aeb41df6a76568434701e0917da10692da28cb69d5fb6919ce5fdb07374"}, + {file = "pydantic_core-2.46.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fa3eb7c2995aa443687a825bc30395c8521b7c6ec201966e55debfd1128bcceb"}, + {file = "pydantic_core-2.46.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d08782c4045f90724b44c95d35ebec0d67edb8a957a2ac81d5a8e4b8a200495"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:831eb19aa789a97356979e94c981e5667759301fb708d1c0d5adf1bc0098b873"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4335e87c7afa436a0dfa899e138d57a72f8aad542e2cf19c36fb428461caabd0"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99421e7684a60f7f3550a1d159ade5fdff1954baedb6bdd407cba6a307c9f27d"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd81f6907932ebac3abbe41378dac64b2380db1287e2aa64d8d88f78d170f51a"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f247596366f4221af52beddd65af1218797771d6989bc891a0b86ccaa019168"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:6dff8cc884679df229ebc6d8eb2321ea6f8e091bc7d4886d4dc2e0e71452843c"}, + {file = "pydantic_core-2.46.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68ef2f623dda6d5a9067ac014e406c020c780b2a358930a7e5c1b73702900720"}, + {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d56bdb4af1767cc15b0386b3c581fdfe659bb9ee4a4f776e92c1cd9d074000d6"}, + {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:91249bcb7c165c2fb2a2f852dbc5c91636e2e218e75d96dfdd517e4078e173dd"}, + {file = "pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b068543bdb707f5d935dab765d99227aa2545ef2820935f2e5dd801795c7dbd"}, + {file = "pydantic_core-2.46.3-cp39-cp39-win32.whl", hash = "sha256:dcda6583921c05a40533f982321532f2d8db29326c7b95c4026941fa5074bd79"}, + {file = "pydantic_core-2.46.3-cp39-cp39-win_amd64.whl", hash = "sha256:a35cc284c8dd7edae8a31533713b4d2467dfe7c4f1b5587dd4031f28f90d1d13"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:9715525891ed524a0a1eb6d053c74d4d4ad5017677fb00af0b7c2644a31bae46"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:9d2f400712a99a013aff420ef1eb9be077f8189a36c1e3ef87660b4e1088a874"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd2aab0e2e9dc2daf36bd2686c982535d5e7b1d930a1344a7bb6e82baab42a76"}, + {file = "pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9d76736da5f362fabfeea6a69b13b7f2be405c6d6966f06b2f6bfff7e64531"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:b12dd51f1187c2eb489af8e20f880362db98e954b54ab792fa5d92e8bcc6b803"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f00a0961b125f1a47af7bcc17f00782e12f4cd056f83416006b30111d941dfa3"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57697d7c056aca4bbb680200f96563e841a6386ac1129370a0102592f4dddff5"}, + {file = "pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd35aa21299def8db7ef4fe5c4ff862941a9a158ca7b63d61e66fe67d30416b4"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:13afdd885f3d71280cf286b13b310ee0f7ccfefd1dbbb661514a474b726e2f25"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f91c0aff3e3ee0928edd1232c57f643a7a003e6edf1860bc3afcdc749cb513f3"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6529d1d128321a58d30afcc97b49e98836542f68dd41b33c2e972bb9e5290536"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:975c267cff4f7e7272eacbe50f6cc03ca9a3da4c4fbd66fffd89c94c1e311aa1"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2b8e4f2bbdf71415c544b4b1138b8060db7b6611bc927e8064c769f64bed651c"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e61ea8e9fff9606d09178f577ff8ccdd7206ff73d6552bcec18e1033c4254b85"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b504bda01bafc69b6d3c7a0c7f039dcf60f47fab70e06fe23f57b5c75bdc82b8"}, + {file = "pydantic_core-2.46.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b00b76f7142fc60c762ce579bd29c8fa44aaa56592dd3c54fab3928d0d4ca6ff"}, + {file = "pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c"}, +] + +[package.dependencies] +typing-extensions = ">=4.14.1" + +[[package]] +name = "pygments" +version = "2.20.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pylint" +version = "3.3.9" +description = "python code static checker" +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "pylint-3.3.9-py3-none-any.whl", hash = "sha256:01f9b0462c7730f94786c283f3e52a1fbdf0494bbe0971a78d7277ef46a751e7"}, + {file = "pylint-3.3.9.tar.gz", hash = "sha256:d312737d7b25ccf6b01cc4ac629b5dcd14a0fcf3ec392735ac70f137a9d5f83a"}, +] + +[package.dependencies] +astroid = ">=3.3.8,<=3.4.0.dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = {version = ">=0.3.7", markers = "python_version >= \"3.12\""} +isort = ">=4.2.5,<5.13 || >5.13,<7" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2" +tomlkit = ">=0.10.1" + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pyparsing" +version = "3.3.2" +description = "pyparsing - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pyproject-api" +version = "1.10.0" +description = "API to interact with the python pyproject.toml based projects" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "pyproject_api-1.10.0-py3-none-any.whl", hash = "sha256:8757c41a79c0f4ab71b99abed52b97ecf66bd20b04fa59da43b5840bac105a09"}, + {file = "pyproject_api-1.10.0.tar.gz", hash = "sha256:40c6f2d82eebdc4afee61c773ed208c04c19db4c4a60d97f8d7be3ebc0bbb330"}, +] + +[package.dependencies] +packaging = ">=25" + +[package.extras] +docs = ["furo (>=2025.9.25)", "sphinx-autodoc-typehints (>=3.5.1)"] +testing = ["covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)", "setuptools (>=80.9)"] + +[[package]] +name = "pystow" +version = "0.8.5" +description = "Easily pick a place to store data for your Python code" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "pystow-0.8.5-py3-none-any.whl", hash = "sha256:a8593a22ec6a16c39ee0458b393db30abbba1e9f95f2865c5793df7e81c51e9e"}, + {file = "pystow-0.8.5.tar.gz", hash = "sha256:c918ead173ed5d0234a888e3d480e00d3fe3ee608c9fc0722796d72aa4e44438"}, +] + +[package.dependencies] +tqdm = "*" +typing-extensions = "*" + +[package.extras] +aws = ["boto3"] +bs4 = ["bs4", "requests"] +cli = ["click"] +pandas = ["pandas"] +pydantic = ["pydantic"] +ratelimit = ["ratelimit", "requests"] +rdf = ["rdflib"] +requests = ["requests"] +xml = ["lxml"] +yaml = ["pyyaml"] + +[[package]] +name = "pytest" +version = "9.0.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"}, + {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-bdd" +version = "8.1.0" +description = "BDD for pytest" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_bdd-8.1.0-py3-none-any.whl", hash = "sha256:2124051e71a05ad7db15296e39013593f72ebf96796e1b023a40e5453c47e5fb"}, + {file = "pytest_bdd-8.1.0.tar.gz", hash = "sha256:ef0896c5cd58816dc49810e8ff1d632f4a12019fb3e49959b2d349ffc1c9bfb5"}, +] + +[package.dependencies] +gherkin-official = ">=29.0.0,<30.0.0" +Mako = "*" +packaging = "*" +parse = "*" +parse-type = "*" +pytest = ">=7.0.0" +typing-extensions = "*" + +[[package]] +name = "pytest-cov" +version = "6.3.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_cov-6.3.0-py3-none-any.whl", hash = "sha256:440db28156d2468cafc0415b4f8e50856a0d11faefa38f30906048fe490f1749"}, + {file = "pytest_cov-6.3.0.tar.gz", hash = "sha256:35c580e7800f87ce892e687461166e1ac2bcb8fb9e13aea79032518d6e503ff2"}, +] + +[package.dependencies] +coverage = {version = ">=7.5", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=6.2.5" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-logging" +version = "2015.11.4" +description = "Configures logging and allows tweaking the log level with a py.test flag" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pytest-logging-2015.11.4.tar.gz", hash = "sha256:cec5c85ecf18aab7b2ead5498a31b9f758680ef5a902b9054ab3f2bdbb77c896"}, +] + +[package.dependencies] +pytest = ">=2.8.1" + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-discovery" +version = "1.2.2" +description = "Python interpreter discovery" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a"}, + {file = "python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb"}, +] + +[package.dependencies] +filelock = ">=3.15.4" +platformdirs = ">=4.3.6,<5" + +[package.extras] +docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, + {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "pytz" +version = "2026.1.post1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a"}, + {file = "pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1"}, +] + +[[package]] +name = "pywin32" +version = "311" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +groups = ["dev"] +markers = "sys_platform == \"win32\"" +files = [ + {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, + {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, + {file = "pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b"}, + {file = "pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151"}, + {file = "pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503"}, + {file = "pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2"}, + {file = "pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31"}, + {file = "pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067"}, + {file = "pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852"}, + {file = "pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d"}, + {file = "pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d"}, + {file = "pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a"}, + {file = "pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee"}, + {file = "pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87"}, + {file = "pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42"}, + {file = "pywin32-311-cp38-cp38-win32.whl", hash = "sha256:6c6f2969607b5023b0d9ce2541f8d2cbb01c4f46bc87456017cf63b73f1e2d8c"}, + {file = "pywin32-311-cp38-cp38-win_amd64.whl", hash = "sha256:c8015b09fb9a5e188f83b7b04de91ddca4658cee2ae6f3bc483f0b21a77ef6cd"}, + {file = "pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b"}, + {file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"}, + {file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, +] + +[[package]] +name = "radon" +version = "6.0.1" +description = "Code Metrics in Python" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "radon-6.0.1-py2.py3-none-any.whl", hash = "sha256:632cc032364a6f8bb1010a2f6a12d0f14bc7e5ede76585ef29dc0cecf4cd8859"}, + {file = "radon-6.0.1.tar.gz", hash = "sha256:d1ac0053943a893878940fedc8b19ace70386fc9c9bf0a09229a44125ebf45b5"}, +] + +[package.dependencies] +colorama = {version = ">=0.4.1", markers = "python_version > \"3.4\""} +mando = ">=0.6,<0.8" + +[package.extras] +toml = ["tomli (>=2.0.1)"] + +[[package]] +name = "rdflib" +version = "7.6.0" +description = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information." +optional = false +python-versions = ">=3.8.1" +groups = ["main"] +files = [ + {file = "rdflib-7.6.0-py3-none-any.whl", hash = "sha256:30c0a3ebf4c0e09215f066be7246794b6492e054e782d7ac2a34c9f70a15e0dd"}, + {file = "rdflib-7.6.0.tar.gz", hash = "sha256:6c831288d5e4a5a7ece85d0ccde9877d512a3d0f02d7c06455d00d6d0ea379df"}, +] + +[package.dependencies] +pyparsing = ">=2.1.0,<4" + +[package.extras] +berkeleydb = ["berkeleydb (>=18.1.0,<19.0.0)"] +graphdb = ["httpx (>=0.28.1,<0.29.0)"] +html = ["html5rdf (>=1.2,<2)"] +lxml = ["lxml (>=4.3,<6.0)"] +networkx = ["networkx (>=2,<4)"] +orjson = ["orjson (>=3.9.14,<4)"] +rdf4j = ["httpx (>=0.28.1,<0.29.0)"] + +[[package]] +name = "redis" +version = "7.4.0" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "redis-7.4.0-py3-none-any.whl", hash = "sha256:a9c74a5c893a5ef8455a5adb793a31bb70feb821c86eccb62eebef5a19c429ec"}, + {file = "redis-7.4.0.tar.gz", hash = "sha256:64a6ea7bf567ad43c964d2c30d82853f8df927c5c9017766c55a1d1ed95d18ad"}, +] + +[package.extras] +circuit-breaker = ["pybreaker (>=1.4.0)"] +hiredis = ["hiredis (>=3.2.0)"] +jwt = ["pyjwt (>=2.9.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (>=20.0.1)", "requests (>=2.31.0)"] +otel = ["opentelemetry-api (>=1.39.1)", "opentelemetry-exporter-otlp-proto-http (>=1.39.1)", "opentelemetry-sdk (>=1.39.1)"] +xxhash = ["xxhash (>=3.6.0,<3.7.0)"] + +[[package]] +name = "referencing" +version = "0.37.0" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231"}, + {file = "referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" +typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} + +[[package]] +name = "requests" +version = "2.33.1" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.10" +groups = ["main", "dev"] +files = [ + {file = "requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a"}, + {file = "requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"}, +] + +[package.dependencies] +certifi = ">=2023.5.7" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.26,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] + +[[package]] +name = "rich" +version = "15.0.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.9.0" +groups = ["dev"] +files = [ + {file = "rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb"}, + {file = "rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rpds-py" +version = "0.30.0" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139"}, + {file = "rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464"}, + {file = "rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85"}, + {file = "rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394"}, + {file = "rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95"}, + {file = "rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53"}, + {file = "rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e"}, + {file = "rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84"}, +] + +[[package]] +name = "ruff" +version = "0.15.11" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ruff-0.15.11-py3-none-linux_armv6l.whl", hash = "sha256:e927cfff503135c558eb581a0c9792264aae9507904eb27809cdcff2f2c847b7"}, + {file = "ruff-0.15.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7a1b5b2938d8f890b76084d4fa843604d787a912541eae85fd7e233398bbb73e"}, + {file = "ruff-0.15.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d4176f3d194afbdaee6e41b9ccb1a2c287dba8700047df474abfbe773825d1cb"}, + {file = "ruff-0.15.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b17c886fb88203ced3afe7f14e8d5ae96e9d2f4ccc0ee66aa19f2c2675a27e4"}, + {file = "ruff-0.15.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:49fafa220220afe7758a487b048de4c8f9f767f37dfefad46b9dd06759d003eb"}, + {file = "ruff-0.15.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2ab8427e74a00d93b8bda1307b1e60970d40f304af38bccb218e056c220120d"}, + {file = "ruff-0.15.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:195072c0c8e1fc8f940652073df082e37a5d9cb43b4ab1e4d0566ab8977a13b7"}, + {file = "ruff-0.15.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3a0996d486af3920dec930a2e7daed4847dfc12649b537a9335585ada163e9e"}, + {file = "ruff-0.15.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bef2cb556d509259f1fe440bb9cd33c756222cf0a7afe90d15edf0866702431"}, + {file = "ruff-0.15.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:030d921a836d7d4a12cf6e8d984a88b66094ccb0e0f17ddd55067c331191bf19"}, + {file = "ruff-0.15.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0e783b599b4577788dbbb66b9addcef87e9a8832f4ce0c19e34bf55543a2f890"}, + {file = "ruff-0.15.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ae90592246625ba4a34349d68ec28d4400d75182b71baa196ddb9f82db025ef5"}, + {file = "ruff-0.15.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1f111d62e3c983ed20e0ca2e800f8d77433a5b1161947df99a5c2a3fb60514f0"}, + {file = "ruff-0.15.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:06f483d6646f59eaffba9ae30956370d3a886625f511a3108994000480621d1c"}, + {file = "ruff-0.15.11-py3-none-win32.whl", hash = "sha256:476a2aa56b7da0b73a3ee80b6b2f0e19cce544245479adde7baa65466664d5f3"}, + {file = "ruff-0.15.11-py3-none-win_amd64.whl", hash = "sha256:8b6756d88d7e234fb0c98c91511aae3cd519d5e3ed271cae31b20f39cb2a12a3"}, + {file = "ruff-0.15.11-py3-none-win_arm64.whl", hash = "sha256:063fed18cc1bbe0ee7393957284a6fe8b588c6a406a285af3ee3f46da2391ee4"}, + {file = "ruff-0.15.11.tar.gz", hash = "sha256:f092b21708bf0e7437ce9ada249dfe688ff9a0954fc94abab05dcea7dcd29c33"}, +] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "splink" +version = "4.0.16" +description = "Fast probabilistic data linkage at scale" +optional = false +python-versions = "<4.0.0,>=3.9.0" +groups = ["main"] +files = [ + {file = "splink-4.0.16-py3-none-any.whl", hash = "sha256:32b0ad5ab171fb4524337c64b3265ef7432fc7bcb3fff4245d172a042c354bb8"}, + {file = "splink-4.0.16.tar.gz", hash = "sha256:a4be4ab1ed4de350667418ed29ad98aac9239e97f5135cc666c45f3043f3aae8"}, +] + +[package.dependencies] +altair = ">=5.0.1" +duckdb = ">=0.9.2" +igraph = ">=0.11.2" +jinja2 = ">=3.0.3" +numpy = ">=1.19.3" +pandas = ">=1.3.5" +sqlglot = ">=17.6.0" + +[package.extras] +athena = ["awswrangler"] +postgres = ["psycopg2-binary (>=2.9.0)", "sqlalchemy (>=2.0.0)"] +pyspark = ["pyspark (>=3.5.0)"] +spark = ["pyspark (>=3.5.0)"] + +[[package]] +name = "sqlglot" +version = "30.6.0" +description = "An easily customizable SQL parser and transpiler" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "sqlglot-30.6.0-py3-none-any.whl", hash = "sha256:e005fc2f47994f90d7d8df341f1cbe937518497b0b7b1507d4c03c4c9dfd2778"}, + {file = "sqlglot-30.6.0.tar.gz", hash = "sha256:246d34d39927422a50a3fa155f37b2f6346fba85f1a755b13c941eb32ef93361"}, +] + +[package.extras] +c = ["sqlglotc (==30.6.0)"] +dev = ["duckdb (>=0.6)", "pandas", "pandas-stubs", "pdoc", "pre-commit", "pyperf", "python-dateutil", "pytz", "ruff (==0.15.6)", "setuptools_scm", "sqlglot-mypy", "types-python-dateutil", "types-pytz", "typing_extensions"] +rs = ["sqlglotc (==30.6.0)", "sqlglotrs (==0.13.0)"] + +[[package]] +name = "testcontainers" +version = "4.14.2" +description = "Python library for throwaway instances of anything that can run in a Docker container" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "testcontainers-4.14.2-py3-none-any.whl", hash = "sha256:0d0522c3cd8f8d9627cda41f7a6b51b639fa57bdc492923c045117933c668d68"}, + {file = "testcontainers-4.14.2.tar.gz", hash = "sha256:1340ccf16fe3acd9389a6c9e1d9ab21d9fe99a8afdf8165f89c3e69c1967d239"}, +] + +[package.dependencies] +docker = "*" +python-dotenv = "*" +redis = {version = ">=7", optional = true, markers = "extra == \"redis\""} +typing-extensions = "*" +urllib3 = "*" +wrapt = "*" + +[package.extras] +arangodb = ["python-arango (>=8)"] +aws = ["boto3 (>=1)", "httpx"] +azurite = ["azure-storage-blob (>=12)"] +chroma = ["chromadb-client (>=1)"] +clickhouse = ["clickhouse-driver"] +cosmosdb = ["azure-cosmos (>=4)"] +db2 = ["ibm-db-sa ; platform_machine != \"aarch64\" and platform_machine != \"arm64\"", "sqlalchemy (>=2)"] +generic = ["httpx", "redis (>=7)"] +google = ["google-cloud-datastore (>=2)", "google-cloud-pubsub (>=2)"] +influxdb = ["influxdb (>=5)", "influxdb-client (>=1)"] +k3s = ["kubernetes", "pyyaml (>=6.0.3)"] +keycloak = ["python-keycloak (>=6) ; python_version < \"4.0\""] +localstack = ["boto3 (>=1)"] +mailpit = ["cryptography"] +minio = ["minio (>=7)"] +mongodb = ["pymongo (>=4)"] +mssql = ["pymssql (>=2)", "sqlalchemy (>=2)"] +mysql = ["pymysql[rsa] (>=1)", "sqlalchemy (>=2)"] +nats = ["nats-py (>=2)"] +neo4j = ["neo4j (>=6)"] +openfga = ["openfga-sdk"] +opensearch = ["opensearch-py (>=3) ; python_version < \"4.0\""] +oracle = ["oracledb (>=3)", "sqlalchemy (>=2)"] +oracle-free = ["oracledb (>=3)", "sqlalchemy (>=2)"] +qdrant = ["qdrant-client (>=1)"] +rabbitmq = ["pika (>=1)"] +redis = ["redis (>=7)"] +registry = ["bcrypt (>=5)"] +scylla = ["cassandra-driver (>=3)"] +selenium = ["selenium (>=4)"] +sftp = ["cryptography"] +test-module-import = ["httpx"] +trino = ["trino"] +weaviate = ["weaviate-client (>=4)"] + +[[package]] +name = "texttable" +version = "1.7.0" +description = "module to create simple ASCII tables" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917"}, + {file = "texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638"}, +] + +[[package]] +name = "tomli-w" +version = "1.2.0" +description = "A lil' TOML writer" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90"}, + {file = "tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021"}, +] + +[[package]] +name = "tomlkit" +version = "0.14.0" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "tomlkit-0.14.0-py3-none-any.whl", hash = "sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680"}, + {file = "tomlkit-0.14.0.tar.gz", hash = "sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064"}, +] + +[[package]] +name = "tox" +version = "4.53.0" +description = "tox is a generic virtualenv management and test command line tool" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "tox-4.53.0-py3-none-any.whl", hash = "sha256:cc4e716d18c4889aa179d785175c438fa60c35deef20ce689ec288d8fb656096"}, + {file = "tox-4.53.0.tar.gz", hash = "sha256:62c780e42f87d34ee60f2ea20342156253794fdcbd6885fd797d98ee05009f22"}, +] + +[package.dependencies] +cachetools = ">=7.0.3" +colorama = ">=0.4.6" +filelock = ">=3.25" +packaging = ">=26" +platformdirs = ">=4.9.4" +pluggy = ">=1.6" +pyproject-api = ">=1.10" +python-discovery = ">=1.2.2" +tomli-w = ">=1.2" +virtualenv = ">=21.1" + +[package.extras] +completion = ["argcomplete (>=3.6.3)"] + +[[package]] +name = "tqdm" +version = "4.67.3" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf"}, + {file = "tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "tzdata" +version = "2026.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +groups = ["main"] +files = [ + {file = "tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9"}, + {file = "tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98"}, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, +] + +[package.extras] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] + +[[package]] +name = "virtualenv" +version = "21.2.4" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "virtualenv-21.2.4-py3-none-any.whl", hash = "sha256:29d21e941795206138d0f22f4e45ff7050e5da6c6472299fb7103318763861ac"}, + {file = "virtualenv-21.2.4.tar.gz", hash = "sha256:b294ef68192638004d72524ce7ef303e9d0cf5a44c95ce2e54a7500a6381cada"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} +platformdirs = ">=3.9.1,<5" +python-discovery = ">=1.2.2" + +[[package]] +name = "wrapt" +version = "2.1.2" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "wrapt-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a86d99a14f76facb269dc148590c01aaf47584071809a70da30555228158c"}, + {file = "wrapt-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a819e39017f95bf7aede768f75915635aa8f671f2993c036991b8d3bfe8dbb6f"}, + {file = "wrapt-2.1.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5681123e60aed0e64c7d44f72bbf8b4ce45f79d81467e2c4c728629f5baf06eb"}, + {file = "wrapt-2.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8b28e97a44d21836259739ae76284e180b18abbb4dcfdff07a415cf1016c3e"}, + {file = "wrapt-2.1.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cef91c95a50596fcdc31397eb6955476f82ae8a3f5a8eabdc13611b60ee380ba"}, + {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dad63212b168de8569b1c512f4eac4b57f2c6934b30df32d6ee9534a79f1493f"}, + {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d307aa6888d5efab2c1cde09843d48c843990be13069003184b67d426d145394"}, + {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c87cf3f0c85e27b3ac7d9ad95da166bf8739ca215a8b171e8404a2d739897a45"}, + {file = "wrapt-2.1.2-cp310-cp310-win32.whl", hash = "sha256:d1c5fea4f9fe3762e2b905fdd67df51e4be7a73b7674957af2d2ade71a5c075d"}, + {file = "wrapt-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:d8f7740e1af13dff2684e4d56fe604a7e04d6c94e737a60568d8d4238b9a0c71"}, + {file = "wrapt-2.1.2-cp310-cp310-win_arm64.whl", hash = "sha256:1c6cc827c00dc839350155f316f1f8b4b0c370f52b6a19e782e2bda89600c7dc"}, + {file = "wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb"}, + {file = "wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d"}, + {file = "wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894"}, + {file = "wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842"}, + {file = "wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8"}, + {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6"}, + {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9"}, + {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15"}, + {file = "wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b"}, + {file = "wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1"}, + {file = "wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a"}, + {file = "wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9"}, + {file = "wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748"}, + {file = "wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e"}, + {file = "wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8"}, + {file = "wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c"}, + {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c"}, + {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1"}, + {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2"}, + {file = "wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0"}, + {file = "wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63"}, + {file = "wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf"}, + {file = "wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b"}, + {file = "wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e"}, + {file = "wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb"}, + {file = "wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca"}, + {file = "wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267"}, + {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f"}, + {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8"}, + {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413"}, + {file = "wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6"}, + {file = "wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1"}, + {file = "wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf"}, + {file = "wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b"}, + {file = "wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18"}, + {file = "wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d"}, + {file = "wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015"}, + {file = "wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92"}, + {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf"}, + {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67"}, + {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a"}, + {file = "wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd"}, + {file = "wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f"}, + {file = "wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679"}, + {file = "wrapt-2.1.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9"}, + {file = "wrapt-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9"}, + {file = "wrapt-2.1.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e"}, + {file = "wrapt-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c"}, + {file = "wrapt-2.1.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a"}, + {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90"}, + {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586"}, + {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19"}, + {file = "wrapt-2.1.2-cp314-cp314-win32.whl", hash = "sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508"}, + {file = "wrapt-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04"}, + {file = "wrapt-2.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575"}, + {file = "wrapt-2.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb"}, + {file = "wrapt-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22"}, + {file = "wrapt-2.1.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596"}, + {file = "wrapt-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044"}, + {file = "wrapt-2.1.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b"}, + {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf"}, + {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2"}, + {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3"}, + {file = "wrapt-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7"}, + {file = "wrapt-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5"}, + {file = "wrapt-2.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00"}, + {file = "wrapt-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5e0fa9cc32300daf9eb09a1f5bdc6deb9a79defd70d5356ba453bcd50aef3742"}, + {file = "wrapt-2.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:710f6e5dfaf6a5d5c397d2d6758a78fecd9649deb21f1b645f5b57a328d63050"}, + {file = "wrapt-2.1.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:305d8a1755116bfdad5dda9e771dcb2138990a1d66e9edd81658816edf51aed1"}, + {file = "wrapt-2.1.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0d8fc30a43b5fe191cf2b1a0c82bab2571dadd38e7c0062ee87d6df858dd06e"}, + {file = "wrapt-2.1.2-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a5d516e22aedb7c9c1d47cba1c63160b1a6f61ec2f3948d127cd38d5cfbb556f"}, + {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:45914e8efbe4b9d5102fcf0e8e2e3258b83a5d5fba9f8f7b6d15681e9d29ffe0"}, + {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:478282ebd3795a089154fb16d3db360e103aa13d3b2ad30f8f6aac0d2207de0e"}, + {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3756219045f73fb28c5d7662778e4156fbd06cf823c4d2d4b19f97305e52819c"}, + {file = "wrapt-2.1.2-cp39-cp39-win32.whl", hash = "sha256:b8aefb4dbb18d904b96827435a763fa42fc1f08ea096a391710407a60983ced8"}, + {file = "wrapt-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:e5aeab8fe15c3dff75cfee94260dcd9cded012d4ff06add036c28fae7718593b"}, + {file = "wrapt-2.1.2-cp39-cp39-win_arm64.whl", hash = "sha256:f069e113743a21a3defac6677f000068ebb931639f789b5b226598e247a4c89e"}, + {file = "wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8"}, + {file = "wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e"}, +] + +[package.extras] +dev = ["pytest", "setuptools"] + +[[package]] +name = "xenon" +version = "0.9.3" +description = "Monitor code metrics for Python on your CI server" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "xenon-0.9.3-py2.py3-none-any.whl", hash = "sha256:6e2c2c251cc5e9d01fe984e623499b13b2140fcbf74d6c03a613fa43a9347097"}, + {file = "xenon-0.9.3.tar.gz", hash = "sha256:4a7538d8ba08aa5d79055fb3e0b2393c0bd6d7d16a4ab0fcdef02ef1f10a43fa"}, +] + +[package.dependencies] +PyYAML = ">=5.0,<7.0" +radon = ">=4,<7" +requests = ">=2.0,<3.0" + +[metadata] +lock-version = "2.1" +python-versions = ">=3.12,<3.15" +content-hash = "a74fb6a86c6e0f5bd7163394aeceb779b6c13ab388a20b1f8727d6c84d32c92b" diff --git a/src/pyproject.toml b/src/pyproject.toml new file mode 100644 index 0000000..3c1e981 --- /dev/null +++ b/src/pyproject.toml @@ -0,0 +1,94 @@ +[project] +name = "ere-basic" +version = "1.1.0" +description = "A basic implementation of the Entity Resolution Engine (ERE)." +authors = [ + {name = "Publications Office of the European Union"} +] +readme = "../README.md" +requires-python = ">=3.12,<3.15" + + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +packages = [ + { include = "ere" } +] + + +[dependency-groups] +dev = [ + "pytest==9.0.3", + "pytest-bdd==8.1.0", + "pytest-cov==6.3.0", + "assertpy==1.1", + "ruff==0.15.11", + "pylint==3.3.9", + "import-linter==2.11", + "tox==4.53.0", + "radon==6.0.1", + "xenon==0.9.3", + "testcontainers[redis]==4.14.2", +] + +[tool.poetry.dependencies] +pydantic = "2.13.3" +redis = "7.4.0" +linkml-runtime = "1.10.0" +urllib3 = "2.6.3" +charset-normalizer = "3.4.7" +chardet = "5.2.0" +duckdb = "1.5.2" +pandas = "2.3.3" +splink = "4.0.16" +rdflib = "7.6.0" +pyyaml = "6.0.3" + +# TODO: should we have a registry? +ers-spec = { git = "https://github.com/OP-TED/entity-resolution-spec.git", branch = "release/1.1.0", subdirectory = "src" } + + +[tool.pytest.ini_options] +addopts = [ + "-v", + "--basetemp=/tmp/pytest", + "--cov=ere", + "--cov-report=term-missing", + "--cov-fail-under=80", +] +testpaths = ["../test"] +# Skips warning from 3rd party libs, such as rdflib +filterwarnings = [ + "once", + "ignore", + "default::Warning:ere\\..*" +] +# Logging is set up in conftest.py + + +[tool.ruff.lint] +select = ["E", "F", "I", "N", "C90"] +ignore = ["E501"] + +[tool.ruff.lint.mccabe] +max-complexity = 10 + + +[tool.mypy] +python_version = "3.12" +strict = false +ignore_missing_imports = true +warn_unused_ignores = true +warn_return_any = true + + +[tool.coverage.run] +source = ["ere"] +omit = ["*/__init__.py"] + +[tool.coverage.report] +fail_under = 80 +show_missing = true diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000..cb96047 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,290 @@ +""" +Pytest configuration file, which the framework picks up at startup. + +[Details here](https://docs.pytest.org/en/stable/reference/fixtures.html) +""" + +import os +import logging.config +from pathlib import Path + +import pytest +import redis +import yaml + +# Path constants — single source of truth for test directory structure +TEST_RESOURCES_DIR = Path(__file__).parent / "resources" +TEST_DATA_DIR = Path(__file__).parent / "test_data" + + +def pytest_configure(config: pytest.Config): + """ + Configures various pytest settings: + + * markers for tests + * Logging + """ + + config.addinivalue_line("markers", "integration: Integration test marker.") + + # Setup logging from YAML config file + cfg_path = str(TEST_RESOURCES_DIR / "logging-test.yml") + with open(cfg_path, encoding="utf-8") as f: + logging_cfg = yaml.safe_load(f) + logging.config.dictConfig(logging_cfg) + + +# ============================================================================ +# Helper: Load RDF content by relative path +# ============================================================================ + + +def load_rdf(relative_path: str) -> str: + """ + Load RDF content from test_data directory. + + Args: + relative_path: Path relative to test_data/, e.g., "organizations/group1/661238-2023.ttl" + + Returns: + str: Full RDF/Turtle content + + Raises: + FileNotFoundError: If file does not exist + """ + file_path = TEST_DATA_DIR / relative_path + if not file_path.exists(): + raise FileNotFoundError(f"Test data file not found: {file_path}") + return file_path.read_text(encoding="utf-8") + + +# ============================================================================ +# Organizations Test Data Fixtures +# ============================================================================ + + +@pytest.fixture(scope="session") +def org_group1_file1() -> str: + """Organizations group1, file 1.""" + return load_rdf("organizations/group1/661238-2023.ttl") + + +@pytest.fixture(scope="session") +def org_group1_file2() -> str: + """Organizations group1, file 2.""" + return load_rdf("organizations/group1/662860-2023.ttl") + + +@pytest.fixture(scope="session") +def org_group1_file3() -> str: + """Organizations group1, file 3.""" + return load_rdf("organizations/group1/663653-2023.ttl") + + +@pytest.fixture(scope="session") +def org_group2_file1() -> str: + """Organizations group2, file 1.""" + return load_rdf("organizations/group2/661197-2023.ttl") + + +@pytest.fixture(scope="session") +def org_group2_file2() -> str: + """Organizations group2, file 2.""" + return load_rdf("organizations/group2/663952-2023.ttl") + + +# ============================================================================ +# Procedures Test Data Fixtures +# ============================================================================ + + +@pytest.fixture(scope="session") +def proc_group1_file1() -> str: + """Procedures group1, file 1.""" + return load_rdf("procedures/group1/662861-2023.ttl") + + +@pytest.fixture(scope="session") +def proc_group1_file2() -> str: + """Procedures group1, file 2.""" + return load_rdf("procedures/group1/663131-2023.ttl") + + +@pytest.fixture(scope="session") +def proc_group1_file3() -> str: + """Procedures group1, file 3.""" + return load_rdf("procedures/group1/664733-2023.ttl") + + +@pytest.fixture(scope="session") +def proc_group2_file1() -> str: + """Procedures group2, file 1.""" + return load_rdf("procedures/group2/661196-2023.ttl") + + +@pytest.fixture(scope="session") +def proc_group2_file2() -> str: + """Procedures group2, file 2.""" + return load_rdf("procedures/group2/663262-2023.ttl") + + +# ============================================================================ +# Path Fixtures — inject test file paths to avoid inline Path constructions +# ============================================================================ + + +@pytest.fixture(scope="session") +def resolver_config_path(): + """Path to test resolver.yaml (from test/resources).""" + return TEST_RESOURCES_DIR / "resolver.yaml" + + +@pytest.fixture(scope="session") +def rdf_mapping_path(): + """Path to test rdf_mapping.yaml (from test/resources).""" + return TEST_RESOURCES_DIR / "rdf_mapping.yaml" + + +# ============================================================================ +# Entity Resolution Service Fixture +# ============================================================================ + + +@pytest.fixture +def entity_resolution_service(resolver_config_path, rdf_mapping_path): # pylint: disable=redefined-outer-name # pytest fixture params intentionally shadow outer scope names + """ + Fresh EntityResolver instance per test (core resolver). + + Creates isolated resolver with in-memory DuckDB for test scenario isolation. + Uses test-specific config files to ensure reproducibility and independence. + """ + import duckdb + from ere.adapters.duckdb_repositories import ( + DuckDBMentionRepository, + DuckDBSimilarityRepository, + DuckDBClusterRepository, + ) + from ere.adapters.duckdb_schema import init_schema + from ere.adapters.splink_linker_impl import SpLinkSimilarityLinker + from ere.services.entity_resolution_service import EntityResolver + from ere.services.resolver_config import ResolverConfig + + # Load resolver config from injected fixture path + with open(resolver_config_path, encoding="utf-8") as f: + raw_config = yaml.safe_load(f) + + # Entity fields are the source of truth from config + entity_fields = raw_config.get("entity_fields", ["legal_name", "country_code"]) + + resolver_config = ResolverConfig.from_dict(raw_config) + con = duckdb.connect(":memory:") + try: + init_schema(con, entity_fields) + + mention_repo = DuckDBMentionRepository(con, entity_fields) + similarity_repo = DuckDBSimilarityRepository(con) + cluster_repo = DuckDBClusterRepository(con) + linker = SpLinkSimilarityLinker(entity_fields, raw_config) + + yield EntityResolver( + mention_repo, similarity_repo, cluster_repo, linker, resolver_config + ) + finally: + con.close() + + +# ============================================================================ +# RDF Mapper Fixture +# ============================================================================ + + +@pytest.fixture +def rdf_mapper(rdf_mapping_path): # pylint: disable=redefined-outer-name # pytest fixture params intentionally shadow outer scope names + """ + Fresh RDFMapper instance per test. + + Returns a concrete TurtleRDFMapper implementation using test-specific config. + Uses injected rdf_mapping_path fixture to ensure reproducibility and independence. + """ + from ere.adapters.rdf_mapper_impl import TurtleRDFMapper + + return TurtleRDFMapper(rdf_mapping_path) + + +# ============================================================================ +# Redis fixture +# ============================================================================ + + +@pytest.fixture(scope="module") +def redis_client(): + """ + Connect to Redis and verify it's available. + Tries configured host first, then fallback to localhost if configured host is "redis". + Raises: RuntimeError if Redis is not accessible. + """ + hosts_to_try = [] + + # Primary: configured host (from .env or environment) + configured_host = os.environ.get("REDIS_HOST", "localhost") + hosts_to_try.append(configured_host) + + # Fallback: if configured host is a Docker service name, also try localhost + if configured_host in ("redis", "ersys-redis"): + hosts_to_try.append("localhost") + + port = int(os.environ.get("REDIS_PORT", "6379")) + db = int(os.environ.get("REDIS_DB", "0")) + password = os.environ.get("REDIS_PASSWORD") + + client = None + last_error = None + host = configured_host + for host in hosts_to_try: + try: + client = redis.Redis( + host=host, + port=port, + db=db, + password=password, + decode_responses=False, + ) + client.ping() + last_error = None + break + except redis.RedisError as e: + last_error = e + client = None + continue + + if last_error is not None: + raise RuntimeError("Redis test service cannot be detected.") from last_error + + # Propagate the host that actually worked so that any test reading REDIS_HOST from + # os.environ (e.g. to wire main() or another subprocess) gets a resolvable address. + if host != configured_host: + os.environ["REDIS_HOST"] = host + + # Verify connection + try: + client.ping() + print(f"\n✓ Connected to Redis at {host}:{port}") + except redis.RedisError as e: + pytest.skip(f"Redis not available at {host}:{port} — {e}") + + # Flush entire database to start clean + try: + client.flushdb() + print(f"✓ Flushed Redis DB {db}") + except redis.RedisError as e: + print(f"Warning: Could not flush database: {e}") + + yield client + + # Cleanup after test + try: + client.flushdb() + except redis.RedisError as e: + print(f"Warning: Could not cleanup after test: {e}") + + return client diff --git a/test/e2e/__init__.py b/test/e2e/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/e2e/test_app.py b/test/e2e/test_app.py new file mode 100644 index 0000000..1a8d693 --- /dev/null +++ b/test/e2e/test_app.py @@ -0,0 +1,100 @@ +"""End-to-end smoke test: app.py main() invoked directly.""" + +import json +import os +from datetime import datetime, timezone +from unittest.mock import patch + +import pytest + +from ere.adapters.utils import get_response_from_message +from ere.entrypoints.app import main +from ere.entrypoints.queue_worker import RedisQueueWorker + +REQUEST_QUEUE = "test-app-requests" +RESPONSE_QUEUE = "test-app-responses" + + +@pytest.fixture +def app_queues(redis_client): + """Provide test queue names and clean them before/after test.""" + redis_client.delete(REQUEST_QUEUE, RESPONSE_QUEUE) + yield REQUEST_QUEUE, RESPONSE_QUEUE + redis_client.delete(REQUEST_QUEUE, RESPONSE_QUEUE) + + +@pytest.mark.integration +def test_app_main_processes_single_request( + redis_client, app_queues, resolver_config_path, rdf_mapping_path, monkeypatch +): + """ + E2E smoke: main() resolves one queued request and writes response. + + Flow: + 1. Set env vars so main() connects to the test Redis with correct config + 2. Push one EntityMentionResolutionRequest + 3. Call main() — patched to exit after processing the first message + 4. Assert response structure + """ + req_queue, resp_queue = app_queues + + # 1. Wire main() to test Redis + configs via env vars + monkeypatch.setenv("REDIS_HOST", os.environ.get("REDIS_HOST", "localhost")) + monkeypatch.setenv("REDIS_PORT", os.environ.get("REDIS_PORT", "6379")) + monkeypatch.setenv("REDIS_DB", os.environ.get("REDIS_DB", "0")) + if redis_password := os.environ.get("REDIS_PASSWORD"): + monkeypatch.setenv("REDIS_PASSWORD", redis_password) + monkeypatch.setenv("ERSYS_REQUEST_QUEUE", req_queue) + monkeypatch.setenv("ERSYS_RESPONSE_QUEUE", resp_queue) + monkeypatch.setenv("RESOLVER_CONFIG_PATH", str(resolver_config_path)) + monkeypatch.setenv("RDF_MAPPING_PATH", str(rdf_mapping_path)) + + # 2. Push request before starting main() + payload = { + "type": "EntityMentionResolutionRequest", + "entity_mention": { + "identifiedBy": { + "request_id": "app-smoke-001", + "source_id": "TEST", + "entity_type": "ORGANISATION", + }, + "content": ( + "@prefix org: .\n" + "@prefix cccev: .\n" + "@prefix epo: .\n" + "@prefix epd: .\n" + 'epd:ent001 a org:Organization ;\n' + ' epo:hasLegalName "Acme Corp" ;\n' + ' cccev:registeredAddress [ epo:hasCountryCode "US" ] .\n' + ), + "content_type": "text/turtle", + }, + "timestamp": datetime.now(timezone.utc).isoformat(), + "ere_request_id": "app-smoke-001:01", + } + redis_client.rpush(req_queue, json.dumps(payload).encode()) + + # 3. Call main() — stop loop after first message via KeyboardInterrupt + _real = RedisQueueWorker.process_single_message + calls = [] + + def _stop_after_first(self): + result = _real(self) + calls.append(result) + raise KeyboardInterrupt # caught by main()'s except block → clean exit + + with patch.object(RedisQueueWorker, "process_single_message", _stop_after_first): + with patch("sys.argv", ["ere.entrypoints.app"]): + main() + + assert calls, "process_single_message was never called" + + # 4. Assert response + result = redis_client.brpop(resp_queue, timeout=5) + assert result is not None, "No response in output queue" + _, raw = result + + response = get_response_from_message(raw) + assert response.type == "EntityMentionResolutionResponse" + assert response.entity_mention_id.request_id == "app-smoke-001" + assert response.candidates is not None diff --git a/test/e2e/test_ere.py b/test/e2e/test_ere.py new file mode 100644 index 0000000..c8d05e5 --- /dev/null +++ b/test/e2e/test_ere.py @@ -0,0 +1,289 @@ +"""End-to-end test: RedisQueueWorker processes entity resolution requests. + +Tests the complete entrypoint flow: +1. Push EntityMentionResolutionRequest to input queue +2. RedisQueueWorker consumes, parses, and processes request +3. Response is written to output queue +4. Verify response structure and content +""" + +import json +import os +from datetime import datetime, timezone + +import pytest +import redis + +from ere.adapters.factories import build_rdf_mapper +from ere.adapters.utils import get_request_from_message, get_response_from_message +from ere.entrypoints.queue_worker import RedisQueueWorker +from ere.services.factories import ( + build_entity_resolver, + build_entity_resolution_service, +) + + +# =============================================================================== +# Fixtures +# =============================================================================== + + +@pytest.fixture +def redis_queues(redis_client): + """Provide queue names and clear them before test.""" + request_queue = "test-ere_requests" + response_queue = "test-ere_responses" + + # Clear queues + redis_client.delete(request_queue, response_queue) + + yield request_queue, response_queue + + # Cleanup + redis_client.delete(request_queue, response_queue) + + +@pytest.fixture(scope="module") +def e2e_entity_resolution_service(resolver_config_path, rdf_mapping_path): + """Build the full entity resolution service using test-specific config paths (injected from conftest).""" + resolver = build_entity_resolver(resolver_config_path=resolver_config_path) + mapper = build_rdf_mapper(rdf_mapping_path=rdf_mapping_path) + return build_entity_resolution_service(resolver, mapper) + + +@pytest.fixture +def queue_worker(redis_client, e2e_entity_resolution_service, redis_queues): + """Create RedisQueueWorker with test queue names.""" + request_queue, response_queue = redis_queues + return RedisQueueWorker( + redis_client=redis_client, + entity_resolution_service=e2e_entity_resolution_service, + request_queue=request_queue, + response_queue=response_queue, + ) + + +# =============================================================================== +# Helper functions +# =============================================================================== + + +def create_entity_mention_request( + request_id: str, + source_id: str, + entity_type: str, + legal_name: str, + country_code: str, +) -> dict: + """Create a minimal EntityMentionResolutionRequest payload.""" + # Minimal RDF content (simplified Turtle) + # Uses correct predicates per config/rdf_mapping.yaml: + # - legal_name maps to epo:hasLegalName + # - country_code maps to cccev:registeredAddress/epo:hasCountryCode + content = f""" +@prefix org: . +@prefix cccev: . +@prefix epo: . +@prefix epd: . +@prefix locn: . + +epd:ent001 a org:Organization ; + epo:hasLegalName "{legal_name}" ; + cccev:registeredAddress [ + epo:hasCountryCode "{country_code}" + ] ; + cccev:telephone "+44 1924306780" . +""" + + return { + "type": "EntityMentionResolutionRequest", + "entity_mention": { + "identifiedBy": { + "request_id": request_id, + "source_id": source_id, + "entity_type": entity_type, + }, + "content": content.strip(), + "content_type": "text/turtle", + }, + "timestamp": datetime.now(timezone.utc).isoformat(), + "ere_request_id": f"{request_id}:01", + } + + +# =============================================================================== +# End-to-end tests +# =============================================================================== + + +@pytest.mark.integration +def test_single_request_resolution_flow(redis_client, redis_queues, queue_worker): + """ + E2E test: single entity mention pushed to queue, resolved, response returned. + + Flow: + 1. Create and push EntityMentionResolutionRequest to input queue + 2. RedisQueueWorker consumes and processes request + 3. Response is written to output queue + 4. Verify response structure + """ + request_queue, response_queue = redis_queues + + # 1. Create and push request + request_payload = create_entity_mention_request( + request_id="324fs3r345vx", + source_id="TEDSWS", + entity_type="ORGANISATION", + legal_name="Acme Corporation", + country_code="US", + ) + request_bytes = json.dumps(request_payload).encode("utf-8") + redis_client.rpush(request_queue, request_bytes) + + # 2. Process message using worker + assert queue_worker.process_single_message() is True, ( + "Worker should process message" + ) + + # 3. Verify response in queue + result = redis_client.brpop(response_queue, timeout=1) + assert result is not None, "Response should be in output queue" + _, response_raw = result + + # 4. Verify response structure + response_obj = get_response_from_message(response_raw) + assert response_obj.type == "EntityMentionResolutionResponse" + assert response_obj.entity_mention_id.request_id == "324fs3r345vx" + assert response_obj.candidates is not None + + +@pytest.mark.integration +def test_multiple_requests_accumulate(redis_client, redis_queues, queue_worker): + """ + E2E test: multiple entity mentions are resolved and responses queued. + + Verifies that: + - Each request is processed independently + - Responses are queued correctly + - Resolution benefits from accumulated state + """ + request_queue, response_queue = redis_queues + + # Create and push two requests + mentions = [ + ("m1_324fs3r345vx", "TEDSWS", "Acme Corp", "US"), + ("m2_324fs3r345vx", "TEDSWS", "Acme Corporation", "US"), + ] + + for req_id, source, legal_name, country in mentions: + request_payload = create_entity_mention_request( + request_id=req_id, + source_id=source, + entity_type="ORGANISATION", + legal_name=legal_name, + country_code=country, + ) + redis_client.rpush(request_queue, json.dumps(request_payload).encode("utf-8")) + + # Process both requests using worker + for _ in range(2): + assert queue_worker.process_single_message() is True + + # Verify both responses in queue + responses = [] + for _ in range(2): + result = redis_client.brpop(response_queue, timeout=1) + assert result is not None + responses.append(get_response_from_message(result[1])) + + # Verify responses (order may vary) + assert len(responses) == 2 + request_ids = {r.entity_mention_id.request_id for r in responses} + assert request_ids == {"m1_324fs3r345vx", "m2_324fs3r345vx"} + + # Both should have candidates + for response in responses: + assert response.candidates is not None + + +@pytest.mark.integration +def test_request_response_payload_structure(redis_client, redis_queues, queue_worker): + """ + E2E test: verify request and response payload structures match spec. + + Validates: + - Request has required fields + - Response has required fields with correct types + """ + request_queue, response_queue = redis_queues + + # Create a request + request_payload = create_entity_mention_request( + request_id="struct_test_001", + source_id="TEST_SOURCE", + entity_type="ORGANISATION", + legal_name="Test Organization Ltd", + country_code="GB", + ) + + # Verify request structure + assert request_payload["type"] == "EntityMentionResolutionRequest" + assert "entity_mention" in request_payload + assert "identifiedBy" in request_payload["entity_mention"] + assert "content" in request_payload["entity_mention"] + assert "content_type" in request_payload["entity_mention"] + assert request_payload["entity_mention"]["content_type"] == "text/turtle" + + # Push and process + redis_client.rpush(request_queue, json.dumps(request_payload).encode("utf-8")) + assert queue_worker.process_single_message() is True + + # Get response + result = redis_client.brpop(response_queue, timeout=1) + assert result is not None + response = get_response_from_message(result[1]) + + # Verify response structure + assert response.type == "EntityMentionResolutionResponse" + assert hasattr(response, "entity_mention_id") + assert hasattr(response, "candidates") + assert hasattr(response, "timestamp") + assert hasattr(response, "ere_request_id") + + # Verify candidates structure + for candidate in response.candidates: + assert hasattr(candidate, "cluster_id") + assert hasattr(candidate, "confidence_score") + assert hasattr(candidate, "similarity_score") + assert isinstance(candidate.confidence_score, (float, int)) + assert isinstance(candidate.similarity_score, (float, int)) + + +@pytest.mark.integration +def test_organisation_with_different_country(redis_client, redis_queues, queue_worker): + """ + E2E test: organization entities with different country codes. + + Verifies service can process requests with different countries (uses blocking rules). + """ + request_queue, response_queue = redis_queues + + # Create request with German organization + request_payload = create_entity_mention_request( + request_id="de_org_test", + source_id="TEDSWS", + entity_type="ORGANISATION", + legal_name="Test GmbH", + country_code="DE", + ) + + redis_client.rpush(request_queue, json.dumps(request_payload).encode("utf-8")) + + # Process message + assert queue_worker.process_single_message() is True + + # Verify response + result = redis_client.brpop(response_queue, timeout=1) + assert result is not None + response = get_response_from_message(result[1]) + assert response.type == "EntityMentionResolutionResponse" diff --git a/test/features/direct_service_resolution.feature b/test/features/direct_service_resolution.feature new file mode 100644 index 0000000..93a52f2 --- /dev/null +++ b/test/features/direct_service_resolution.feature @@ -0,0 +1,115 @@ +Feature: Entity Mention Resolution — Direct Service Calls + + Tests: resolve_entity_mention(entity_mention: EntityMention) -> ClusterReference + + Fixed for all scenarios: + source_id = "ted-sws-pipeline" + content_type = "text/turtle" + + Test data root: test/test_data/ + + + Background: + Given a fresh resolution service is ready + + + # --------------------------------------------------------------------------- + # Known entity mention → resolves to an existing cluster + # --------------------------------------------------------------------------- + + Scenario Outline: Resolving a known entity mention + Given entity mention "" of type "" was already resolved with content from "" + When I resolve entity mention "" of type "" with content from "" + Then the result is a ClusterReference + And the cluster_id matches the seed cluster + + Examples: + | entity_type | mention_id_seed | rdf_file_seed | mention_id | rdf_file | + | ORGANISATION | http://ers.test/mention/org2-ks-seed | organizations/group2/663952-2023.ttl | http://ers.test/mention/org2-ks-new | organizations/group2/663952_-2023.ttl | + + + # --------------------------------------------------------------------------- + # Same-group entities → resolve to the same cluster + # --------------------------------------------------------------------------- + + Scenario Outline: Same-group entity mentions resolve to the same cluster + When I resolve the first entity mention "" of type "" with content from "" + And I resolve the second entity mention "" of type "" with content from "" + Then both results are ClusterReference instances + And both cluster_ids are equal + + Examples: + | group_id | entity_type | mention_id_a | rdf_file_a | mention_id_b | rdf_file_b | + | org-g1 | ORGANISATION | http://ers.test/mention/org1-001 | organizations/group1/661238-2023.ttl | http://ers.test/mention/org1-002 | organizations/group1/662860-2023.ttl | + | org-g1 | ORGANISATION | http://ers.test/mention/org1-001 | organizations/group1/661238-2023.ttl | http://ers.test/mention/org1-003 | organizations/group1/663653-2023.ttl | + + + # --------------------------------------------------------------------------- + # Different-group entities → each produces its own new singleton cluster + # --------------------------------------------------------------------------- + + Scenario Outline: Different-group entity mentions produce distinct clusters + When I resolve the first entity mention "" of type "" with content from "" + And I resolve the second entity mention "" of type "" with content from "" + Then both results are ClusterReference instances + And the cluster_ids are different + + Examples: + | entity_type | mention_id_a | rdf_file_a | mention_id_b | rdf_file_b | + | ORGANISATION | http://ers.test/mention/org1-001 | organizations/group1/661238-2023.ttl | http://ers.test/mention/org2-001 | organizations/group2/661197-2023.ttl | + | ORGANISATION | http://ers.test/mention/org1-001 | organizations/group1/661238-2023.ttl | http://ers.test/mention/org2-002 | organizations/group2/663952-2023.ttl | + + + # --------------------------------------------------------------------------- + # Idempotency — same mention + same content → identical ClusterReference + # --------------------------------------------------------------------------- + + Scenario Outline: Resolving the same entity mention twice returns identical ClusterReference + When I resolve entity mention "" of type "" with content from "" + And I resolve entity mention "" of type "" with content from "" again + Then both ClusterReference results are identical + + Examples: + | entity_type | mention_id | rdf_file | + | ORGANISATION | http://ers.test/mention/org1-idem | organizations/group1/661238-2023.ttl | + + + # --------------------------------------------------------------------------- + # Idempotency conflict — same mention_id, different content → exception + # --------------------------------------------------------------------------- + + Scenario Outline: Resolving the same mention_id with different content raises an exception + Given entity mention "" of type "" was already resolved with content from "" + When I try to resolve entity mention "" of type "" with content from "" + Then an exception is raised + + Examples: + | entity_type | mention_id | rdf_file_first | rdf_file_conflict | + | ORGANISATION | http://ers.test/mention/org1-conf | organizations/group1/661238-2023.ttl | organizations/group2/661197-2023.ttl | + + + # --------------------------------------------------------------------------- + # Unsupported entity type → exception + # --------------------------------------------------------------------------- + + Scenario Outline: Unsupported entity type raises an exception + When I try to resolve entity mention "" of type "" with content from "" + Then an unsupported entity type exception is raised + + Examples: + | entity_type | mention_id | rdf_file | + | CONTRACT | http://ers.test/mention/unsup-001 | organizations/group1/661238-2023.ttl | + + + # --------------------------------------------------------------------------- + # Malformed input → exception + # --------------------------------------------------------------------------- + + Scenario Outline: Malformed entity mention content raises an exception + When I try to resolve entity mention "" of type "" with invalid content "" + Then an exception is raised + + Examples: + | entity_type | mention_id | bad_content | + | ORGANISATION | http://ers.test/mention/err-001 | not valid rdf | + | ORGANISATION | http://ers.test/mention/err-002 | | diff --git a/test/features/entity_resolution_algorithm.feature b/test/features/entity_resolution_algorithm.feature new file mode 100644 index 0000000..0a1e9fc --- /dev/null +++ b/test/features/entity_resolution_algorithm.feature @@ -0,0 +1,53 @@ +Feature: Entity Resolution Algorithm + + Entity resolution algorithm for matching and clustering mentions. + Based on ALGORITHM.md canonical examples with configurable threshold. + + Scenario: First mention always creates a singleton + Given an entity resolution service with threshold 0.8 + When I resolve mention "m1" + Then mention "m1" is in cluster "m1" with score 0.0 + And the result has 1 candidate clusters + + Scenario: Strong match joins the best match's cluster + Given an entity resolution service with threshold 0.8 + When I resolve mention "m1" + And I set similarity between "m1" and "m2" to 0.95 + And I resolve mention "m2" + Then mention "m2" is in cluster "m1" with score 0.95 + And the result has 1 candidate clusters + + Scenario: New mention joins cluster of best match, not best match itself + Given an entity resolution service with threshold 0.8 + When I resolve mention "m1" + And I set similarity between "m1" and "m2" to 0.95 + And I resolve mention "m2" + And I set similarity between "m3" and "m2" to 0.92 + And I resolve mention "m3" + Then mention "m3" is in cluster "m1" with score 0.92 + And the result has 1 candidate clusters + + Scenario: Strong match joins cluster, below-threshold link also surfaces as candidate + Given an entity resolution service with threshold 0.8 + When I resolve mention "m1" + Then mention "m1" is in cluster "m1" with score 0.0 + When I resolve mention "m3" + Then mention "m3" is in cluster "m3" with score 0.0 + When I set similarity between "m2" and "m1" to 0.66 + And I set similarity between "m2" and "m3" to 0.95 + And I resolve mention "m2" + Then mention "m2" is in cluster "m3" with score 0.95 + And the result has 2 candidate clusters + And candidate 0 is cluster "m3" with score 0.95 + And candidate 1 is cluster "m1" with score 0.66 + + Scenario: Below-threshold match creates singleton, own cluster appears alongside candidates + Given an entity resolution service with threshold 0.8 + When I resolve mention "m1" + Then mention "m1" is in cluster "m1" with score 0.0 + When I set similarity between "m1" and "m2" to 0.60 + And I resolve mention "m2" + Then the result has 2 candidate clusters + And candidate 0 is cluster "m1" with score 0.60 + And candidate 1 is cluster "m2" with score 0.0 + And the cluster assignment for mention "m2" is "m2" diff --git a/test/features/steps/__init__.py b/test/features/steps/__init__.py new file mode 100644 index 0000000..275247c --- /dev/null +++ b/test/features/steps/__init__.py @@ -0,0 +1 @@ +"""Step definitions for pytest-bdd scenarios.""" diff --git a/test/features/steps/test_direct_service_resolution_steps.py b/test/features/steps/test_direct_service_resolution_steps.py new file mode 100644 index 0000000..b39d6b8 --- /dev/null +++ b/test/features/steps/test_direct_service_resolution_steps.py @@ -0,0 +1,306 @@ +"""Step definitions for direct_service_resolution.feature. + +Tests resolve_entity_mention(EntityMention) -> ClusterReference directly. +""" + +import pytest +from assertpy import assert_that +from erspec.models.core import ClusterReference, EntityMention, EntityMentionIdentifier +from pytest_bdd import given, scenario, scenarios, then, when +from pytest_bdd import parsers + +from ere.models.exceptions import ConflictError +from ere.services.entity_resolution_service import resolve_entity_mention +from test.conftest import load_rdf + +scenarios("../direct_service_resolution.feature") + +SOURCE_ID = "ted-sws-pipeline" +CONTENT_TYPE = "text/turtle" + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def _make_mention(mention_id: str, entity_type: str, content: str) -> EntityMention: + return EntityMention( + identifiedBy=EntityMentionIdentifier( + request_id=mention_id, + source_id=SOURCE_ID, + entity_type=entity_type, + ), + content_type=CONTENT_TYPE, + content=content, + ) + + +# A tiny mutable container fixture for the scenario +@pytest.fixture +def outcome(): + # store either "result" or "exception" + return {"result": None, "exception": None} + + +# --------------------------------------------------------------------------- +# Background +# --------------------------------------------------------------------------- + + +@given("a fresh resolution service is ready") +def fresh_service(entity_resolution_service): + # Fixture provides a fresh service instance per test + pass + + +# --------------------------------------------------------------------------- +# Given — pre-resolve for conflict test +# --------------------------------------------------------------------------- + + +@given( + parsers.parse( + 'entity mention "{mention_id}" of type "{entity_type}" was already resolved with content from "{rdf_file_first}"' + ), + target_fixture="seed_result", +) +def pre_resolve( + mention_id: str, + entity_type: str, + rdf_file_first: str, + entity_resolution_service, + rdf_mapper, +) -> ClusterReference: + return resolve_entity_mention( + _make_mention(mention_id, entity_type, load_rdf(rdf_file_first)), + entity_resolution_service, + rdf_mapper, + ) + + +# --------------------------------------------------------------------------- +# When — two-mention scenarios (same-group / different-group) +# --------------------------------------------------------------------------- + + +@when( + parsers.parse( + 'I resolve the first entity mention "{mention_id}" of type "{entity_type}" with content from "{rdf_file}"' + ), + target_fixture="first_result", +) +def resolve_first( + mention_id: str, + entity_type: str, + rdf_file: str, + entity_resolution_service, + rdf_mapper, +) -> ClusterReference: + return resolve_entity_mention( + _make_mention(mention_id, entity_type, load_rdf(rdf_file)), + entity_resolution_service, + rdf_mapper, + ) + + +@when( + parsers.parse( + 'I resolve the second entity mention "{mention_id}" of type "{entity_type}" with content from "{rdf_file}"' + ), + target_fixture="second_result", +) +def resolve_second( + mention_id: str, + entity_type: str, + rdf_file: str, + entity_resolution_service, + rdf_mapper, +) -> ClusterReference: + return resolve_entity_mention( + _make_mention(mention_id, entity_type, load_rdf(rdf_file)), + entity_resolution_service, + rdf_mapper, + ) + + +# --------------------------------------------------------------------------- +# When — idempotency (same mention twice) +# --------------------------------------------------------------------------- + + +@when( + parsers.parse( + 'I resolve entity mention "{mention_id}" of type "{entity_type}" with content from "{rdf_file}"' + ), + target_fixture="first_result", +) +def resolve_mention( + mention_id: str, + entity_type: str, + rdf_file: str, + entity_resolution_service, + rdf_mapper, +) -> ClusterReference: + mention = _make_mention(mention_id, entity_type, load_rdf(rdf_file)) + return resolve_entity_mention(mention, entity_resolution_service, rdf_mapper) + + +@when( + parsers.parse( + 'I resolve entity mention "{mention_id}" of type "{entity_type}" with content from "{rdf_file}" again' + ), + target_fixture="second_result", +) +def resolve_mention_again( + mention_id: str, + entity_type: str, + rdf_file: str, + entity_resolution_service, + rdf_mapper, +) -> ClusterReference: + return resolve_entity_mention( + _make_mention(mention_id, entity_type, load_rdf(rdf_file)), + entity_resolution_service, + rdf_mapper, + ) + + +# --------------------------------------------------------------------------- +# When — expected-failure scenarios (capture exception as fixture) +# --------------------------------------------------------------------------- + + +@when( + parsers.parse( + 'I try to resolve entity mention "{mention_id}" of type "{entity_type}" with content from "{rdf_file}"' + ), + target_fixture="raised_exception", +) +def try_resolve_conflict( + mention_id: str, + entity_type: str, + rdf_file: str, + outcome, + entity_resolution_service, + rdf_mapper, +) -> Exception | None: + try: + outcome["result"] = resolve_entity_mention( + _make_mention(mention_id, entity_type, load_rdf(rdf_file)), + entity_resolution_service, + rdf_mapper, + ) + return None + except Exception as exc: + outcome["exception"] = exc + return exc + + +@when( + # parsers.re required: parsers.parse cannot match an empty string for {bad_content} + parsers.re( + r'I try to resolve entity mention "(?P[^"]+)" of type "(?P[^"]+)" with invalid content "(?P.*)"' + ), + target_fixture="raised_exception", +) +def try_resolve_malformed( + mention_id: str, + entity_type: str, + bad_content: str, + outcome, + entity_resolution_service, + rdf_mapper, +) -> Exception | None: + try: + outcome["result"] = resolve_entity_mention( + _make_mention(mention_id, entity_type, bad_content), + entity_resolution_service, + rdf_mapper, + ) + return None + except Exception as exc: + outcome["exception"] = exc + return exc + + +# --------------------------------------------------------------------------- +# Then +# --------------------------------------------------------------------------- + + +@then("both results are ClusterReference instances") +def check_cluster_reference_type( + first_result: ClusterReference, second_result: ClusterReference +): + assert_that(first_result).is_instance_of(ClusterReference) + assert_that(second_result).is_instance_of(ClusterReference) + + +@then("both cluster_ids are equal") +def check_same_cluster(first_result: ClusterReference, second_result: ClusterReference): + assert_that(first_result.cluster_id).is_equal_to(second_result.cluster_id) + + +@then("the cluster_ids are different") +def check_different_clusters( + first_result: ClusterReference, second_result: ClusterReference +): + assert_that(first_result.cluster_id).is_not_equal_to(second_result.cluster_id) + + +@then("both ClusterReference results are identical") +def check_identical_results( + first_result: ClusterReference, second_result: ClusterReference +): + assert_that(first_result).is_equal_to(second_result) + assert_that(first_result).is_equal_to(second_result) + + +@then("an exception is raised") +def check_exception_raised(outcome): + raised_exception = outcome["exception"] + assert raised_exception is not None, ( + "Expected an exception, but the call succeeded. " + f"Result was: {outcome['result']!r}" + ) + assert_that(raised_exception).is_instance_of((ValueError, ConflictError)) + # Validate exception message based on type + if isinstance(raised_exception, ValueError): + # RDF parsing errors should match specific patterns + assert_that(str(raised_exception)).matches( + r"(Failed to parse RDF Turtle:|RDF content is empty or whitespace-only)" + ) + elif isinstance(raised_exception, ConflictError): + # Conflict errors should contain mention_id and indicate content mismatch + assert_that(str(raised_exception)).contains( + "was already resolved with different content" + ) + + +@then("the result is a ClusterReference") +def check_single_result_type(first_result: ClusterReference): + """Verify single resolution produces a valid ClusterReference.""" + assert_that(first_result).is_instance_of(ClusterReference) + + +@then("the cluster_id matches the seed cluster") +def check_matches_seed_cluster( + first_result: ClusterReference, seed_result: ClusterReference +): + """Verify new mention joined the pre-established cluster (not a new one).""" + assert_that(first_result.cluster_id).is_equal_to(seed_result.cluster_id) + + +@then("an unsupported entity type exception is raised") +def check_unsupported_entity_type_exception(outcome): + """Verify that unsupported entity types raise ValueError with proper message.""" + raised_exception = outcome["exception"] + assert raised_exception is not None, ( + "Expected a ValueError for unsupported entity type, but the call succeeded. " + f"Result was: {outcome['result']!r}" + ) + assert_that(raised_exception).is_instance_of(ValueError) + assert_that(str(raised_exception)).matches( + r"No rdf_mapping configured for entity_type" + ) diff --git a/test/features/steps/test_entity_resolution_algorithm_steps.py b/test/features/steps/test_entity_resolution_algorithm_steps.py new file mode 100644 index 0000000..c41e42c --- /dev/null +++ b/test/features/steps/test_entity_resolution_algorithm_steps.py @@ -0,0 +1,168 @@ +"""Step definitions for entity_resolution_algorithm.feature. + +Tests the core entity resolution algorithm with simple mentions and configurable similarities. +""" + +import pytest +from assertpy import assert_that +from pytest_bdd import given, when, then, parsers, scenarios + +from ere.models.resolver import Mention, MentionId, ClusterId +from ere.services.entity_resolution_service import EntityResolver +from ere.services.resolver_config import DuckDBConfig, ResolverConfig +from test.unit.adapters.stubs import ( + InMemoryMentionRepository, + InMemorySimilarityRepository, + InMemoryClusterRepository, + FixedSimilarityLinker, +) + +scenarios("../entity_resolution_algorithm.feature") + + +# =============================================================================== +# Fixtures for scenario context +# =============================================================================== + + +@pytest.fixture +def algorithm_context(): + """Mutable container to hold scenario state.""" + return { + "service": None, + "last_result": None, + "similarities": {}, # frozenset([id1, id2]) -> score + } + + +# =============================================================================== +# Given steps +# =============================================================================== + + +@given(parsers.parse("an entity resolution service with threshold {threshold}")) +def create_service(threshold: str, algorithm_context): + """Create a fresh EntityResolver with specified threshold.""" + threshold_value = float(threshold) + config = ResolverConfig( + threshold=threshold_value, + match_weight_threshold=-10, + top_n=100, + cache_strategy="tf_incremental", + entity_fields=["legal_name", "country_code"], + duckdb=DuckDBConfig(type="in-memory", path=":memory:"), + ) + + mention_repo = InMemoryMentionRepository() + similarity_repo = InMemorySimilarityRepository() + cluster_repo = InMemoryClusterRepository() + linker = FixedSimilarityLinker(similarity_map={}) + + algorithm_context["service"] = EntityResolver( + mention_repo=mention_repo, + similarity_repo=similarity_repo, + cluster_repo=cluster_repo, + linker=linker, + config=config, + ) + algorithm_context["similarities"] = {} + + +# =============================================================================== +# When steps +# =============================================================================== + + +@when(parsers.parse('I resolve mention "{mention_id}"')) +def resolve_mention(mention_id: str, algorithm_context): + """Resolve a mention with the configured similarities.""" + service = algorithm_context["service"] + + # Create mention + mention = Mention( + id=MentionId(value=mention_id), + attributes={"legal_name": f"Company {mention_id}", "country_code": "US"}, + ) + + # Update linker with new similarities + similarities = algorithm_context["similarities"] + linker = FixedSimilarityLinker(similarity_map=similarities) + + # Register previously resolved mentions + for prev_mention in service._mention_repo.load_all(): + linker.register_mention(prev_mention) + + # Update service linker + service._linker = linker + + # Resolve the mention + result = service.resolve(mention) + + # Store the result for Then steps + algorithm_context["last_result"] = result + + +@when( + parsers.parse('I set similarity between "{left_id}" and "{right_id}" to {score:f}') +) +def set_similarity(left_id: str, right_id: str, score: float, algorithm_context): + """Set similarity between two mentions.""" + pair_set = frozenset([left_id, right_id]) + algorithm_context["similarities"][pair_set] = score + + +# =============================================================================== +# Then steps +# =============================================================================== + + +@then( + parsers.parse( + 'mention "{mention_id}" is in cluster "{cluster_id}" with score {score:f}' + ) +) +def check_mention_cluster( + mention_id: str, cluster_id: str, score: float, algorithm_context +): + """Verify that a mention is assigned to a cluster with the expected score.""" + result = algorithm_context["last_result"] + assert_that(result.top.cluster_id.value).is_equal_to(cluster_id) + assert_that(result.top.score).is_close_to(score, 0.01) + + +@then(parsers.parse("the result has {count:d} candidate clusters")) +def check_candidate_count(count: int, algorithm_context): + """Verify the number of candidate clusters in the result.""" + result = algorithm_context["last_result"] + assert_that(len(result.candidates)).is_equal_to(count) + + +@then( + parsers.parse('candidate {index:d} is cluster "{cluster_id}" with score {score:f}') +) +def check_candidate(index: int, cluster_id: str, score: float, algorithm_context): + """Verify a specific candidate cluster and its score.""" + result = algorithm_context["last_result"] + assert_that(index).is_less_than(len(result.candidates)) + candidate = result.candidates[index] + assert_that(candidate.cluster_id.value).is_equal_to(cluster_id) + assert_that(candidate.score).is_close_to(score, 0.01) + + +@then( + parsers.parse('the cluster assignment for mention "{mention_id}" is "{cluster_id}"') +) +def check_cluster_assignment(mention_id: str, cluster_id: str, algorithm_context): + """Verify the cluster assignment from state.""" + service = algorithm_context["service"] + state = service.state() + + # Find which cluster this mention is assigned to + found_cluster = None + for cid, mention_list in state.cluster_membership.items(): + for m in mention_list: + if m.value == mention_id: + found_cluster = cid.value + break + + assert_that(found_cluster).is_equal_to(cluster_id) diff --git a/test/integration/test_entity_resolver.py b/test/integration/test_entity_resolver.py new file mode 100644 index 0000000..abf5e7e --- /dev/null +++ b/test/integration/test_entity_resolver.py @@ -0,0 +1,520 @@ +"""Integration test: EntityResolver with all real adapters. + +This test wires EntityResolver with real DuckDB repositories and +SpLinkSimilarityLinker to demonstrate the complete entity resolution flow: +initialization, resolution, training, and state introspection. +""" + +import pytest +import duckdb + +from ere.adapters.duckdb_repositories import ( + DuckDBClusterRepository, + DuckDBMentionRepository, + DuckDBSimilarityRepository, +) +from ere.adapters.splink_linker_impl import SpLinkSimilarityLinker, build_tf_df +from ere.adapters.duckdb_schema import init_schema +from ere.models.resolver import Mention +from ere.services.entity_resolution_service import EntityResolver +from ere.services.resolver_config import DuckDBConfig, ResolverConfig + + +# =============================================================================== +# Module-scoped fixtures +# =============================================================================== + + +@pytest.fixture(scope="module") +def entity_fields(): + """Standard entity fields for tests.""" + return ["legal_name", "country_code"] + + +@pytest.fixture(scope="module") +def resolver_config(): + """Resolver configuration for tests.""" + return ResolverConfig( + threshold=0.5, + match_weight_threshold=-10, + top_n=100, + cache_strategy="tf_incremental", + entity_fields=["legal_name", "country_code"], + duckdb=DuckDBConfig(type="in-memory", path=":memory:"), + ) + + +@pytest.fixture(scope="module") +def splink_config(): + """Splink configuration dict (needed for SpLinkSimilarityLinker).""" + return { + "threshold": 0.5, + "match_weight_threshold": -10, + "top_n": 100, + "cache_strategy": "tf_incremental", + "splink": { + "probability_two_random_records_match": 0.3, + "comparisons": [ + { + "type": "jaro_winkler", + "field": "legal_name", + "thresholds": [0.9, 0.8], + } + ], + "blocking_rules": ["country_code"], + }, + } + + +@pytest.fixture +def con(entity_fields): + """Fresh in-memory DuckDB connection with initialized schema.""" + c = duckdb.connect(":memory:") + init_schema(c, entity_fields) + return c + + +@pytest.fixture +def service(con, entity_fields, resolver_config, splink_config): + """ + Create EntityResolver with all real adapters. + + Wiring: + - DuckDBMentionRepository for persistence + - DuckDBSimilarityRepository for pairwise scores + - DuckDBClusterRepository for cluster assignments + - SpLinkSimilarityLinker for Splink-based scoring + """ + mention_repo = DuckDBMentionRepository(con, entity_fields) + similarity_repo = DuckDBSimilarityRepository(con) + cluster_repo = DuckDBClusterRepository(con) + linker = SpLinkSimilarityLinker(entity_fields, splink_config) + + return EntityResolver( + mention_repo=mention_repo, + similarity_repo=similarity_repo, + cluster_repo=cluster_repo, + linker=linker, + config=resolver_config, + ) + + +# =============================================================================== +# integration tests +# =============================================================================== + + +@pytest.mark.integration +def test_first_mention_resolves_to_singleton(service, con): + """ + Resolve the first mention. + Assert: creates a singleton cluster (mention is its own cluster). + """ + m1 = Mention(mention_id="m1", legal_name="Acme Corp", country_code="US") + + result = service.resolve(m1) + + # First mention is its own cluster + assert result.top.cluster_id.value == "m1" + assert result.top.score == 0.0 # Self-cluster has zero similarity + assert len(result.candidates) >= 1 + + # Verify persistence + mention_count = con.execute("SELECT COUNT(*) FROM mentions").fetchone()[0] + assert mention_count == 1 + cluster_count = con.execute( + "SELECT COUNT(DISTINCT cluster_id) FROM clusters" + ).fetchone()[0] + assert cluster_count == 1 + + +@pytest.mark.integration +def test_strong_match_joins_existing_cluster(service, con): + """ + Resolve m1, then resolve m2 (similar name, same country). + Assert: m2 joins m1's cluster (strong match above threshold). + """ + m1 = Mention(mention_id="m1", legal_name="Acme Corp", country_code="US") + m2 = Mention(mention_id="m2", legal_name="Acme Corporation", country_code="US") + + result1 = service.resolve(m1) + assert result1.top.cluster_id.value == "m1" + + result2 = service.resolve(m2) + assert result2.top.cluster_id.value == "m1", "m2 should join m1's cluster" + + # Verify both in same cluster + cluster_rows = con.execute( + "SELECT mention_id FROM clusters WHERE cluster_id = 'm1' ORDER BY mention_id" + ).fetchall() + assert [row[0] for row in cluster_rows] == ["m1", "m2"] + + +@pytest.mark.integration +def test_below_threshold_creates_new_cluster(service, con): + """ + Resolve m1 (resolves to its own cluster), then resolve m2. + Assert: cluster assignments persist and both mentions are resolved. + """ + m1 = Mention(mention_id="m1", legal_name="Acme Corporation", country_code="US") + m2 = Mention(mention_id="m2", legal_name="BestCo Industries", country_code="US") + + result1 = service.resolve(m1) + result2 = service.resolve(m2) + + # Both should resolve to some cluster + assert result1.top is not None + assert result2.top is not None + + # Verify both are in the database + mention_count = con.execute("SELECT COUNT(*) FROM mentions").fetchone()[0] + assert mention_count == 2 + + # Verify cluster assignments persist + cluster_count = con.execute( + "SELECT COUNT(DISTINCT cluster_id) FROM clusters" + ).fetchone()[0] + assert cluster_count >= 1 + + +@pytest.mark.integration +def test_cross_country_blocked_by_blocking_rule(service, con): + """ + Resolve m1 (US), then resolve m2 (DE, similar name but different country). + Assert: blocking rule prevents comparison, m2 creates new cluster. + """ + m1 = Mention(mention_id="m1", legal_name="Acme", country_code="US") + m2 = Mention(mention_id="m2", legal_name="Acme", country_code="DE") + + service.resolve(m1) + result2 = service.resolve(m2) + + assert result2.top.cluster_id.value == "m2", "Blocking rule should prevent match" + + # Verify no similarities stored (blocked pair) + sim_count = con.execute("SELECT COUNT(*) FROM similarities").fetchone()[0] + assert sim_count == 0, "No similarities should exist for blocked cross-country pair" + + +@pytest.mark.integration +def test_similarities_persisted_to_repository(service, con): + """ + Resolve multiple mentions with some matches. + Assert: similarities table contains the scored pairs. + """ + m1 = Mention(mention_id="m1", legal_name="Acme", country_code="US") + m2 = Mention(mention_id="m2", legal_name="Acme Inc", country_code="US") + m3 = Mention(mention_id="m3", legal_name="BestCo", country_code="US") + + service.resolve(m1) + service.resolve(m2) # Should score m2 vs m1 (similar) + service.resolve(m3) # Should score m3 vs m1, m2 (dissimilar) + + # Verify similarities persisted + sim_rows = con.execute("SELECT COUNT(*) FROM similarities").fetchone()[0] + assert sim_rows > 0, "Similarities should be persisted" + + # Verify pair structure + pair_rows = con.execute( + "SELECT mention_id_l, mention_id_r FROM similarities ORDER BY mention_id_l, mention_id_r" + ).fetchall() + assert len(pair_rows) >= 2, "Should have at least 2 pairs (m2 vs m1, m3 vs m1/m2)" + + +@pytest.mark.integration +def test_train_succeeds_with_sufficient_records(service, con): + """ + Resolve 10+ mentions, then train. + Assert: training succeeds (uses cold-start), linker is still functional. + """ + mentions = [ + Mention(mention_id="a1", legal_name="Acme Corp", country_code="US"), + Mention(mention_id="a2", legal_name="Acme", country_code="US"), + Mention(mention_id="b1", legal_name="BestCo Inc", country_code="US"), + Mention(mention_id="b2", legal_name="BestCo", country_code="US"), + Mention(mention_id="c1", legal_name="TechSoft Ltd", country_code="US"), + Mention(mention_id="c2", legal_name="TechSoft", country_code="US"), + Mention(mention_id="d1", legal_name="InnovateX SARL", country_code="US"), + Mention(mention_id="d2", legal_name="Innovate X", country_code="US"), + Mention(mention_id="e1", legal_name="GlobalTrade BV", country_code="US"), + Mention(mention_id="e2", legal_name="GlobalTrade", country_code="US"), + ] + + for mention in mentions: + service.resolve(mention) + + # Training should succeed (cold-start is used if EM fails) + service.train() + + # Verify linker is still functional + query = Mention( + mention_id="test_q", legal_name="Acme Technologies", country_code="US" + ) + result = service.resolve(query) + + assert result.top is not None + assert len(result.candidates) >= 1 + + +@pytest.mark.integration +def test_auto_training_nonblocking(con, entity_fields): + """ + Auto-training triggers at threshold without blocking resolution. + Verify resolution returns immediately (not delayed by training). + """ + splink_config = { + "threshold": 0.5, + "match_weight_threshold": -10, + "top_n": 100, + "cache_strategy": "tf_incremental", + "splink": { + "probability_two_random_records_match": 0.3, + "comparisons": [ + { + "type": "jaro_winkler", + "field": "legal_name", + "thresholds": [0.9, 0.8], + } + ], + "blocking_rules": ["country_code"], + }, + } + + config = ResolverConfig( + threshold=0.5, + match_weight_threshold=-10, + top_n=100, + cache_strategy="tf_incremental", + auto_train_threshold=5, # Trigger at 5 mentions + entity_fields=["legal_name", "country_code"], + duckdb=DuckDBConfig(type="in-memory", path=":memory:"), + ) + + mention_repo = DuckDBMentionRepository(con, entity_fields) + similarity_repo = DuckDBSimilarityRepository(con) + cluster_repo = DuckDBClusterRepository(con) + linker = SpLinkSimilarityLinker(entity_fields, splink_config) + + test_service = EntityResolver( + mention_repo=mention_repo, + similarity_repo=similarity_repo, + cluster_repo=cluster_repo, + linker=linker, + config=config, + ) + + # Resolve 5 mentions - at the 5th, training should trigger + mentions = [ + Mention(mention_id="m1", legal_name="Acme", country_code="US"), + Mention(mention_id="m2", legal_name="Acme Inc", country_code="US"), + Mention(mention_id="m3", legal_name="BestCo", country_code="US"), + Mention(mention_id="m4", legal_name="TechSoft", country_code="US"), + Mention(mention_id="m5", legal_name="GlobalTrade", country_code="US"), + ] + + for mention in mentions: + result = test_service.resolve(mention) + # Resolution should return immediately, not block for training + assert result.top is not None + + # Verify state accumulated + state = test_service.state() + assert state.mention_count == 5 + + +@pytest.mark.integration +def test_state_reflects_all_mentions(service, con): + """ + Resolve multiple mentions, check state. + Assert: state.mention_count matches database. + """ + mentions = [ + Mention(mention_id="m1", legal_name="Acme", country_code="US"), + Mention(mention_id="m2", legal_name="BestCo", country_code="US"), + Mention(mention_id="m3", legal_name="TechSoft", country_code="US"), + ] + + for mention in mentions: + service.resolve(mention) + + state = service.state() + + assert state.mention_count == 3 + db_mention_count = con.execute("SELECT COUNT(*) FROM mentions").fetchone()[0] + assert state.mention_count == db_mention_count + + +@pytest.mark.integration +def test_state_reflects_cluster_membership(service): + """ + Resolve mentions and verify cluster membership is reflected in state. + Assert: state.cluster_membership shows correct assignment structure. + """ + m1 = Mention(mention_id="m1", legal_name="Acme Corporation", country_code="US") + m2 = Mention(mention_id="m2", legal_name="Acme Corp", country_code="US") + m3 = Mention(mention_id="m3", legal_name="BestCo Industries", country_code="US") + + service.resolve(m1) + service.resolve(m2) + service.resolve(m3) + + state = service.state() + + # Verify cluster structure + assert state.cluster_count >= 1, "Should have at least 1 cluster" + assert state.mention_count == 3, "Should have 3 mentions" + + # Verify all mentions are assigned to some cluster + all_mentions = set() + for cluster_id, mention_list in state.cluster_membership.items(): + for mention in mention_list: + all_mentions.add(mention.value) + + assert all_mentions == {"m1", "m2", "m3"}, "All mentions should be assigned" + + +@pytest.mark.integration +def test_state_reflects_similarity_count(service, con): + """ + Resolve mentions, check state.similarity_count. + Assert: matches number of persisted similarities. + """ + m1 = Mention(mention_id="m1", legal_name="Acme", country_code="US") + m2 = Mention(mention_id="m2", legal_name="Acme Inc", country_code="US") + m3 = Mention(mention_id="m3", legal_name="BestCo", country_code="US") + + service.resolve(m1) + service.resolve(m2) + service.resolve(m3) + + state = service.state() + + db_sim_count = con.execute("SELECT COUNT(*) FROM similarities").fetchone()[0] + assert state.similarity_count == db_sim_count + + +@pytest.mark.integration +def test_linker_warm_start_capability(entity_fields, splink_config): + """ + Verify SpLinkSimilarityLinker supports warm-start with pre-seeded mentions. + Assert: linker initialized with initial_df can score against those mentions. + """ + # Create initial mentions for warm-start + initial_mentions = [ + Mention(mention_id="seed1", legal_name="Acme Corp", country_code="US"), + Mention(mention_id="seed2", legal_name="BestCo", country_code="US"), + ] + + # Create linker with warm-start initial_df + initial_df = build_tf_df(initial_mentions, entity_fields) + linker = SpLinkSimilarityLinker(entity_fields, splink_config, initial_df=initial_df) + + # Query against warm-start mentions + query = Mention(mention_id="q1", legal_name="Acme", country_code="US") + links = linker.find_matches(query) + + # Should find links to seed1 (similar name) + assert len(links) >= 1, "Should find matches against warm-start mentions" + + # Register new mention and query again + linker.register_mention(query) + query2 = Mention(mention_id="q2", legal_name="Acme Inc", country_code="US") + links2 = linker.find_matches(query2) + + # Should find links to both seed1 and q1 + assert len(links2) >= 1, "Linker should work after registering new mention" + + +@pytest.mark.integration +def test_multiple_resolves_accumulate_state(service, con): + """ + Resolve mentions in sequence, verify state accumulates correctly. + Assert: each resolve persists and is visible in subsequent resolves. + """ + mentions = [ + Mention(mention_id="m1", legal_name="Acme", country_code="US"), + Mention(mention_id="m2", legal_name="Acme Inc", country_code="US"), + Mention(mention_id="m3", legal_name="Acme Corp", country_code="US"), + ] + + for i, mention in enumerate(mentions, 1): + result = service.resolve(mention) + state = service.state() + + # Verify state accumulates + assert state.mention_count == i, ( + f"After resolving {i} mentions, should have {i} in DB" + ) + + # Later mentions should see earlier mentions in results + if i > 1: + assert len(result.candidates) >= 1, ( + "Should see candidates from earlier mentions" + ) + + +@pytest.mark.integration +def test_end_to_end_realistic_scenario(service, con): + """ + Realistic scenario: resolve a stream of entity mentions with variants. + Assert: all mentions are resolved to clusters, similarities are persisted. + """ + # Stream of mentions: 3 companies with variants + mentions = [ + # Company A + Mention( + mention_id="acme_1", legal_name="Acme Corporation Ltd", country_code="US" + ), + Mention(mention_id="acme_2", legal_name="Acme Corp", country_code="US"), + Mention(mention_id="acme_3", legal_name="Acme", country_code="US"), + # Company B + Mention( + mention_id="bestco_1", legal_name="BestCo Industries Inc", country_code="US" + ), + Mention(mention_id="bestco_2", legal_name="BestCo Inc", country_code="US"), + # Company C + Mention( + mention_id="techsoft_1", + legal_name="TechSoft Solutions Limited", + country_code="US", + ), + Mention(mention_id="techsoft_2", legal_name="TechSoft Ltd", country_code="US"), + Mention(mention_id="techsoft_3", legal_name="TechSoft", country_code="US"), + ] + + for mention in mentions: + service.resolve(mention) + + # Verify state + state = service.state() + assert state.mention_count == 8, "Should have resolved all 8 mentions" + assert state.cluster_count >= 3, "Should have at least 3 clusters (one per company)" + assert state.similarity_count > 0, "Should have persisted similarities" + + # Build a map from mention_id to cluster_id + mention_to_cluster = {} + for cluster_id, mention_list in state.cluster_membership.items(): + for mention in mention_list: + mention_to_cluster[mention.value] = cluster_id + + # Verify all mentions are assigned + assert set(mention_to_cluster.keys()) == { + "acme_1", + "acme_2", + "acme_3", + "bestco_1", + "bestco_2", + "techsoft_1", + "techsoft_2", + "techsoft_3", + }, "All mentions should be assigned to clusters" + + # Verify different companies are in different clusters + # (strongest assertion: first mention of each company should be in different clusters) + acme_cluster = mention_to_cluster["acme_1"] + bestco_cluster = mention_to_cluster["bestco_1"] + techsoft_cluster = mention_to_cluster["techsoft_1"] + + assert len({acme_cluster, bestco_cluster, techsoft_cluster}) == 3, ( + "Different companies should be in different clusters" + ) diff --git a/test/integration/test_redis_integration.py b/test/integration/test_redis_integration.py new file mode 100644 index 0000000..2b0fac4 --- /dev/null +++ b/test/integration/test_redis_integration.py @@ -0,0 +1,153 @@ +""" +Integration tests for Redis queue interaction with ERE service. + +These tests verify end-to-end request/response flow through Redis. + + +Run with: + pytest test/integration/test_redis_integration.py -v + pytest test/integration/test_redis_integration.py::TestRedisQueueIntegration::test_send_dummy_request -v +""" + +import json +import time + +import pytest + + +def create_test_request( + request_id: str = "test-001", content: str = "John Smith" +) -> dict: + """Create a valid EntityMentionResolutionRequest for testing.""" + return { + "type": "EntityMentionResolutionRequest", + "ere_request_id": request_id, + "timestamp": "2026-02-24T21:00:00Z", + "entity_mention": { + "identifiedBy": "mention-1", + "content_type": "text", + "content": content, + }, + } + + +@pytest.mark.integration +class TestRedisQueueIntegration: + """Test ERE service request/response flow through Redis.""" + + def test_redis_service_connectivity(self, redis_client): + """Test: Redis service exists and client can connect.""" + try: + response = redis_client.ping() + assert response is True, "Redis ping failed" + except Exception as e: + pytest.fail(f"Cannot connect to Redis: {e}") + + def test_send_dummy_request(self, redis_client): + """Test: Push a dummy request and verify it was queued.""" + request = create_test_request("test-send-001") + + # Push request to queue + result = redis_client.lpush("dummy-queue", json.dumps(request)) + print(f"lpush result: {result}") + assert result == 1, "Request was not added to queue" + + # Verify queue length + queue_len = redis_client.llen("dummy-queue") + print(f"Queue length after push: {queue_len}") + assert queue_len == 1, f"Expected 1 request in queue, got {queue_len}" + + # Verify data is actually in Redis + item = redis_client.lindex("dummy-queue", 0) + assert item is not None, "No data found in queue" + print(f"Item in queue: {item[:50]}...") # Print first 50 bytes + + def test_receive_response(self, redis_client): + """Test: Verify response format from mock service (skip if service not running).""" + request = create_test_request("test-receive-001") + + # Snapshot response count before pushing request (to handle in-flight requests from prior tests) + initial_response_count = redis_client.llen("ere_responses") + + # Push request + redis_client.lpush("ere_requests", json.dumps(request)) + + # Wait for processing (service has 3-5s timeout per iteration) + time.sleep(2) + + # Check delta in response queue + new_response_count = redis_client.llen("ere_responses") - initial_response_count + + # Skip this test if the service isn't running + if new_response_count == 0: + pytest.skip("ERE service not running — skipping response test") + + assert new_response_count == 1, ( + f"Expected 1 new response, got {new_response_count}" + ) + + # Retrieve and verify response format (latest response is at index 0) + response_raw = redis_client.lindex("ere_responses", 0) + assert response_raw is not None, "Response is empty" + + # response_raw is bytes, decode it + response_str = ( + response_raw.decode("utf-8") + if isinstance(response_raw, bytes) + else response_raw + ) + response = json.loads(response_str) + + # Verify response structure + assert response["type"] == "EREErrorResponse", "Wrong response type" + assert response["ere_request_id"] == "test-receive-001", "Request ID mismatch" + assert "error_title" in response, "Missing error_title" + assert "error_detail" in response, "Missing error_detail" + assert "timestamp" in response, "Missing timestamp" + + def test_multiple_requests(self, redis_client): + """Test: Handle multiple sequential requests.""" + # Snapshot response count before pushing requests (to handle in-flight responses from prior tests) + initial_response_count = redis_client.llen("ere_responses") + + # Send 3 requests + for i in range(3): + request = create_test_request(f"test-multi-{i:03d}", f"Entity {i}") + redis_client.lpush("ere_requests", json.dumps(request)) + + # Wait for processing (service has 3-5s timeout per iteration) + time.sleep(4) + + # Check delta in response queue + new_response_count = redis_client.llen("ere_responses") - initial_response_count + if new_response_count == 0: + pytest.skip("ERE service not running — skipping response verification") + + assert new_response_count == 3, ( + f"Expected 3 new responses, got {new_response_count}" + ) + + def test_redis_authentication(self, redis_client): + """Test: Verify Redis connection works with authentication.""" + # If we got here, redis_client fixture succeeded + # which means authentication (if needed) worked + + response = redis_client.ping() + assert response is True, "Redis ping failed" + + def test_malformed_request_handling(self, redis_client): + """Test: Service handles malformed requests gracefully.""" + # Push invalid JSON + redis_client.lpush("ere_requests", "this is not valid json") + + # Service should still be running (not crash) + time.sleep(1) + + # Verify service is still responsive + response = redis_client.ping() + assert response is True, "Service crashed on malformed request" + + +if __name__ == "__main__": + """Allow running tests directly: python test/integration/test_redis_integration.py""" + pytest.main([__file__, "-v"]) diff --git a/test/resources/logging-test.yml b/test/resources/logging-test.yml new file mode 100644 index 0000000..5a760f7 --- /dev/null +++ b/test/resources/logging-test.yml @@ -0,0 +1,43 @@ +# Used to run tests via pytest. This is loaded by conftest.py, which pytest auto-loads. +# + +version: 1 + +handlers: + + console: + class: logging.StreamHandler + stream: ext://sys.stderr + formatter: simpleFormatter + level: DEBUG + + file: + class: logging.FileHandler + # Makes the temp path OS-independent. As per documentation you can use these Python calls with + # the YAML unsafe loader, which we support in our logger_config function, see the tests. + #  + # Note that under macOS, tempfile.gettempdir() IS NOT /tmp, but something like /var/folders/... + # + filename: test.log + mode: a + level: DEBUG + formatter: simpleFormatter + +formatters: + simpleFormatter: + # The formatter class, this is the default + #class: logging.Formatter + + # A way to give the FQN. + #class: !!python/name:logging.Formatter + format: '%(asctime)s [%(levelname)-7s] [%(name)-10s] [%(threadName)-8s] %(message)s' + datefmt: '%Y-%m-%d %H:%M:%S' + + +root: + level: DEBUG + handlers: + - console + - file + +# loggers: diff --git a/test/resources/rdf_mapping.yaml b/test/resources/rdf_mapping.yaml new file mode 100644 index 0000000..8dd02e2 --- /dev/null +++ b/test/resources/rdf_mapping.yaml @@ -0,0 +1,20 @@ +# Namespace prefix registry - used by rdf_mapper.py to resolve prefixed names in field paths +namespaces: + epo: "http://data.europa.eu/a4g/ontology#" + org: "http://www.w3.org/ns/org#" + locn: "http://www.w3.org/ns/locn#" + cccev: "http://data.europa.eu/m8g/" + +# Entity type mappings: entity_type_string -> rdf_type + field property paths +# Property paths use / as separator for multi-hop traversal. +# Field names must match entity_fields in resolver.yaml (legal_name, country_code). +entity_types: + ORGANISATION: + rdf_type: "org:Organization" + fields: + legal_name: "epo:hasLegalName" + country_code: "cccev:registeredAddress/epo:hasCountryCode" + nuts_code: "cccev:registeredAddress/epo:hasNutsCode" + post_code: "cccev:registeredAddress/locn:postCode" + post_name: "cccev:registeredAddress/locn:postName" + thoroughfare: "cccev:registeredAddress/locn:thoroughfare" diff --git a/test/resources/resolver.yaml b/test/resources/resolver.yaml new file mode 100644 index 0000000..b258e93 --- /dev/null +++ b/test/resources/resolver.yaml @@ -0,0 +1,160 @@ +# Entity Resolver configuration +# +# Entity fields: names must match fields in rdf_mapping.yaml entity_types.ORGANISATION.fields +entity_fields: + - legal_name + - country_code + - nuts_code + - post_code + - post_name + - thoroughfare + +# DuckDB database configuration +duckdb: + type: in-memory # Options: "in-memory" or "persistent" + +cache_strategy: tf_incremental + +# Cluster assignment threshold: requires match_probability >= threshold for cluster join. +# Address-enriched model is expected to be more confident; starting at 0.20. +# Adjust downward if precision is too low; upward if recall is insufficient. +threshold: 0.20 + +# Maximum cluster references returned per resolve_request() call. +top_n: 100 + +# Lower bound on match weight passed to find_matches_to_new_records(). +# -10 captures below-threshold links needed for full candidate output. +match_weight_threshold: -10 + +# Automatic training threshold: trigger non-blocking EM at N mentions. +auto_train_threshold: 50 + +splink: + # Prior: Fellegi-Sunter λ (probability any two records match). + # With address fields, expect slightly higher match rate (finer granularity helps). + # Using 0.003 (vs 0.0022 for name-only) to account for address signal. + probability_two_random_records_match: 0.003 + + # Comparisons: identity functions and similarity scoring for pairwise evaluation. + # NOTE: country_code used only in blocking rules, not comparisons (to preserve EM training). + # Address fields complement legal_name matching for disambiguation and confidence. + comparisons: + + # Primary identifier: legal name with Jaro-Winkler thresholds + # Unchanged from baseline: 0.9 (very high similarity), 0.8 (quite similar), else (low) + - type: jaro_winkler + field: legal_name + thresholds: [0.9, 0.8] + + # Supporting signals (lower confidence than legal name, but disambiguate) + + # NUTS code (Nomenclature of Territorial Units for Statistics) + # Exact match only: same NUTS = same region, no NUTS = missing data. + # Most EU organizations in procurement have NUTS; non-EU lack it. + # Confidence: Match implies same country+region (but not unique identifier). + - type: exact_match + field: nuts_code + + # Post Code (postal / ZIP code) + # Jaro-Winkler with high thresholds for typo tolerance + - type: jaro_winkler + field: post_code + thresholds: [0.95, 0.85] + + # Post Name (city/locality name, e.g., "Frankfurt am Main") + # Jaro-Winkler at [0.90, 0.80]: captures abbreviations, accents, spelling variations + # 0.90: high confidence (e.g., "München" vs "Munich" should match, or with accents) + # 0.80: moderate confidence (e.g., "St. John's" vs "St Johns", abbreviation variations) + # Caveat: multiple companies in same city; not alone sufficient for match. + - type: jaro_winkler + field: post_name + thresholds: [0.90, 0.80] + + # Thoroughfare (street address: road name + house number) + # Jaro-Winkler at [0.95, 0.85]: very high threshold due to specificity + # 0.95: near-identical streets (captures digit transpositions: "4 Main" vs "5 Main") + # 0.85: captures common abbreviations ("Street" vs "St.", "Avenue" vs "Ave") + # Rationale: Street addresses are highly specific; typos are unusual but possible. + # Organizations may move offices, so don't rely on this alone. + - type: jaro_winkler + field: thoroughfare + thresholds: [0.95, 0.85] + + # Country code: exact match only (baseline blocking rule support). + # NOTE: Used in blocking only; comparison is a no-op (all same-country pairs). + - type: exact_match + field: country_code + + # Blocking rules: pairs are compared only if at least ONE rule fires. + # Expressed as field names; multi-field rules use a list. + # + # Design: country-level primary blocking, NUTS-level secondary for EU. + blocking_rules: + # Primary: country code (strict rule: must match country) + - country_code + + # Secondary (EU-specific): country + NUTS code blocking for finer granularity + # Enables disambiguation of large countries (e.g., Germany's 290+ regions). + # Falls back gracefully: if NUTS missing, country-only rule fires. + # Only applies when both records have NUTS (common for EU procurement data). + - [country_code, nuts_code] + + # Cold-start default m/u probabilities (used before EM training). + # Each comparison field gets distributions for each similarity level. + # Once EM training completes, trained parameters overwrite these. + cold_start: + comparisons: + + legal_name: + # JaroWinkler [0.9, 0.8]: high / medium / low similarity + # m_prob: likelihood of match at each similarity tier (empirically tuned) + # u_prob: likelihood in random records (opposite population) + m_probabilities: [0.9, 0.6, 0.025, 0.005] + u_probabilities: [0.00001, 0.0004, 0.004, 0.99559] + + country_code: + # ExactMatch: match / no-match + # Near-deterministic: matching country codes strongly imply same country. + m_probabilities: [0.99, 0.01] + u_probabilities: [0.10, 0.90] + + nuts_code: + # ExactMatch: match / no-match + # Strong signal: same NUTS region = same EU administrative region. + # However, some organizations have operations across multiple NUTS (parent + branches). + # m_prob=0.92: "likely same location" but not identity. + # u_prob=0.08: in random records, small chance of NUTS collision across large geographic areas. + m_probabilities: [0.92, 0.08] + u_probabilities: [0.05, 0.95] + + post_code: + # Jaro-Winkler [0.95, 0.85]: very high / high / low similarity + # m_prob: 0.85 (95% match), 0.40 (85% match), 0.02 (low) + # - 0.95 JW: nearly identical postal codes + # - 0.85 JW: postal codes with minor variations (digit transposition, typo) + # - else: different postal zone or missing data + # u_prob: 0.02 (95% match - rare collision), 0.08 (85% match), 0.90 (low) + m_probabilities: [0.85, 0.40, 0.02, 0.005] + u_probabilities: [0.02, 0.08, 0.08, 0.82] + + post_name: + # JaroWinkler [0.90, 0.80]: high / moderate / low similarity + # Moderate confidence: city names are less unique than addresses. + # Multiple organizations can be in same city. + # m_prob: 0.65 (90% match), 0.25 (80% match), 0.01 (low) + # u_prob: 0.05 (90% match), 0.15 (80% match), 0.80 (low) + m_probabilities: [0.65, 0.25, 0.01, 0.005] + u_probabilities: [0.05, 0.15, 0.15, 0.65] + + thoroughfare: + # JaroWinkler [0.95, 0.85]: very high / high / low similarity + # Very strong signal: street addresses are highly specific. + # Same street + building = likely same organization (or landlord info). + # m_prob: 0.85 (95% match), 0.50 (85% match), 0.02 (low) + # - 95% JW match: almost certainly same office location + # - 85% JW match: likely same street but possibly different building/unit + # - low: different address or missing data + # u_prob: 0.01 (95% match - street collision rare), 0.08 (85% match), 0.91 (low) + m_probabilities: [0.85, 0.50, 0.02, 0.005] + u_probabilities: [0.01, 0.08, 0.08, 0.83] diff --git a/test/stress/README.md b/test/stress/README.md new file mode 100644 index 0000000..cd33711 --- /dev/null +++ b/test/stress/README.md @@ -0,0 +1,358 @@ +# Stress Test Documentation + +Unified stress test runner for the entity resolver. This document describes usage patterns, parameters, and interpretation of results. + +## Quick Start + +### Small dataset smoke test (~30 seconds) + +```bash +poetry run python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-small.csv \ + --seed 20 \ + --records 30 \ + --output /tmp/results.json +``` + +### Mid-size dataset baseline (2-3 minutes) + +```bash +poetry run python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-mid.csv \ + --seed 200 \ + --records 500 \ + --output /tmp/baseline.json +``` + +### Cold-start test (no training) + +```bash +poetry run python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-small.csv \ + --no-train \ + --records 30 \ + --output /tmp/coldstart.json +``` + +## CLI Parameters + +### Required + +**`--dataset PATH`** +- Path to CSV file with stress test data +- Available: `test/stress/data/org-small.csv`, `test/stress/data/org-mid.csv` + +### Optional + +**`--config PATH`** +- Path to resolver config YAML (default: `config/resolver.yaml`) +- Determines blocking rules, thresholds, and Splink settings + +**`--seed N`** +- Number of mentions to seed resolver with before stress loop (default: 200) +- Higher seed = warmer start, more stable latency +- Lower seed = cold-start behavior, variable latency + +**`--records N`** +- Number of records to process in stress loop +- If omitted, processes all remaining records (after seed) + +**`--time SECONDS`** +- Instead of fixed record count, run stress loop for N seconds +- Mutually exclusive with `--records` +- Useful for capacity planning: "How many records in 60 seconds?" + +**`--output PATH`** +- JSON file to save results (default: `/tmp/stress_result.json`) + +**`--name STR`** +- Experiment name (default: dataset basename, e.g., `org-small`) + +**`--no-train`** +- Skip training; use cold-start parameters only (forces `--seed 0`) +- Tests resolver behavior with only Splink cold-start probabilities +- No EM training occurs; model uses hard-coded m/u values from config +- Useful for measuring pure latency baseline without training overhead + +## Understanding Results + +### Summary Output + +``` +====================================================================== +Experiment: org-small +====================================================================== +Dataset: test/stress/data/org-small.csv +Mentions: 100 total, 50 stressed +Seeding: 20 mentions + +Resolved clusters: 25 +Latency (ms): + Mean: 145.32 + Median: 143.87 + Std: 12.45 + Min: 121.03 + P95: 168.19 + P99: 171.02 + Max: 175.45 + +Memory: 1.2 MB (peak) +Total time: 7.3 sec +====================================================================== +``` + +### Key Metrics + +**Resolved clusters** +- Number of distinct clusters created by the resolver during stress test +- Indicates clustering behavior and diversity of matches + +**Latency (ms)** +- **Mean**: Average per-request time (typical case) +- **Median**: 50th percentile (robust to outliers) +- **Std**: Standard deviation (variability) +- **P95, P99**: 95th and 99th percentile (tail behavior) +- **Min, Max**: Range (watch for outliers suggesting GC or I/O stalls) + +**Memory** +- Peak memory used during stress loop (MB) +- In-memory DuckDB + Splink DataFrame size +- Should remain stable; growth suggests memory leak + +**Total time** +- Wall-clock seconds for stress loop +- Includes I/O, GC, all overhead +- Throughput = records / time + +### JSON Schema + +The JSON output has this structure: + +```json +{ + "name": "experiment_name", + "dataset_path": "test/stress/data/org-small.csv", + "n_mentions": 100, + "n_records_stressed": 50, + "n_seed": 20, + "n_clusters": 25, + "mean_latency_ms": 145.32, + "median_latency_ms": 143.87, + "p95_latency_ms": 168.19, + "p99_latency_ms": 171.02, + "min_latency_ms": 121.03, + "max_latency_ms": 175.45, + "stdev_latency_ms": 12.45, + "peak_memory_mb": 1.2, + "total_time_sec": 7.3, + "metrics": [ + { + "record_idx": 20, + "mention_id": "d00001234", + "latency_ms": 145.67, + "cluster_id": "cl000042", + "n_candidates": 5, + "score": 0.92 + }, + ... + ] +} +``` + +## Stress Test Datasets + +Organization datasets for entity resolution testing across varied scales. + +### org-small.csv — Small Organization Dataset +- **Size**: 100 organizations (12 KB) +- **Use Case**: Quick testing and validation, smoke testing with realistic EU organization data +- **Expected latency**: ~15-25ms per request +- **Geography**: European organizations with country codes (ISO 3166-1 alpha-3) + +### org-mid.csv — Mid-Size Organization Dataset +- **Size**: 5,497 organizations (456 KB) +- **Use Case**: Performance baseline testing, representative dataset for entity resolution evaluation +- **Expected latency**: ~100-200ms per request (scaling effects) +- **Geography**: European organizations with country codes (ISO 3166-1 alpha-3) + +### CSV Schema + +``` +mention_id,legal_name,country_code,nuts_code,post_code,post_name,thoroughfare +d000001,"SNAGA, družba za ravnanje z odpadki in druge komunalne storitve, d.o.o.",SVN,SI,2000,Maribor,Nasipna ulica 64 +d000002,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d000003,Universitair Ziekenhuis Gent,BEL,BE234,9000,Gent,Corneel Heymanslaan 10 +... +``` + +**Fields**: +- `mention_id`: Unique mention identifier (e.g., `d000001`) +- `legal_name`: Organization name (company/institution name, may contain special characters and formatting) +- `country_code`: ISO 3166-1 alpha-3 code (European countries) +- `nuts_code`: NUTS (Nomenclature of Territorial Units for Statistics) region code +- `post_code`: Postal code (may be empty) +- `post_name`: City or postal locality name +- `thoroughfare`: Street address or location (may be empty) + +## Cold-Start Testing + +### What is Cold-Start? + +Cold-start means resolving mentions **without prior training**. The resolver uses only: +- Cold-start m/u probabilities from config (hardcoded) +- No EM training +- No seeding (resolver empty) + +Useful for: +- Measuring "out-of-the-box" latency (no training overhead) +- Baseline performance before any warm data +- Testing Splink linker startup cost + +### Running Cold-Start Tests + +```bash +# Pure cold-start: no seeding, no training +poetry run python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-small.csv \ + --no-train \ + --records 30 +``` + +The `--no-train` flag: +- Forces `--seed 0` (no seeding) +- Skips EM training +- Uses cold-start parameters from config YAML + +### Expected Behavior + +Cold-start results typically show: +- **Higher latency** than trained (no optimized parameters) +- **More variable latency** (P99 >> Mean, indicating higher uncertainty) +- **Faster startup** (no EM training overhead) + +Example output: +``` +Experiment: org-small_coldstart +Seeding: 0 mentions +Latency (ms): + Mean: 226.54 + Median: 225.72 + P95: 272.27 + P99: 272.27 +``` + +vs. trained (for comparison): +``` +Experiment: org-small +Seeding: 20 mentions +Latency (ms): + Mean: 218.76 + Median: 219.37 + P95: 238.11 +``` + +### Cold-Start vs Warm-Start Comparison + +```bash +# Warm-start baseline +poetry run python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-small.csv \ + --seed 50 \ + --records 50 \ + --output /tmp/warm.json + +# Cold-start equivalent +poetry run python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-small.csv \ + --no-train \ + --records 50 \ + --output /tmp/cold.json +``` + +Compare `mean_latency_ms` in both JSON files to measure training benefit. + +## Exit Strategies + +### Record-based (default) + +Process a fixed number of records: + +```bash +# Process exactly 100 records after seeding +python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-mid.csv \ + --seed 200 \ + --records 100 +``` + +**Pros**: +- Deterministic (same input = same output) +- Good for regression testing and comparisons +- Reproducible across runs + +**Cons**: +- May not reflect real-world time constraints + +### Time-based + +Process records for a fixed duration: + +```bash +# Run for 60 seconds, process as many records as possible +python3 test/stress/stress_test.py \ + --dataset test/stress/data/org-mid.csv \ + --seed 200 \ + --time 60 +``` + +**Pros**: +- Reflects real-world SLA constraints +- Good for capacity planning +- Shows throughput under time pressure + +**Cons**: +- Non-deterministic (latency affects record count) +- Harder to compare across runs + +## Assumptions & Constraints + +1. **In-memory DuckDB**: All data fits in RAM + - Suitable for POC/testing (< 1GB) + - Not for production (use file-backed DB or distributed) + +2. **Single-threaded**: No parallelization + - Conservative latency measurement (no contention) + - Useful for baseline, not production throughput + +3. **Cold Splink linker**: No pre-trained model + - Uses cold-start parameters from config + - EM training happens during seed phase + - Latency may stabilize after first N records + +4. **Single config**: All experiments use one resolver config + - To test different configs, run separate experiments + - Results not comparable if configs differ + +## Troubleshooting + +**"ModuleNotFoundError: No module named 'ere'"** +- Run with `poetry run`: `poetry run python3 test/stress/stress_test.py` + +**"No such file: test/stress/data/org-small.csv"** +- Check dataset path is correct +- Datasets must be in `/home/greg/PROJECTS/ERS/ere-basic/test/stress/data/` + +**"Your model is not yet fully trained" warnings** +- Normal with small seed or sparse data +- Splink uses cold-start parameters for untrained levels +- More seed data improves training (try `--seed 100`) + +**Latency spikes (P99 >> Mean)** +- May indicate GC pauses or I/O stalls +- Try on quieter system or increase seed size for stability +- Use `--verbose` to see detailed timing + +**Memory grows over time** +- Check `peak_memory_mb` in JSON output +- If > 1GB with 5k records, investigate for leaks +- Consider smaller seed or fewer records diff --git a/test/stress/data/org-mid.csv b/test/stress/data/org-mid.csv new file mode 100644 index 0000000..74222d1 --- /dev/null +++ b/test/stress/data/org-mid.csv @@ -0,0 +1,5498 @@ +mention_id,legal_name,country_code,nuts_code,post_code,post_name,thoroughfare +d000001,"SNAGA, družba za ravnanje z odpadki in druge komunalne storitve, d.o.o.",SVN,SI,2000,Maribor,Nasipna ulica 64 +d000002,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d000003,Universitair Ziekenhuis Gent,BEL,BE234,9000,Gent,Corneel Heymanslaan 10 +d000004,Markt Eggolsheim,DEU,DE248,91330,Eggolsheim,Hauptstraße 27 +d000005,Bright Professionals bv,NLD,NL,,Haarlem, +d000006,Eurohelp Consult,ROU,RO411,200217,Craiova,Str. Pictor Obedeanu Oscar nr. 13 +d000007,Ville d'Antibes Juan-les-Pins,FRA,FRL03,06606,Antibes Cedex,"Direction de la commande publique, bâtiment «Orange bleu», 4e étage, 11 boulevard Chancel, BP 2205" +d000008,Reta - prevozi Marko Krže s.p.,SVN,SI,1310,Ribnica,Žlebič 38 +d000009,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000010,Česká republika – Ministerstvo vnitra,CZE,CZ,,Praha 7, +d000011,Gmina Nowy Tomyśl,POL,PL,64-300,Nowy Tomyśl,Poznańska 33 +d000012,"Hispano Igualadina, S. L.",ESP,ES511,08700,Igualada,"C/ Mestre Montaner, 50" +d000013,Sicurezza e ambiente srl,ITA,ITI43,,Roma, +d000014,Stadt Osnabrück — Fachdienst Öffentliche Aufträge,DEU,DE944,49074,Osnabrück,Bierstraße 2 +d000015,Medicina trgovina d.o.o.,HRV,HR,10257,Brezovica,Zeleni brijeg 1C +d000016,"Full Body Insight, S. L.",ESP,ES,46520,Sagunto (Valencia),"Avenida 9 d´Octubre, 106, entresuelo, despacho 9" +d000017,Vermögen und Bau Baden-Württemberg Amt Karlsruhe,DEU,DE122,76131,Karlsruhe,Engesserstraße 1 +d000018,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d000019,Bpifrance Assurance Export,FRA,FR107,94710,Maisons-Alfort Cedex,27-31 avenue du Général-Leclerc +d000020,Weiss Dienstleistungen GmbH,DEU,DE21H,,Planegg, +d000021,Fakultní nemocnice v Motole,CZE,CZ010,150 06,Praha 5,V Úvalu 84 +d000022,Tinmar Energy S.A.,ROU,RO321,014476,București,Str. Floreasca nr. 246C +d000023,Albert Ziegler GmbH,DEU,DE11C,,Giengen, +d000024,Deloitte expertises Européennes et politiques publiques,FRA,FRL04,13002,Marseille,"immeuble Castel Office, boulevard Jacques Saadé" +d000025,EMM Life Science AB,SWE,SE110,129 39,Hägersten,"EMM Life Science AB, Mamsell Ullas Väg 3" +d000026,Österreichische Bundesforste AG,AUT,AT,3002,Purkersdorf,Pummergasse 10-12 +d000027,Ville de Lens,FRA,FRE12,62300,Lens,17 bis place Jean Jaurès +d000028,Archiwum Narodowe w Krakowie,POL,PL213,30-960,Kraków,ul. Sienna 16 +d000029,InnovationSPIN Lemgo GmbH,DEU,DEA45,32657,Lemgo,Johannes-Schuchen-Straße 4 +d000030,UMO Sp. z o.o.,POL,PL,05-220,Zielonka,ul. Henryka Sienkiewicza 61 +d000031,"Kemofarmacija, veletrgovina za oskrbo zdravstva, d.d.",SVN,SI,1000,Ljubljana,Cesta na Brdo 100 +d000032,"Transportes Urbanos de Sevilla, S. A. M.",ESP,ES618,41007,Sevilla,"Avenida Andalucía, 11" +d000033,RSG,FRA,FRY30,97300,Cayenne,"8 rue des Bourdins, ZI Collery 1" +d000034,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d000035,VTT Technical Research Centre of Finland Ltd,FIN,FI,02044,Espoo,"PO Box 1000, VTT" +d000036,Tinmar Energy S.A.,ROU,RO321,014476,București,Str. Floreasca nr. 246C +d000037,Vergabe und Beschaffungszentrum Dortmund,DEU,DEA52,44135,Dortmund,Viktoriastraße 15 +d000038,Les repas sant2,FRA,FR,69340,Francheville, +d000039,Universiteit Twente,NLD,NL,7500 AE,Enschede,Postbus 217 +d000040,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d000041,Strungariu & CO Rigams LM SNC,ROU,RO213,707027,Iași,Str. Carpați nr. 5 +d000042,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000043,Conseil départemental Haute-Garonne,FRA,FRJ23,31090,Toulouse Cedex 9,1 boulevard de la Marquette +d000044,Uppsala Innovation Centre AB,SWE,SE121,,Uppsala, +d000045,SARL HBM Architectes (titulaire),FRA,FRJ22,12000,Rodez,37 rue Béteille +d000046,Ned Com,ROU,RO223,905700,Constanța,Str. Vârfu cu Dor nr. 26 +d000047,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d000048,"Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle",DEU,DED41,09111,Chemnitz,Friedensplatz 1 +d000049,Merit Medical Systems AB,SWE,SE110,114 79,Stockholm,Box 1485 +d000050,SARL clinic auto: point's,FRA,FRK22,07200,Aubenas,ZA Moulon +d000051,"Staatsbetrieb Sächsisches Immobilien- und Baumanagement, Zentrale, SSC VVM, Außenstelle Dresden 1, Zentrale Vergabestelle",DEU,DED2,01099,Dresden,Königsbrücker Str. 80 +d000052,Syddansk Universitet,DNK,DK0,5230,Odense M,Udbudskontoret +d000053,Markt Berchtesgaden,DEU,DE215,83471,Berchtesgaden,Rathausplatz 1 +d000054,UAB „Ignitis“,LTU,LT,,Vilnius, +d000055,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d000056,Johanniter-Unfall-Hilfe e.V.,DEU,DEA11,40233,Düsseldorf,Erkrather Str. 245 +d000057,Kiinteistö Oy Biomedicum Helsinki,FIN,FI1B,FI-00290,Helsinki,Haartmaninkatu 8 +d000058,SCHLÜTER+THOMSEN Ingenieurgesellschaft mbH & Co. KG,DEU,DEF04,24537,Neumünster,Rendsburger Straße 162 +d000059,"AIG Europe, S. A., Sucursal España",ESP,ES120,,Madrid, +d000060,Gemeinde Hallwang,AUT,AT323,5300,Hallwang,Dorfstraße 45 +d000061,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d000062,Phinelec,FRA,FRL,13015,Marseille,21 rue André Hallar +d000063,Vejle Kommune,DNK,DK032,7100,Vejle,Skolegade 1 +d000064,SDU,DNK,DK,,Odense M, +d000065,Schenker Deutschland AG,DEU,DE300,40472,Düsseldorf, +d000066,Espoon kaupunki,FIN,FI1B1,FI-02070,Espoo,PL 640 +d000067,"Protección y Electrónica del Sur, S. L.",ESP,ES,41500,Alcalá de Guadaíra (Sevilla),"C/ Equidad, 16, polígono industrial Cabeza Hermosa" +d000068,CAP sciences CCSTI,FRA,FRI12,33300,Bordeaux,hangar 20 quai Bacalan +d000069,Talend Germany GmbH,DEU,DEA22,53113,Bonn,Baunscheidstr. 17 +d000070,Secretaría General de la Fundación Internacional y para Iberoamérica de Administración Políticas Públicas,ESP,ES300,28040,Madrid,"C/ Beatriz de Bobadilla, 18, 4.ª planta" +d000071,Distrito de Arganzuela,ESP,ES300,28045,Madrid,"Paseo de la Chopera, 10" +d000072,Società cattolica di assicurazioni — soc. coop.,ITA,ITH31,,Verona, +d000073,Ginger CEBTP,FRA,FRE12,62400,Béthune,technoparc Futura +d000074,"Bundesministerium für Kunst, Kultur, öffentlichen Dienst und Sport",AUT,AT13,1030,Wien,Radetzkystraße 2 +d000075,Dirmed,FRA,FRL04,13331,Marseille Cedex 03,16 rue Antoine Zattara — CS 70248 +d000076,imp GmbH,DEU,DEA5,59823,Arnsberg,im Neyl 18 +d000077,"Stadt Leipzig, Amt für Jugend, Familie und Bildung",DEU,DED51,04159,Leipzig,Georg-Schumann-Straße 357 +d000078,Europharma Ltd,MLT,MT,BKR-9076,Birkirkara [Birkirkara],Catalunya Buildings Psaila Street +d000079,Excelentísimo Ayuntamiento de Ciudad Real,ESP,ES,13001,Ciudad Real,"Plaza Mayor, 1" +d000080,Nifor Limited,ARE,,11111,Abu Dhabi,Incubator Building Ground Floor Masdar City +d000081,Przedsiębiorstwo Usług Komunalnych Eko Sp. z o.o.,POL,PL62,14-200,Iława, +d000082,FastWeb SpA,ITA,ITC4C,,Milano (MI), +d000083,ArGe Bio,DEU,DE239,,Neunburg, +d000084,"Medias International, trgovanje in trženje z medicinskim materialom d.o.o.",SVN,SI,1000,Ljubljana,Leskoškova cesta 9D +d000085,SGAMI Sud-Ouest,FRA,FRI,33041,Bordeaux,89 cours Dupré de Saint-Maur +d000086,Löwen Medien Service GmbH,DEU,DE911,38104,Braunschweig, +d000087,CRS Laboratories Oy,FIN,FI1D9,,Kempele, +d000088,Antea Group,FRA,FRK26,,Rillieux-la-Pape, +d000089,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d000090,"Mecánicas Bolea, S. A.",ESP,ES62,30353,Cartagena, +d000091,O-K-TEH d.o.o.,HRV,HR050,10090,Zagreb,Vučak 16a +d000092,Global Mobility Moving AB,SWE,SE232,753 23,Uppsala,Danmarksgatan 47 +d000093,"Arch.Design, s.r.o.",CZE,CZ064,616 00,Brno,"Sochorova 3178/23, Žabovřesky" +d000094,Vertis Environmental Finance,BEL,BE,1050,Brussel,Louizalaan 475 +d000095,Ředitelství silnic a dálnic ČR,CZE,CZ01,140 00,Praha 4,Na Pankráci 546/56 +d000096,CMC Byggadministration Aktiebolag,SWE,SE232,414 62,Göteborg,Djurgårdsgatan 9 +d000097,Salisbury Plain Academies,GBR,UKK15,SP4 8HH,Salisbury,"Avon Valley College, Durrington, Salisbury, SP4 8HH" +d000098,"Total Service, a.s.",CZE,CZ010,170 00,Praha 7-Holešovice,U Uranie 954/18 +d000099,"Pharmamed-Mado, družba za trgovino s profesionalno medicinsko opremo in pripomočki, d.o.o.",SVN,SI,1000,Ljubljana,Leskoškova cesta 9E +d000100,Teknologian tutkimuskeskus VTT Oy,FIN,FI,FI-02044,VTT,PL 1000 +d000101,Tegral GmbH,DEU,DEC04,,Überherrn, +d000102,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d000103,"Spesa Ingeniería, S. A.",ESP,ES243,50004,Zaragoza,"Avenida César Augusto, 3, 10.º C" +d000104,St. Martini Krankenhaus in Duderstadt,DEU,DE929,37115,Duderstadt,Göttinger Straße 34 +d000105,Ramboll Finland Oy,FIN,FI1B1,,Espoo, +d000106,Przedsiębiorstwo Wodociągów i Kanalizacji Sp. z o.o.,POL,PL633,81-311 Gdynia,Gdynia,Witomińska 29 +d000107,Agencia de Ciberseguretat de Catalunya,ESP,ES511,08908,L'Hospitalet de Llobregat,"C/ Salvador Espriu, 45-51" +d000108,AVERS spol. s r.o.,CZE,CZ010,141 00,Praha 4–Michle,Michelská 240/49 +d000109,Stadibau GmbH - Gesellschaft für den Staatsbediensteten Wohnungsbau in Bayern mbH,DEU,DE212,80804,München,Mottlstr. 1 +d000110,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000111,Javni zavod Mladi zmaji - Center za kakovostno preživljanje prostega časa mladih,SVN,SI,1000,Ljubljana,Resljeva cesta 18 +d000112,Departamento de Salud de Sagunto — Dirección Económica-Gerencia,ESP,ES523,46520,Sagunto,"Avenida Ramón i Cajal, s/n" +d000113,Synergie,FRA,FR101,75016,Paris,11 avenue du Colonel-Bonnet +d000114,"Landratsamt Esslingen, Amt für Kreisimmobilien und Hochbau, Amt 54",DEU,DE113,73728,Esslingen,Pulverwiesen 11 +d000115,Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos,LTU,LT,LT-50161,Kaunas,Eivenių g. 2 +d000116,Rogaland Fylkeskommune,NOR,NO0A1,4012,Stavanger,Bergelandsgården 30 +d000117,Eesti Töötukassa,EST,EE,11412,Tallinn,Lasnamäe tn 2 +d000118,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d000119,Medway International GmbH,DEU,DE600,20095,Hamburg,Schopenstehl 15 +d000120,Baxter Polska Sp. z o.o.,POL,PL,00-380,Warszawa,ul. Kruczkowskiego 8 +d000121,Mazars SA,FRA,FR105,92400,Courbevoie,61 rue Henri Regnault +d000122,Coor Norrland Lokalvård AB,SWE,SE332,856 33,Sundsvall,Heffners Allé 52 +d000123,Bouygues Bâtiment Île-de-France SAS,FRA,FR10,78061,Saint-Quentin-en-Yvelines,"1 avenue Eugène Freyssinet, Guyancourt" +d000124,Conseil departemental des Vosges,FRA,FRF34,88088,Épinal Cedex 9,8 rue de la Préfecture +d000125,AED les Ateliers d'Ascalon,FRA,FRE21,02350,Liesse-Notre-Dame,68 rue de l'Abbé-Duployé +d000126,Abena-Helpi prodaja medicinskih in drugih pripomočkov d.o.o.,SVN,SI,1236,Trzin,Dobrave 7B +d000127,WSP Sverige AB,SWE,SE224,121 88,Stockholm-Globen, +d000128,Mairie de Liévin,FRA,FRE12,62800,Liévin,45 rue E Vaillant +d000129,La formidable Armada,FRA,FRK26,69001,Lyon,16 rue René-Leynaud +d000130,Landkreis Göttingen,DEU,DE91C,37083,Göttingen,Reinhäuser Landstraße 4 +d000131,Agenția Națională de Administrare Fiscală,ROU,RO321,050741,Bucureşti,Str. Apolodor nr. 17 +d000132,"Z + M Partner, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Valchařská 3261/17, Moravská Ostrava" +d000133,Inter Koop družba za trgovino in proizvodnjo d.o.o.,SVN,SI,2000,Maribor,Zrkovska cesta 97 +d000134,"Interserve Facilities Services, S. A. U.",ESP,ES300,,Madrid, +d000135,"Framed, trgovina in storitve, d.o.o.",SVN,SI,1236,Trzin,Borovec 18 +d000136,Glissando,ROU,RO424,300167,Timișoara,Str. Gării nr. 15 +d000137,Instytut Hematologii i Transfuzjologii,POL,PL911,02-776,Warszawa,ul. Indiry Gandhi 14 +d000138,Espoon kaupunki,FIN,FI1B1,,Espoo, +d000139,Schäfer Trennwandsysteme GmbH,DEU,DEB1B,56593,Horhausen,Industriepark 37 +d000140,Silnice LK a.s.,CZE,CZ051,466 05,Jablonec nad Nisou,Československé armády 4805/24 +d000141,Takeda Pharmaceuticals Czech Republic s.r.o.,CZE,CZ01,120 00,Praha 2,Škrétova 490/12 +d000142,Mathem i Sverige AB,SWE,SE2,114 59,Stockholm,Östermalmsgatan 87D +d000143,Vereniging van Vlaamse Huisvestingsmaatschappijen,BEL,BE211,2020,Antwerpen,Evert Larockstraat 6 +d000144,Municipiul Reșița,ROU,RO422,320084,Reșița,Str. 1 Decembrie 1918 nr. 1A +d000145,Thinkproject Conclude GmbH,DEU,DEA1A,,Wuppertal, +d000146,Malermester Tommy Mørk AS,NOR,NO092,4626,Kristiansand S,Kartheia 5 +d000147,Joensuun Yrityskiinteistöt Oy,FIN,FI1D3,,Joensuu, +d000148,"Vilex '94. Ipari-, Szolgáltató- és Kereskedelmi Kft.",HUN,HU,4100,Berettyóújfalu,Széchenyi utca 74. +d000149,Arpiem Aviation,ROU,RO322,075100,Otopeni,Calea Bucureștilor nr. 224E +d000150,Občina Šoštanj,SVN,SI,3325,Šoštanj,Trg svobode 12 +d000151,Ute mark & miljö i Örebro AB,SWE,SE,702 27,Örebro,Nastagatan 22 +d000152,"Správa silnic Moravskoslezského kraje, příspěvková organizace",CZE,CZ080,702 23,Ostrava,Úprkova 795/1 +d000153,Teampro Strategy Consulting,ROU,RO321,024054,București,"Str. Dimitrie Onciu nr. 18, sector 2" +d000154,R4 Korjausurakointi Tampere Oy,FIN,FI197,FI-33800,Tampere,Viinikankatu 49 +d000155,Lamor Corporation Oy,FIN,FI1B1,,Porvoo, +d000156,Minnucci Associati srl,ITA,ITI43,00061,Anguillara Sabazia,via Comunale di San Francesco 768 +d000157,Distribuție Energie Oltenia S.A.,ROU,RO411,200769,Craiova,"Calea Severinului nr. 97, parter, et. 2, 3, 4" +d000158,Matka-Kyllönen Oy,FIN,FI1D8,FI-88900,Kuhmo,Kainuuntie 84 +d000159,Farid industrie SpA,ITA,ITC11,,Vinovo, +d000160,Terra-Log Mélyépítő Kft.,HUN,HU110,1124,Budapest,Bürök utca 34–36. +d000161,Delo Časopisno založniško podjetje d.o.o.,SVN,SI,1000,Ljubljana,Dunajska cesta 5 +d000162,Københavns Kommune,DNK,DK011,2200,København,Sjællandsgade 40 +d000163,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d000164,Atlantic Vert,FRA,FR,44412,Rezé, +d000165,Société Alpbus Fournier,FRA,FR,74800,Saint-Pierre-en-Faucigny,32 rue des Vanneaux — ZAE des Jourdies +d000166,Unipolsai assicurazioni SpA,ITA,ITH55,,Bologna, +d000167,Elektro Redeker e. K.,DEU,DEA36,,Recklinghausen, +d000168,Electro Standard S.R.L.,ROU,RO211,600332,Bacău,Str. Mărăști nr. 18 +d000169,"Maxto ITS Sp. z o.o., Sp. k.",POL,PL,32-085,Modlniczka,ul. Willowa 87 +d000170,Malerei Hosp KG,AUT,AT332,6020,Innsbruck,Ampferer Straße 60 +d000171,BWI GmbH,DEU,DE212,80637,München,Dachauer Str 128 +d000172,Kreisverwaltung Mayen-Koblenz,DEU,DEB17,56068,Koblenz,Bahnhofstr. 9 +d000173,Les résidences de l'Orléanais — OPH d'Orléans Métropole,FRA,FRB06,45081,Orléans,16 avenue de la Mouillère +d000174,Ever Pharma GmbH,DEU,DE,,Gröbenzell, +d000175,Lernen fördern e. V.,DEU,DEA37,49477,Ibbenbüren, +d000176,Vrtec Hansa Christiana Andersena,SVN,SI,1000,Ljubljana,Rašiška ulica 7 +d000177,Spitalul Clinic Municipal „Dr. Gavril Curteanu”,ROU,RO111,410469,Oradea,Str. Corneliu Coposu nr. 12 +d000178,Karanta Medical trgovska družba d.o.o.,SVN,SI,1000,Ljubljana,Poljanski nasip 6 +d000179,"Centro Hospitalar Universitário de Lisboa Norte, E. P. E.",PRT,PT170,1649-035,Lisboa,Lisboa +d000180,"Rádio e Televisão de Portugal, S. A.",PRT,PT170,1849-030,Lisboa,"Avenida Marechal Gomes da Costa, 37" +d000181,VERSAMED Sp. z o.o.,POL,PL841,15-703,Białystok, +d000182,"Stadt Wil, Departement Bau, Umwelt und Verkehr Stadtplanung",CHE,CH0,9552,Bronschhofen,Hauptstraße 20 +d000183,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000184,Weatherford Atlas GIP S.A.,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2A +d000185,Byggmester Oddleif Henriksen AS,NOR,NO092,4656,Hamresanden,Krittveien 44 +d000186,Microsound Kereskedelmi és Szolgáltató Kft.,HUN,HU110,1037,Budapest,Kunigunda útja 39. +d000187,SARL cabinet Bec,FRA,FR,,Mareuil-les-Meaux, +d000188,TREBOR DRUM CONSTRUCT SRL,ROU,RO111,410265,Oradea,"Strada Erofte Grigore, Nr. 1B" +d000189,Argenta Sp. z o.o.,POL,PL418,60-401,Poznań,Polska 114 +d000190,Juuan kunta,FIN,FI1D3,,Juuka, +d000191,Gemeente Uithoorn,NLD,NL,1423 AJ,Uithoorn,Laan van Meerwijk 16 +d000192,"Iturri Portugal Indústria e Segurança, S. A.",PRT,PT170,,Palmela, +d000193,Crayon Deutschland GmbH,DEU,DE21H,82008,Unterhaching,Inselkammerstraße 12 +d000194,Ornithologische Gesellschaft Baden-Württemberg e. V.,DEU,DE14,72072,Tübingen, +d000195,Servelect S.R.L.,ROU,RO113,400573,Cluj-Napoca,"Str. Teleorman nr. 23, sector: -, județ Cluj, localitate: Cluj-Napoca, cod poștal: 400573" +d000196,FBSerwis Dolny Śląsk Sp. z o.o.,POL,PL515,57-410,Ścinawka Średnia,Ścinawka Dolna 86 +d000197,Hrvatski zavod za transfuzijsku medicinu,HRV,HR,10000,Zagreb,Petrova 3 +d000198,SWECO Structures AB,SWE,SE224,100 26,Stockholm,Box 34044 +d000199,Järfälla kommun,SWE,SE110,177 80,Järfälla,i.u +d000200,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000201,Krypton Chemists Ltd,MLT,MT,,Naxxar [In-Naxxar],"Cantrija Complex, Triq It-Targa, Maghtab," +d000202,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d000203,APRR Direction Infrastructure Patrimoine Environnement,FRA,FRC11,21850,Saint-Apollinaire,36 rue du Docteur Schmitt +d000204,PAI INVEST nv,BEL,BE211,2030,Antwerpen,Zaha HAdidplein 1 +d000205,Ethias nv,BEL,BE224,3500,Hasselt,Prins-Bisschopssingel 73 +d000206,Salto Ingénierie,FRA,FRK14,63510,Aulnat,13 bis rue du Commandant Fayolle +d000207,Osnovna šola Fram,SVN,SI,2313,Fram,Turnerjeva ulica 120 +d000208,Incom SpA,ITA,ITI13,51018,Pieve a Nievole,via Roma 47 +d000209,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4 b +d000210,Ajuntament de Barcelona — Distrito de Sant Andreu,ESP,ES511,08030,Barcelona,"Plaza Orfila, 1" +d000211,UAB „Ignitis“,LTU,LT,,Vilnius, +d000212,"Nemocnice Pardubického kraje, a.s.",CZE,CZ053,532 03,Pardubice,Kyjevská 44 +d000213,Varsinais-Suomen sairaanhoitopiirin kuntayhtymä,FIN,FI1C1,FI-20520,Turku,Kiinamyllynkatu 4-8 +d000214,Substrate HD nom commercial Volta Medical,FRA,FR,13006,Marseille,65 avenue Jules Cantini +d000215,Universität Stuttgart,DEU,DE111,70174,Stuttgart,Keplerstr. 7 +d000216,Spitalul Județean de Urgență Zalău,ROU,RO116,450129,Zalău,Str. Simion Bărnuţiu nr. 67 +d000217,WISAG Gebäudereinigung Süd-West GmbH & Co. KG,DEU,DEC01,66121,Saarbrücken,Am Halberg 10 +d000218,Direcția Generală de Asistență Socială și Protecția Copilului Brașov,ROU,RO122,500091,Brașov,Str. Iuliu Maniu nr. 6 +d000219,Spitalul Județean de Urgență Vâlcea,ROU,RO415,240011,Râmnicu Vâlcea,Calea lui Traian nr. 201 +d000220,Sarl ABC Architecture — mandataire,FRA,FRJ23,31200,Toulouse,46-48 rue André Vasseur +d000221,Groupama Antilles Guyane,FRA,FRY20,97200,Fort-de-France,pôle technologie de Kerlys — route de Saint-Christophe — bâtiment E — BP 559 +d000222,Medical intertrade d.o.o.,HRV,HR065,10431,Sveta Nedelja,Dr.Franje Tuđmana 3 +d000223,documentus Deutschland GmbH,DEU,DE600,,Hamburg, +d000224,CIDIU SpA,ITA,ITC11,10093,Collegno (TO),via Torino 9 +d000225,Agence Cantarane,FRA,FR,94200,Ivry-sur-Seine,41 rue Barbès +d000226,Landratsamt Rhein-Neckar-Kreis,DEU,DE128,69115,Heidelberg,Kurfürsten-Anlage 38-40 +d000227,"Excellent CD, spol. s r.o.",SVK,SK03,960 01,Zvolen,Š. Moyzesa 3 +d000228,Linköping Science Park AB,SWE,SE123,,Linköping, +d000229,Västra Götalandsregionen,SWE,SE232,462 80,Vänersborg,Östergatan 1 +d000230,Arpiem Aviation,ROU,RO322,075100,Otopeni,Calea Bucureștilor nr. 224E +d000231,Hemsö Fastighets AB,SWE,SE121,104 51,Stockholm,Box 24281 +d000232,Tratec Teknikken A/S,NOR,NO092,4550,Farsund,Lundevågveien 3 c +d000233,Univerza v Mariboru,SVN,SI,2000,Maribor,Slomškov trg 15 +d000234,Siemens SAS,FRA,FRF33,57084,Metz,6 rue Marie de Coëtlosquet +d000235,"Baza de Aprovizionare, Gospodărire și Reparații",ROU,RO32,077120,Jilava,Str. Sabarului nr. 1 +d000236,Universitatea de Științe Agricole și Medicină Veterinară a Banatului „Regele Mihai I al României” Timișoara,ROU,RO424,300645,Timișoara,Calea Aradului nr. 119 +d000237,"Saarland, vertreten durch das Ministerium der Justiz, dieses vertreten durch den Präsidenten des Amtsgerichts Saarbrücken",DEU,DEC01,66119,Saarbrücken,Franz-Josef-Röder-Straße 13 +d000238,SN Perfect,FRA,FR106,77290,Mitry-Mory,11 rue Henri Becquerel +d000239,Compagnons Saint-Jacques,FRA,FRI12,33370,Tresses, +d000240,Länsstyrelsen i Kronobergs län,SWE,SE212,351 86,Växjö, +d000241,"Peragro Přísečná, s.r.o.",CZE,CZ031,381 01,Český Krumlov,Přísečná 85 +d000242,Merianto Install Oy,FIN,FI1B1,,Helsinki, +d000243,Presidencia de la Diputación Provincial de Cuenca,ESP,ES423,16001,Cuenca,"C/ Aguirre, 1" +d000244,SAS BSMG-les techniciens des fluides,FRA,FR102,94100,St-Maur-des-Fossés,95 avenue Foch +d000245,aib Bauplanung Nord GmbH,DEU,DE,18055,Rostock,Rosa-Luxemburg-Straße 14 +d000246,Usługi Leśne Adrian Nidecki,POL,PL84,16-100,Sokółka,Kuryły 5 +d000247,APEC-Antwerp/Flanders Port Training center,BEL,BE21,2030,Antwerpen,Zaha Hadidplein 1 +d000248,"Landeshauptstadt Dresden, GB Stadtentwicklung, Bau, Verkehr und Liegenschaften, Amt f. Hochbau u. Immobilienverwaltung",DEU,DED21,01001,Dresden,Postfach 120020 +d000249,Sessile,FRA,FR102,77140,Nemours,"ZAC des Hauteurs du Loing, 27 chemin des Mazes" +d000250,UAB „Evolco LT“,LTU,LT,LT-50384,Kaunas,V. Krėvės pr. 94-201 +d000251,IMMA,FRA,FR101,75015,Paris,17 avenue Félix Faure +d000252,"Landeshauptstadt Düsseldorf, Der Oberbürgermeister, Stadtentwässerungsbetrieb",DEU,DEA11,40225,Düsseldorf,Auf'm Hennekamp 47 +d000253,SNRB SAS,FRA,FR108,95120,Ermont,23 rue du Plessis +d000254,AXA assicurazioni SpA,ITA,ITC4C,,Milano, +d000255,"Pohjois-Pohjanmaan elinkeino-, liikenne- ja ympäristökeskus",FIN,FI,,Oulu, +d000256,Thermo Fisher Diagnostics AB,SWE,SE121,751 37,Uppsala,"c/o Phadia AB, Box 6460" +d000257,Mediclim S.R.L.,ROU,RO321,030671,București,Str. Matei Basarab nr. 47 +d000258,Piramal Critical Care Deutschland GmbH,DEU,DE,,München, +d000259,Val de Garonne agglomération,FRA,FRI14,47213,Marmande Cedex,place du Marché — CS 70305 +d000260,Gemeente Zuidplas,NLD,NL,,Nieuwerkerk aan den IJssel, +d000261,Oktal Pharma d.o.o.,HRV,HR050,10020,Zagreb,Utinjska 40 +d000262,Turun kaupunki / Hyvinvointitoimiala,FIN,FI1C1,FI-20101,Turku,"PL 630 (käyntiosoite: Linnankatu 31, 2. krs)" +d000263,Medline international France,FRA,FR103,78960,Voisins-le-Bretonneux,parc d'Affaires — le Val Saint-Ouen 2 rue René Caudron +d000264,"Suministros Autoferr, S. L.",ESP,ES43,10800,Coria,"C/ García Morato, 22" +d000265,Media Buy Marseille,FRA,FRL04,13008,Marseille,rue Florac +d000266,CHU de Montpellier,FRA,FRJ13,34295,Montpellier Cedex 5,191 avenue du Doyen-Gaston-Giraud +d000267,Schneck Schaal Braun Ingenieurgesellschaft Bauen mbH,DEU,DE142,72070,Tübingen, +d000268,H. Isserstedt GmbH,DEU,DEA53,,Hagen, +d000269,AOK PLUS — Die Gesundheitskasse für Sachsen und Thüringen,DEU,DEG01,99084,Erfurt,Augustinerstraße 38 +d000270,"ATS-Telcom Praha, a.s.",CZE,CZ010,106 00,Praha,Nad elektrárnou 1526 45 +d000271,Trinidad Wiseman OÜ,EST,EE,12618,Tallinn,Akadeemia tee 21/4 +d000272,Stadt Offenbach am Main,DEU,DE713,63065,Offenbach am Main,Berliner Str. 100 +d000273,"Johnson & Johnson, prodaja medicinskih in farmacevtskih izdelkov, d.o.o.",SVN,SI,1000,Ljubljana,Šmartinska cesta 53 +d000274,Landkreis Kassel — Der Kreisausschuss —,DEU,DE734,34024,Kassel,Postfach 10 24 20 +d000275,Provincie Zuid-Holland,NLD,NL,2596 AW,Den Haag,Zuid-Hollandplein 1 +d000276,Gemeente Houten,NLD,NL,3995 DW,Houten,Onderdoor 25 +d000277,TFMS,FRA,FRL04,13680,Lançon,347 allée des Combes +d000278,Centre hospitalier intercommunal Nord Ardennes,FRA,FRF21,08011,Charleville-Mézières Cedex,"45 avenue de Manchester, BP 10900" +d000279,Tartu Ülikool,EST,EE,50090,Tartu linn,Ülikooli tn 18 +d000280,Kraftanlagen Hamburg GmbH,DEU,DE,22547,Hamburg,Fangdieckstraße 68 +d000281,Dravske elektrarne Maribor d.o.o.,SVN,SI,2000,Maribor,Obrežna ulica 170 +d000282,Regierungspräsidium Freiburg — Abteilung Umwelt — Referat 53.3 IRP,DEU,DE131,79114,Freiburg i. Br.,Bissierstraße 7 +d000283,SACE,ITA,IT,00187,Roma,piazza Poli 37 +d000284,"SIJ, podjetje za proizvodnjo in ekonomske storitve z marketingom, d.o.o.",SVN,SI,1230,Domžale,Krumperška ulica 11 +d000285,Comune di Caserta,ITA,ITF31,,Caserta, +d000286,Bikeleasing-Service GmbH & Co. KG,DEU,DE734,34246,Vellmar,Bewdley-Platz 18 +d000287,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d000288,Fritsch Chiari und Partner ZT GmbH,AUT,AT,1030,Wien,Marxergasse 1B +d000289,AKTIVA ČIŠČENJE d.o.o.,SVN,SI,1236,Trzin,Ljubljanska cesta 12F +d000290,Hans Barmettler & Co. AG,CHE,CH0,5054,Mooslerau,Gwärbi 325 +d000291,Lidköpings kommun,SWE,SE232,531 88,Lidköping,Skaragatan 8 +d000292,Eudes Architecture,FRA,FR,51000,Châlons-en-Champagne, +d000293,A. Zapalskio IĮ „Azas“,LTU,LT,LT-35100,Panevėžys,Tiekimo g. 2A +d000294,Universiteit Utrecht,NLD,NL,3584 CS,Utrecht,Heidelberglaan 8 +d000295,"Elektro Primorska podjetje za distribucijo električne energije, d.d.",SVN,SI,5000,Nova Gorica,Erjavčeva ulica 22 +d000296,Communauté d'agglomération du Soissonnais,FRA,FR,02880,Cuffies,"11 avenue François Mitterrand, Les Terrasses du Mail" +d000297,"Landesbetrieb Bau- und Liegenschaftsmanagement Sachsen-Anhalt (BLSA), Zentrale Vergabestelle (ZVS)",DEU,DEE03,39014,Magdeburg,"PF 3964 (Tessenowstraße 1, 39114 Magdeburg)" +d000298,KDS,FRA,FRI23,87220,Feytiat,1 allée Mouloudji +d000299,Agence de services et de paiement,FRA,FR,87040,Limoges,2 rue du Maupas +d000300,Paris — Vallée de la Marne,FRA,FR102,77207,Marne-la-Vallée Cedex,5 cours de l'Arche Guédon à Torcy +d000301,Chalmers Tekniska Högskola Aktiebolag,SWE,SE232,412 96,Göteborg,Arvid Hedvalls backe 4 +d000302,Rhein-Sieg-Kreis,DEU,DEA2C,53721,Siegburg,Kaiser-Wilhelm-Platz 1 +d000303,Göteborgs Stads Bostads AB,SWE,SE232,402 21,Göteborg,Box 5044 +d000304,"O2 Czech Republic, a.s.",CZE,CZ,140 22,Praha 4 - Michle,Za Brumlovkou 266/2 +d000305,Nemocnice Na Homolce,CZE,CZ010,150 30,Praha 5,Roentgenova 37/2 +d000306,adesso SE,DEU,DEA52,44269,Dortmund,Adessoplatz 1 +d000307,Universitätsklinikum Tübingen,DEU,DE142,72076,Tübingen,Geissweg 3 +d000308,SMACL assurances,FRA,FR,79031,Niort Cedex 9,141 avenue Salvador Allende +d000309,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d000310,France Travaux (mandataire),FRA,FR107,94460,Valenton,13 et 13 bis rue du Bois Cerdon +d000311,"ČEPRO, a.s.",CZE,CZ0,170 00,Praha 7,Dělnická 213/12 +d000312,Sor Libchavy spol. s r.o.,CZE,CZ,561 16,Libchavy,Dolní Libchavy 48 +d000313,Gemeinnützige Salzburger Landeskliniken Betriebsgesellschaft mbH,AUT,AT,5020,Salzburg,Müllner Hauptstr. 48 +d000314,"Carpintería de Madera Hermanos Valdivia, S. L.",ESP,ES704,35600,Puerto del Rosario,"C/ Hernán Cortés, 30" +d000315,Hochschule Offenburg,DEU,DE134,77652,Offenburg,Badstr. 24 +d000316,RSN Gebäudereinigung und Dienste GmbH,DEU,DEE03,39128,Magdeburg,An der Steinkuhle 1 +d000317,SDEA Alsace Moselle,FRA,FRF1,67013,Strasbourg Cedex,1 rue de Rome — CS 10020 +d000318,Saarpfalz-Kreis,DEU,DEC05,66424,Homburg,Am Forum 1 +d000319,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000320,Stadt Wien – Wiener Wohnen,AUT,AT130,1030,Wien,Rosa-Fischer-Gasse 2 +d000321,Weatherford Atlas GIP S.A.,ROU,RO,100189,Ploiești,Str. Clopotei nr. 2A +d000322,"Presidencia de la Sociedad de Infraestructuras y Equipamientos Penitenciarios y de la Seguridad del Estado, S. M. E., S. A.",ESP,ES300,28001,Madrid,"C/ Claudio Coello, 31, 5.ª planta" +d000323,OMV Petrom S.A.,ROU,RO321,013329,Bucureşti,Str. Coralilor nr. 22 +d000324,Stichting Meridiaan College katholieke scholengemeenschap voor voortgezet onderwijs,NLD,NL,3813 VD,Amersfoort,Hooglandseweg-Noord 55 +d000325,Dunántúli Regionális Vízmű Zártkörűen Működő Részvénytársaság,HUN,HU232,8600,Siófok,Tanácsház utca 7. +d000326,ATAUB,FRA,FRD22,76230,Bois Guillaume,606 chemin de la Bretèque — BP 6 +d000327,Gemeinde Birkenfeld,DEU,DE12B,75217,Birkenfeld,Marktplatz 6 +d000328,müller.schurr architekten,DEU,DE27B,87616,Marktoberdorf,Birkenweg 11 +d000329,Sopra Steria,FRA,FRK28,74940,Annecy-le-Vieux,3 rue du Pré Faucon +d000330,Luna Glanz GmbH & Co.KG,DEU,DE21H,,München, +d000331,CS Planungs- und Ingenieurgesellschaft mbH,DEU,DE300,10997,Berlin,Köpernicker Straße 145 +d000332,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4b +d000333,"Landeshauptstadt Stuttgart, Haupt- und Personalamt, Abt. Allgemeiner Service, Zentraler Einkauf",DEU,DE111,70173,Stuttgart,Eberhardstr. 61 +d000334,S.C. J'Info Tours S.R.L.,ROU,RO321,010458,București,Str. Jules Michelet nr. 1 +d000335,FastWeb SpA,ITA,ITC4C,,Milano (MI), +d000336,Tura-Terv Mérnökiroda Kft.,HUN,HU,1145,Budapest,Gyarmat utca 30. +d000337,Unipolrental SpA,ITA,ITH53,42121,Reggio Emilia,via G. B. Vico 10/C +d000338,"Freie Universität Berlin Abteilung II: Finanzen, Einkauf und Stellenwirtschaft Referat II C — Zentraler Einkauf",DEU,DE30,14195,Berlin,Thielallee 38 +d000339,AMJ Turku Audio Oy,FIN,FI1C1,,Lieto, +d000340,COMPAREX AG a SoftwareONE Company,DEU,DED51,04329,Leipzig,Blochstraße 1 +d000341,Commissariat à l'énergie atomique et aux énergies alternatives,FRA,FR,91191,Gif-sur-Yvette Cedex,CEA Paris-Saclay — Bâtiment 482 — PC n° 70 +d000342,Das Land Hessen vertreten durch die Hessische Zentrale für Datenverarbeitung,DEU,DE714,65185,Wiesbaden,Mainzer Straße 29 +d000343,USG People Business Solutions nv,BEL,BE,2000,Antwerpen,Frankrijklei 101 +d000344,Karlstads Energi Aktiebolag,SWE,SE,654 60,Karlstad,Hedvägen 20 +d000345,PreZero Service Centrum Sp. z o.o.,POL,PL712,99-300,Kutno,ul. Łąkoszyńska 127 +d000346,NIF Nemzeti Infrastruktúra Fejlesztő zártkörűen működő Részvénytársaság,HUN,HU,1134,Budapest,Váci út 45. +d000347,"SAN.KO.M., trgovina, proizvodnja in kooperacija, d.o.o.",SVN,SI,1000,Ljubljana,Ježica 17 +d000348,Bundesagentur für Arbeit Regionales Einkaufszentrum NRW,DEU,DE,40474,Düsseldorf,Josef-Gockeln-Str. 7 +d000349,Arabella-Versandbuchhandlung GmbH,DEU,DE212,80937,München, +d000350,WSP Finland Oy,FIN,FI,FI-00520,Helsinki,Pasilan Asema-aukio 1 +d000351,UAB „Kiwa Inspecta“,LTU,LT,,Vilnius, +d000352,Jensen Ingrisch Recke Architekten und Stadtplaner PartGmbB,DEU,DE212,,München, +d000353,"DRI upravljanje investicij, Družba za razvoj infrastrukture, d.o.o.",SVN,SI041,1000,Ljubljana,Kotnikova ulica 40 +d000354,Stadt Paderborn,DEU,DEA47,33102,Paderborn,Am Hoppenhof 33 +d000355,"Landeshauptstadt Düsseldorf, Der Oberbürgermeister, Rechtsamt",DEU,DEA11,40227,Düsseldorf,Willi-Becker-Allee 10 +d000356,EyeQ Instruments AG,CHE,CH0,8606,Greifensee,Seilerwis 3 +d000357,Vertex Pharmaceutical Ireland Limited,IRL,IE,D02 EK84,Dublin 2,"28-32, Pembroke Street Upper" +d000358,Spitalul Clinic Județean de Urgență „Sf. Apostol Andrei”,ROU,RO223,900591,Constanța,Str. Tomis nr. 145 +d000359,RDW en Politie,NLD,NL,2711 ER,Zoetermeer,Europaweg 205 +d000360,CCAS,FRA,FRE22,60803,Crepy-en-Valois,hôtel de ville +d000361,Medizin & Service GmbH,DEU,DED4,,Chemnitz, +d000362,Nimar,ROU,RO125,545300,Reghin,Str. Gării nr. 78/A +d000363,"Mutua de Accidentes de Canarias, Mutua Colaboradora con la Seguridad Social número 272",ESP,ES70,38003,Santa Cruz de Tenerife,"C/ Robayna, 2" +d000364,Synergie 4,FRA,FR10,91029,Évry,ZAC du Bois Chaland — 10 rue du Bois Chaland — CE 2904 Lisses +d000365,Gemeindeverband Bezirkskrankenhaus Schwaz,AUT,AT,6130,Schwaz,Swarovskistrasse 1-3 +d000366,Kur- und Touristikunternehmen der Stadt Bad Salzungen (kAöR),DEU,DEG0P,36433,Bad Salzungen,Am Flößrasen 1 +d000367,E.ON Észak-dunántúli Áramhálózati Zrt.,HUN,HU221,9027,Győr,Kandó Kálmán utca 11–13. +d000368,Újpesti Torna Egylet,HUN,HU110,1044,Budapest,Megyeri út 13. +d000369,Sweco Polska sp. z o.o.,POL,PL415,60-829,Poznań,ul. Franklina Roosevelta 22 +d000370,York Farm,ROU,RO321,011158,București,"Str. Scărlătescu nr. 17-19, sector 1" +d000371,Dach- und Gartengestaltung Stoewahs GmbH,DEU,DE218,85586 Poing,Westring 41, +d000372,Abbott Medical Sweden AB,SWE,SE11,164 07,Kista,Box 7051 +d000373,HSY Helsingin seudun ympäristöpalvelut -kuntayhtymä,FIN,FI1B,FI-00240,Helsinki,Ilmalantori 1 +d000374,Junta de Gobierno de la Diputación Provincial de León,ESP,ES413,24002,León,"Plaza de San Marcelo, 6" +d000375,La communauté d'Agglomération de Châlons-en-Champagne,FRA,FRF23,51000,Châlons-en-Champagne,"hôtel de ville, place Foch" +d000376,Elektro Compagnoni AG,CHE,CH0,8052,Zürich,Ettenfeldstraße 18 +d000377,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d000378,Sykehusinnkjøp HF,NOR,NO,9811,Vadsø,Postboks 40 +d000379,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d000380,Eiffage Route Sud-Ouest,FRA,FRG01,44156,Ancénis Cedex,ZAC de l'Aufresne — BP 30235 +d000381,Th. Geyer GmbH & Co. KG Niederlassung Berlin,DEU,DE300,10553,Berlin,Huttenstr. 34-35 +d000382,Gemeente Rotterdam,NLD,NL,3002 AN,Rotterdam,Wilhelminakade 179 +d000383,"Slovenské elektrárne, a.s.",SVK,SK,821 09,Bratislava,Mlynské nivy 47 +d000384,NHS Lanarkshire,GBR,UKM8,G71 8BB,Bothwell,"Board Headquarters, Kirkfield Cottage, Fallside Road" +d000385,Asclepios S.A.,POL,PL514,50-502,Wrocław,ul. Hubska 44 +d000386,eSzydłowski Łukasz Szydłowski,POL,PL,49-353,Brzeg,Piekarska 1 +d000387,Helseapps AS,NOR,NO074,9406,Harstad, +d000388,Schwender Energie- u. Gebäudetechnik GmbH & Co. KG,DEU,DE24B,95349,Thurnau,Limmersdorfer Str. 3 +d000389,NEOTECH,ROU,RO321,030235,București,"Str. Botev Hristo nr. 10, sector 3" +d000390,Gemeindeverband Bezirkskrankenhaus Schwaz,AUT,AT,6130,Schwaz,Swarovskistrasse 1-3 +d000391,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d000392,Municipiul Timișoara,ROU,RO424,300030,Timișoara,Bulevardul C.D. Loga nr. 1 +d000393,Frasinul,ROU,RO112,427131,Maieru,Str. Principală nr. 59 +d000394,"Consejería de Economía, Hacienda y Administración Digital",ESP,ES620,,Murcia, +d000395,ALFA farm s.r.o.,CZE,CZ010,180 00,Praha 8,"Vojenova 2481/11, Libeň" +d000396,pmp Projekt GmbH,DEU,DE600,22765,Hamburg,Max - Brauer - Allee 79 +d000397,"CBK Madeira — Corretores de Seguros, S. A.",PRT,PT300,9000-066,Funchal,"Rua da Sé, 40" +d000398,Euromat,FRA,FRM,20250,Corte,RT50 — zone Artisanale +d000399,Cicanord,FRA,FRE11,59130,La Madeleine,37 avenue des Fleurs +d000400,REA Reinhart Engert Albert Beratende Ingenieure GmbH,DEU,DE263,97076,Würzburg,Urlaubstraße 1 +d000401,JMF Metallbautechnik GmbH,DEU,DEG0B,98631,Jüchsen, +d000402,Tornion Krunni Oy,FIN,FI,FI-95401,Tornio, +d000403,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000404,AOK Baden-Württemberg,DEU,DE1,70191,Stuttgart,Presselstraße 19 +d000405,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000406,Stad Roeselare,BEL,BE256,8800,Roeselare,Botermarkt 2 +d000407,ISOTECH A.F.F. GmbH,DEU,DE132,79286,Glottertal,In den Engematten 8 +d000408,RWE Generation SE,DEU,DEA13,45141,Essen,RWE Platz 3 +d000409,Ayuntamiento de Langreo,ESP,ES120,,Principado de Asturias, +d000410,Smart Informatics s.r.o.,CZE,CZ010,120 00,Praha 2,Karlovo náměstí 285/19 +d000411,Wirtschaftsbetrieb Hagen (AöR),DEU,DEA53,58091,Hagen,Eilper Str. 132-136 +d000412,"Österreichisches Rotes Kreuz, Landesverband Burgenland",AUT,AT,7000,Eisenstadt,Henri Dunant-Straße 4 +d000413,KS services (Mandataire),FRA,FRF11,67200,Strasbourg,KS services 91 route des Romains +d000414,SAS Plançon Bariat,FRA,FR,35130,La Guerche-de-Bretagne, +d000415,Delegación del Gobierno de la Junta de Andalucía en Granada,ESP,ES614,18071,Granada,"C/ Gran Vía de Colón, 56" +d000416,GatewayBaltic Ltd,LVA,LV,LV-1010,Riga,Elizabetes iela 51 +d000417,"Técnicas y Sistemas de Conservación, S. A.",ESP,ES511,08023,Barcelona,"C/ Solanes, 2, bxs." +d000418,Gemeente Kaag en Braassem,NLD,NL,,Roelofarendsveen, +d000419,"CTM — Logística, Mudanças e Transportes, Lda.",PRT,PTZZZ,6200-027,Covilhã,"Parque Industrial, lote 5" +d000420,CA Val d'Europe Agglomération,FRA,FR102,77701,Marne-la-Vallée Cedex 4,"Château de Chessy, BP 40, Chessy" +d000421,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d000422,Assium,FRA,FR,51110,Isles-sur-Suippe, +d000423,Animal pensant,FRA,FR101,75013,Paris,10 quai d'Austerlitz Bateau Playtime +d000424,"Tentours turistična agencija, d.o.o., Ljubljanska 85, Domžale",SVN,SI,1230,Domžale,Ljubljanska cesta 85 +d000425,DREAL Bretagne,FRA,FRH,35065,Rennes Cedex,10 rue Maurice Fabre +d000426,Ingenieurbüro Pahl und Jacobsen,DEU,DEF05,25746,Heide,Schillerstraße 37 +d000427,FM Diffusion,FRA,FR103,78400,Chatou,24 avenue du Maréchal-Foch +d000428,UAB „Ignitis grupės paslaugų centras“,LTU,LT,LT-09311,Vilnius,A. Juozapavičiaus g. 13 +d000429,geiger&waltner landschaftsarchitekten GmbH,DEU,DE273,87435,Kempten (Allgäu),Burghaldegasse 26 +d000430,Département de la Moselle,FRA,FRF33,57036,Metz,"1 rue du Pont Moreau, CS 11096" +d000431,INNI Group,BEL,BE,8501,Heule,Industrielaan 5 +d000432,CEA/Grenoble,FRA,FRK24,38000,Grenoble,17 rue des Martyrs +d000433,"Diputación Foral de Bizkaia — Departamento de Euskera, Cultura y Deporte",ESP,ES213,,Bilbao,"Alameda Rekalde, 30, 48009 Bilbao (Bizkaia), Servicio de Acción Cultural — Sección de Programas Socioeducativos" +d000434,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000435,Správa státních hmotných rezerv,CZE,CZ010,150 00,Praha,Šeříková 616/1 +d000436,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d000437,"Elkoplast CZ, s.r.o.",CZE,CZ072,760 01,Zlín,Štefánikova 2664 +d000438,Terumo Sweden AB,SWE,SE232,426 71,Västra Frölunda,Sven Källfelts Gata 18 +d000439,UAB „Labochema LT“,LTU,LT,LT-03151,Vilnius,Vilkpėdės g. 22 +d000440,Vehicle Conversion Specialist Ltd,GBR,UK,HD2 1UB,Huddersfield,"Unit1, Ellis Hill, Leeds Road" +d000441,Hammaslahden Taksi ja Tilausajo,FIN,FI1D3,FI-82200,Hammaslahti,Paavontie 8 c 3 +d000442,Sia garden srl (mandataria) in RTI con AM 22 srl e Mavili srl (mandanti),ITA,ITI43,,Roma, +d000443,"Sanolabor, podjetje za prodajo medicinskih, laboratorijskih in farmacevtskih proizvodov, d.d.",SVN,SI,1000,Ljubljana,Leskoškova cesta 4 +d000444,Département de Seine-Maritime,FRA,FRD22,76101,Rouen Cedex,"Hôtel du Département, quai Jean Moulin, CS 56101" +d000445,Commune de Brignoles,FRA,FRL05,83170,Brignoles,Hôtel de Ville — 9 place Carami +d000446,Aktsiaselts Nõo Lihatööstus,EST,EE,61601,Nõo vald,Voika tn 18 +d000447,IFAM Ingenieurbüro Fassade Ausbau München GmbH,DEU,DE21H,,85622 Feldkirchen, +d000448,CHUBB France,FRA,FRF31,54320,Maxéville,6 rue Alfred Kastler +d000449,Steril România,ROU,RO321,041831,București,"Str. Metalurgiei nr. 3-5, sector 4" +d000450,Azienda napoletana mobilità SpA,ITA,ITF33,80125,Napoli,via G. Marino 1 +d000451,"MEDIS, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d000452,Reichmann Gebäudetechnik GmbH,DEU,DEG0G,,Bad Berka, +d000453,Bundesministerium für Bildung und Forschung,DEU,DE300,11055,Berlin,Dienstsitz Berlin +d000454,Skanska Direkt AB,SWE,SE,901 03,Umeå,Box 93 +d000455,Direcția Generală de Asistență Socială și Protecția Copilului Brașov,ROU,RO122,500091,Brașov,Str. Iuliu Maniu nr. 6 +d000456,GEIT Reimer Ingenieurbüro für TGA,DEU,DEF0C,24848,Kropp,Poststraße 12 +d000457,Alpha Ned 2000 Exim,ROU,RO321,010816,București,"Calea Griviței nr. 188, sector 1" +d000458,Finn og Albert Egeland AS,NOR,NO092,4688,Kristiansand S,Postboks 1592 Lundsiden +d000459,Regia Națională a Pădurilor – Romsilva R.A.,ROU,RO125,540052,Târgu Mureș,"Prin Direcția Silvică Mureș, Str. George Enescu nr. 6" +d000460,Association Compostri,FRA,FRG01,,Nantes, +d000461,Fujitsu Technology Solutions GmbH,DEU,DEA11,40472,Düsseldorf,Gladbecker Str. 7 +d000462,Genesis Pharma Cyprus Ltd.,CYP,CY,2025 Στρόβολος,Λευκωσία,"Αμφιπόλεως 2, 1ος όροφος" +d000463,Penitenciarul Brăila,ROU,RO221,810110,Brăila,Str. Carantina nr. 4A +d000464,Banedanmark,DNK,DK,1577,København V,Carsten Niebuhrs Gade 43 +d000465,Spitalul Clinic Județean de Urgență Craiova,ROU,RO411,200642,Craiova,Str. Tabaci nr. 1 +d000466,NCC Industry,NOR,NO,0101,Oslo,Postboks 93 Sentrum +d000467,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d000468,Staatliches Bau- und Liegenschaftsamt Rostock,DEU,DE803,18055,Rostock,Wallstraße 2 +d000469,Institut Català de la Salut — Hospital Universitari Vall d'Hebron,ESP,ES511,08035,Barcelona,"Passeig Vall d'Hebron, 119-129" +d000470,Uninett Sigma2 AS,NOR,NO060,7030,Trondheim,Abels gate 5 +d000471,Bert Peine + Wilhelm GmbH & Co.KG,DEU,DE21L,82205,Gilching-Argelsried,Münchner Str. 22 +d000472,YIT Suomi Oy,FIN,FI1B,FI-00620,Helsinki,Panuntie 11 +d000473,Medika d.d.,HRV,HR050,10000,Zagreb,Capraška 1 +d000474,Kemijski inštitut,SVN,SI,1000,Ljubljana,Hajdrihova ulica 19 +d000475,"Abbott Rapid Diagnostics Healthcare, S. L.",ESP,ES51,08908,Hospitalet de Llobregat,"Plaza Europa, 9-11, 6.ª planta" +d000476,Carrières de l'Est — Établissement de Sainte-Magnance,FRA,FRC14,89420,Sainte-Magnance,72 rue d'Avallon +d000477,Patronat Municipal del Museu,ESP,ES511,08401,Granollers,"Plaça Porxada, 6" +d000478,Mittetulundusühing Papaver,EST,EE,75331,Rae vald,Saarma tee 6 +d000479,Associazione «L’Albero della Vita» onlus,ITA,ITG19,96018,Pachino,via Unità 6 +d000480,"Oracle Portugal — Sistemas de Informação, Lda.",PRT,PTZZZ,2740-268,Porto Salvo,"Lagoas Park, edifício 8" +d000481,Bayerische Staatsforsten AöR,DEU,DE232,93053,Regensburg,Tillystraße 2 +d000482,Metall- und Ladenbau Jung GmbH & Co.KG,DEU,DE71E,61200,Wölfersheim,Licher Straße 41 +d000483,Harmek AB,SWE,SE231,312 51,Knäred,Lageredsvägen 2 +d000484,Immergis,FRA,FRJ13,34790,Grabels,44 rue Antoine-Jérôme-Balard +d000485,TPL Systèmes,FRA,FRI11,24200,Sarlat-la-Canéda,ZAE du Périgord Noir +d000486,Staatliches Bauamt München 1,DEU,DE212,81547,München,https://my.vergabe.bayern.de +d000487,Logirem,FRA,FRL04,13003,Marseille,111 BD national +d000488,"Deutsche Bundesbank, Beschaffungszentrum",DEU,DE712,60329,Frankfurt am Main,Taunusanlage 5 +d000489,Krausberg Eesti OÜ,EST,EE,10415,Tallinn,Suur-Patarei tn 2 +d000490,Osaühing Arimee,EST,EE,80042,Pärnu linn,Lao tn 8-10 +d000491,Schüßler-Plan Ingenieurgesellschaft mbH,DEU,DE712,60314,Frankfurt am Main,Lindleystraße 11 +d000492,"Rudicar, S. L.",ESP,ES,24549,Carracedelo,"Polígono Industrial Las Malladas, nave 8" +d000493,Kommunales Vergabezentrum Kreis Groß-Gerau für Kreis Groß-Gerau,DEU,DE717,64521,Groß-Gerau,Wilhelm-Seipp-Str. 4 +d000494,Sitec Dienstleistungs GmbH,DEU,DE,,Kerpen, +d000495,Distribuție Energie Oltenia S.A.,ROU,RO411,200769,Craiova,"Calea Severinului nr. 97, parter, et. 2, 3, 4" +d000496,HSH Entreprenør AS,NOR,NO092,4612,Kristiansand S,Markens Gate 42 +d000497,MEDICAL GRUP,ROU,RO113,400689,Cluj-Napoca,"Strada Orastie, Nr. 10" +d000498,Bouygues Énergies et Services SAS,FRA,FR10,78180,Montigny-le-Bretonneux,19 rue Stephenson +d000499,"Land Berlin, Anmietvermögen, vertreten durch die Berliner Immobilienmanagement GmbH",DEU,DE300,10178,Berlin,Alexanderstraße 3 +d000500,Lexon (GB) Ltd,GBR,UKG21,,Crumlin,6/7 Rush Drive +d000501,Pôle Habitat/Colmar Centre Alsace — OPH,FRA,FRF12,68006,Colmar Cedex,Office public de l'habitat — 27 avenue de l'Europe — BP 30334 +d000502,Hrvatska elektroprivreda d.d.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 37 +d000503,Krypton Chemists Ltd,MLT,MT,,Naxxar [In-Naxxar],"Cantrija Complex, Triq It-Targa, Maghtab," +d000504,Pop Industry S.R.L.,ROU,RO414,230070,Slatina,"Strada, Nr." +d000505,Konbini SAS,FRA,FR101,75010,Paris,48 avenue Claude Vellefaux +d000506,Thales Deutschland GmbH,DEU,DE144,89077,Ulm,Söflinger Straße 100 +d000507,Alpha Ned 2000 Exim,ROU,RO321,010816,București,"Calea Griviței nr. 188, sector 1" +d000508,WfrK — Werkstätten für raumbildende Konstruktion,DEU,DEA47,33098,Paderborn, +d000509,Salubris S.A.,ROU,RO213,700237,Iași,Str. Națională nr. 43 +d000510,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d000511,Klinički bolnički centar Osijek,HRV,HR,31000,Osijek,Josipa Huttlera 4 +d000512,B. BRAUN MEDICAL,BEL,BE,1831,Diegem,Lambroekstraat 5b +d000513,Rollladen & Insektenschutz Service,DEU,DE402,03046,Cottbus,Wernerstraße 27 +d000514,180 degrés Ingénierie,FRA,FRI12,33100,Bordeaux,1 quai Deschamps +d000515,Autobahnen- und Schnellstraßen-Finanzierungs-Aktiengesellschaft,AUT,AT,1030,Wien,"z. H. ASFINAG Bau Management GmbH, Modecenterstraße 16" +d000516,"Thüringer Ministerium für Bildung, Jugend und Sport",DEU,DEG01,99096,Erfurt,Werner - Seelenbinder - Straße 7 +d000517,SATE,FRA,FRL04,13011,Marseille,116 BLD de la Pomme +d000518,Vingmed AB,SWE,SE11,175 26,Järfälla,Box 576 +d000519,Agence de services et de paiement,FRA,FRI23,87040,Limoges,2 rue du Maupas +d000520,R.D.R. SpA,ITA,IT,,Torre del Greco (NA), +d000521,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d000522,Hoogheemraadschap Hollands Noorderkwartier,NLD,NL,1703 WC,Heerhugowaard,Stationsplein 136 +d000523,"O2 Czech Republic, a.s.",CZE,CZ,140 22,Praha 4 - Michle,Za Brumlovkou 266/2 +d000524,Whistlejacket London,GBR,UK,W1F 0PH,London,8 Berwick Street +d000525,Banco de España,ESP,ES300,28014,Madrid,"C/ Alcalá, 48" +d000526,"Alvalop Servicios XXI, S. L.",ESP,ES114,36500,Lalín,"Avenida de Buenos Aires, 103" +d000527,"Tinoco Sistemas, S. L.",ESP,ES,41009,Sevilla,"C/ Fray Luis de Granada, 1" +d000528,ASFINAG Service GmbH,AUT,AT,1030,Wien,"Modecenterstraße 16, 6.STock" +d000529,Sana Klinikum Hof GmbH,DEU,DE244,95032,Hof / Saale,Eppenreuther Str. 9 +d000530,Nevadasec Építményüzemeltetési és Biztonsági Korlátolt felelősségű társaság,HUN,HU110,1133,Budapest,Tutaj u. 6/A 3. em. 5. +d000531,Colas France,FRA,FRI32,17139,Dompierre-sur-Mer, +d000532,Universitatea „Alexandru Ioan Cuza” Iași,ROU,RO213,700506,Iași,Str. Carol I nr. 11 +d000533,"Labena trgovina, svetovanje in proizvodnja laboratorijske opreme d.o.o.",SVN,SI,1000,Ljubljana,Verovškova ulica 64 +d000534,Glaserei Udo Trögel,DEU,DED44,08541,Neuensalz,Hauptstr. 10a +d000535,CCI de Vaucluse,FRA,FRL06,84000,Avignon,46 cours Jean Jaurès +d000536,Chouffot SAS,FRA,FR104,91540,Fontenay-le-Vicomte,avenue Saint-Rémi +d000537,De LOCHTING vzw,BEL,BE,8800,Roeselare,Oude Stadenstraat 15 +d000538,Finnmap Infra Oy,FIN,FI,FI-00520,Helsinki,Ratapihantie 11 +d000539,HEWE Glas- und Metallbau GmbH,DEU,DE134,77933,Lahr,Archimedesstr. 3 +d000540,Deutsche Forschungsgemeinschaft,DEU,DEA22,53175,Bonn,Kennedyallee 40 +d000541,"AENA, S. M. E., S. A.",ESP,ES30,28017,Madrid,"Avenida de la Hispanidad, s/n" +d000542,"Dirección General de la Mutual Midat Cyclops, Mutua Colaboradora con la Seguridad Social número 1",ESP,ES511,08029,Barcelona,"Avenida Josep Tarradellas, 14-18" +d000543,Associação de Agricultores do Sul (ACOS),PRT,PT,7801-904,Beja,"Rua Cidade de São Paulo, apartado 296" +d000544,Otto Stöckl Elektroinstallationen GmbH,AUT,AT,1030,Wien,Steingasse 23 +d000545,XL Insurance Company SE,FRA,FR101,75017,Paris,61 rue Mstislav Rostropovitch +d000546,Atalian Propreté PACA,FRA,FRL04,13100,Aix-en-Provence,190 rue Nicolas-Ledoux +d000547,Department of Contracts,MLT,MT,FRN 1600,Floriana,Notre Dame Ravelin +d000548,ProRail bv,NLD,NL,3511 EP,Utrecht,Moreelsepark 3 +d000549,Helsingin ja Uudenmaan sairaanhoitopiirin kuntayhtymä / HUS Logistiikka,FIN,FI1,FI-01770,Vantaa,Uutistie 5 +d000550,Croonwolter&dros bv,NLD,NL,3002 AB,Rotterdam,Postbus 6073 +d000551,Ratatek Oy,FIN,FI,FI-01900,Nurmijärvi,Alhonniiituntie 4 +d000552,Stadt Ludwigsburg,DEU,DE115,71638,Ludwigsburg,Wilhelmstraße 11 +d000553,Ministerie van Defensie,NLD,NL,2511 CB,Den Haag,Kalvermarkt 32 +d000554,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d000555,Urtica Sp. z o.o.,POL,PL51,54-613,Wrocław,ul. Krzemieniecka 120 +d000556,Junta de Gobierno del Ayuntamiento de Murcia,ESP,ES620,30004,Murcia,"Glorieta de España, 1" +d000557,Soresic SA,BEL,BE32B,6000,Charleroi,Boulevard Mayence 1 +d000558,Broadstory,FRA,FR1,75011,Paris, +d000559,Cogeci,FRA,FRK26,69517,Vaulx-en-Velin,10 avenue des Canuts +d000560,"PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d000561,Forskningsfondens Ejendomsselskab A/S (FEAS),DNK,DK042,8200,Aarhus N,Finlandsgade 14 +d000562,Norrlands Bil Tunga Fordon AB,SWE,SE332,931 61,Skellefteå,Tjärnvägen 5 +d000563,Ruhrbahn GmbH,DEU,DEA13,45130,Essen,Zweigertstr. 34 +d000564,Intus Workforce Solutions bv,NLD,NL,3972 NG,Driebergen-Rijsenburg,Princenhof Park 12 +d000565,Samenvijf bv,NLD,NL,,Amsterdam, +d000566,Tulli,FIN,FI,FI-00520,Helsinki,Opastinsilta 12 +d000567,EJIE — Sociedad Informática del Gobierno Vasco,ESP,ES21,,Vitoria-Gasteiz,"Avenida del Mediterráneo, 14, 01010 Vitoria-Gasteiz" +d000568,Cars Philibert,FRA,FRK26,69300,Caluire-et-Cuire,24 avenue Barthélémy Thimonnier +d000569,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d000570,Västra Götalandsregionen,SWE,SE232,462 80,Vänersborg,Östergatan 1 +d000571,Lidköpings kommun,SWE,SE232,531 88,Lidköping,Skaragatan 8 +d000572,Gemeente Westland,NLD,NL,2671 VW,Naaldwijk,Verdilaan 7 +d000573,Javni zavod Mladi zmaji - Center za kakovostno preživljanje prostega časa mladih,SVN,SI,1000,Ljubljana,Resljeva cesta 18 +d000574,KTO engineering GbR,DEU,DE27C,87730,Bad Grönebach,Pappenheimerstraße 4 +d000575,Siemens SAS,FRA,FRF33,57084,Metz,6 rue Marie de Coëtlosquet +d000576,Brandner Unterallgäu UG,DEU,DE27C,,Babenhausen, +d000577,"Integral de Vigilancia y Control, S. L.",ESP,ES213,,Santurtzi, +d000578,Ortostuudio OÜ,EST,EE,76505,Saue vald,Sooja tn 1 +d000579,José Damián Alonso Robayna (Áridos Alonso),ESP,ES704,35600,Puerto del Rosario,"C/ Tajinaste, 28" +d000580,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d000581,Akbal Bau GmbH,DEU,DE21B,44809,Bochum,Berggate 69 +d000582,Institut Jožef Stefan,SVN,SI,1000,Ljubljana,Jamova cesta 39 +d000583,SPL Perpignan Méditerranée,FRA,FRJ15,66000,Perpignan,35 boulevard Saint-Assiscle Bât C +d000584,Iserba,FRA,FRK21,01704,Beynost,303 rue du Chat Botté — CS 10412 +d000585,Scop SA Savoirsplus,FRA,FRG02,49320,Brissac-Loire-Aubance,18 boulevard des Fontenelles +d000586,Ayuntamiento de Vitoria-Gasteiz,ESP,ES211,,Vitoria-Gasteiz,"C/ Pintor Teodoro Dublang, 25, bajo, 01008 Vitoria-Gasteiz (Álava-Araba)" +d000587,Communauté d'agglomération Porte de l'Isère,FRA,FRK24,38081,L'Isle-d'Abeau,"Service «Achats Marchés publics», 17 avenue du Bourg" +d000588,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d000589,Arca Mondo Chim S.R.L.,ROU,RO321,050801,București,"Str. Baltagului nr. 5, sector 5" +d000590,Menigo Foodservice AB,SWE,SE232,721 28,Västerås,Box 1120 +d000591,Huddinge kommun,SWE,SE,141 61,Huddinge,Kommunalvägen 28 +d000592,Município de Lisboa,PRT,PT170,1749-099,Lisboa,"Campo Grande, 25, 9.º A" +d000593,Deutsche Rentenversicherung Knappschaft-Bahn-See,DEU,DEA51,44799,Bochum,Wasserstr.215 +d000594,Atelier Architecture Perraudin,FRA,FRK26,69001,Lyon,16 rue Imbert Colomès +d000595,Software Imagination & Vision,ROU,RO321,013685,București,"Str. Bucureşti-Ploieşti nr. 73-81, sector 1" +d000596,"Medicina Analit Consumibles Mac, S. A.",ESP,ES213,,Sondika (Bizkaia), +d000597,Sveriges Lantbruksuniversitet,SWE,SE121,750 07,Uppsala,Box 7086 +d000598,Uppsala kommun,SWE,SE121,753 75,Uppsala,Uppsala kommun Kommunledningskontoret +d000599,Union CO,ROU,RO113,400552,Cluj-Napoca,Str. Miron Costin nr. 12A +d000600,Cooperative Eureden,FRA,FR,29206,Landerneau, +d000601,Woonwijzerwinkel,NLD,NL,3089 JA,Rotterdam,Directiekade 2 +d000602,Országos Mentőszolgálat,HUN,HU,1055,Budapest,Markó utca 22. +d000603,Société Easter Eggs,FRA,FRJ13,75014,Paris,44-46 rue de l'Ouest +d000604,Umeå kommun,SWE,SE,901 84,Umeå,Upphandlingsbyrån +d000605,KKS Architektur + Gestaltung,DEU,DED21,01099,Dresden,Louisenstraße 9 +d000606,Cardinal Health Sweden 512 AB,SWE,SE11,113 29,Stockholm,Norrtullsgatan 6 +d000607,ITD solutions SpA,ITA,ITC4C,20124,Milano,via Galileo Galilei 7 +d000608,Serviciul de Telecomunicații Speciale,ROU,RO321,060044,Bucureşti,Str. Independenţei nr. 323A +d000609,OSAGE bv,NLD,NL,,Utrecht, +d000610,evia innovation GmbH,DEU,DE111,70565,Stuttgart,Am Wallgraben 100 +d000611,Barresi Axion boutique,FRA,FRE,62118,Biache-Saint-Vaast,"3 rue pasteur ""Les Usines""" +d000612,Comune di Pachino,ITA,ITG19,96018,Pachino (SR),via XXV Luglio +d000613,Hiscox SA — Hiscox France,FRA,FR101,75002,Paris,38 avenue de l'Opéra +d000614,Swiss Post Solutions GmbH,DEU,DE241,,Bamberg, +d000615,Beschaffungsamt des Bundesministeriums des Innern,DEU,DE,53023,Bonn,Postfach 41 01 55 +d000616,DB Netz AG (Bukr 16),DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 11-13 +d000617,"Clece, S. A.",ESP,ES,28050,Madrid,"Avenida Manoteras, 46 bis" +d000618,Björnsen Beratende Ingenieure GmbH,DEU,DEB1,56070,Koblenz,Maria Trost 3 +d000619,"DZS, založništvo in trgovina, d.d.",SVN,SI,1000,Ljubljana,Dalmatinova ulica 2 +d000620,Stadt Bocholt,DEU,DEA34,46395,Bocholt,Kaiser-Wilhelm-Straße 52-58 +d000621,B & B service sas di Budri Paolo & C sas (capogruppo),ITA,ITC48,27058,Voghera,via Emilio Sturla 35 +d000622,Javno podjetje Energetika Ljubljana d.o.o.,SVN,SI,1000,Ljubljana,Verovškova ulica 62 +d000623,costituendo R.T.I. KPMG advisory SpA — INFO.C.E.R. srl,ITA,ITI4,,Roma, +d000624,Knowlimits s.r.o.,CZE,CZ,155 00,Praha 5,Píškova 1948/16 +d000625,FILANTROPIA ORTODOXA ALBA IULIA FILIALA DANES,ROU,RO125,547200,Danes,"Strada PRINCIPALA, Nr. 92" +d000626,"Tentours turistična agencija, d.o.o., Ljubljanska 85, Domžale",SVN,SI,1230,Domžale,Ljubljanska cesta 85 +d000627,"SKR stav, s.r.o.",CZE,CZ064,614 00,Brno,Nováčkova 233/18 +d000628,"Industrias F. Botella, S. L.",ESP,ES511,,Barcelona, +d000629,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d000630,"Nano Medicina, trgovina d.o.o.",SVN,SI,1260,Ljubljana - Polje,Grajzerjeva ulica 23A +d000631,"Omega svetovanje, inženiring, razvoj in raziskovanje, d.o.o.",SVN,SI,1000,Ljubljana,Dolinškova ulica 8 +d000632,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d000633,Sector 3 (Primăria Sector 3 București),ROU,RO321,031084,Bucureşti,Str. Dudești nr. 191 +d000634,Siemens Financial Services,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d000635,"PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d000636,Vladoor Smart,ROU,RO411,207115,Breasta,Str. Parcului nr. 5A +d000637,Skarb Państwa – Urząd Komunikacji Elektronicznej,POL,PL91,01-211,Warszawa,ul. Giełdowa 7/9 +d000638,HWK Trier,DEU,DEB21,,Trier, +d000639,Coral Impex S.R.L.,ROU,RO316,100510,Ploiești,"Str. Peneș Curcanu nr. 8, bloc 151C, ap. 10" +d000640,Acea SpA,ITA,ITI43,,Roma,p.le Ostiense 2 +d000641,FOCUS TRADING '94 S.R.L.,ROU,RO321,011657,Bucuresti,"Strada Tudor Stefan, Nr. 10, Sector: 1" +d000642,Pop Industry S.R.L.,ROU,RO414,230070,Slatina,"Strada, Nr." +d000643,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d000644,Blackboard,NLD,NL32,Amsterdam,Amsterdam,Paleisstraat 1-5 +d000645,"Land Berlin, Sondervermögen für Daseinsvorsorge und nicht betriebsnotwendige Bestandsgrundstücke des Landes Berlin (SODA)vertreten durch die Berliner Immobilienmanagement GmbH",DEU,DE300,10178,Berlin,Alexanderstraße 3 +d000646,Proxis spol. s r.o.,CZE,CZ010,184 00,Praha 8,Spořická 296/46 +d000647,Bright Finland Oy,FIN,FI1B1,,Vantaa, +d000648,Daser srl,ITA,IT,,Treviso, +d000649,Wasser und Kulturbau Leeegebruch GmbH,DEU,DE40,16767,Leegebruch,Eichenallee 1 +d000650,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000651,Uniha GCS,FRA,FRK26,69003,Lyon,9 rue des Tuiliers +d000652,BOMA nv,BEL,BE,2030,Antwerpen 3,Noorderlaan 131 +d000653,Planon SA,BEL,BE21,2800,Mechelen, +d000654,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d000655,"Urbaser, S. A.",ESP,ES300,,Madrid, +d000656,Wohn- und Pflegeheim Zell am Ziller - Kaiser Franz Josef Stiftung,AUT,AT335,6280,Zell am Ziller,Gerlosstraße 5 +d000657,KARL STORZ ENDOSCOPIA ROMANIA,ROU,RO321,041393,Bucuresti,"Strada Colorian Anton, prof. dr., Nr. 74, Sector: 4" +d000658,SICI srl,ITA,ITH20,,S. Pietro in Cariano (VR), +d000659,Vertex Pharmaceutical Ireland Limited,IRL,IE,D02 EK84,Dublin 2,"28-32, Pembroke Street Upper" +d000660,Dupligrafic SARL,FRA,FR102,77776,Marne-la-Vallée,20 avenue Graham-Bell +d000661,Jacobs U.K. Ltd,GBR,UKI,SE1 2QG,London,"Cottons Centre, Cottons Lane, London, SE1 2QG" +d000662,Vrtec Viški gaj,SVN,SI,1000,Ljubljana,Reška ulica 31 +d000663,Inetum,FRA,FR106,93400,Saint-Ouen,145 boulevard Victor Hugo +d000664,Magirus GmbH,DEU,DE144,89079,Ulm,Graf-Arco-Str. 30 +d000665,Takeda Pharma Sp. z o.o.,POL,PL9,00-838,Warszawa,ul. Prosta 68 +d000666,Communauté agglo. Privas Centre Ardèche,FRA,FRK22,07003,Privas,"1 rue Serre-du-Serret, BP 337" +d000667,NRW.BANK AöR,DEU,DEA11,40213,Düsseldorf,Kavalleriestraße 22 +d000668,"Fresenius Medical care Slovenija, Trgovsko in proizvodno podjetje medicinske opreme d.o.o.",SVN,SI,3000,Celje,Gaji 28 +d000669,Kommunale Immobilien Jena,DEU,DEG03,07743,Jena,Paradiesstraße 6 +d000670,Electrabel NV,BEL,BE100,1000,Bruxelles,Boulevard Simon Bolivar 34 +d000671,Splošna bolnišnica Novo mesto,SVN,SI037,8000,Novo mesto,Šmihelska cesta 1 +d000672,Forstbetrieb Johann Ried,DEU,DE234,92266,Ensdorf, +d000673,3TI Progetti Italia Ingegneria Integrata SpA,ITA,ITI43,00146,Roma,Lungotevere V. Gassman 22 +d000674,Entech Ingénieurs Conseils,FRA,FRJ13,34140,Mèze,Parc scientifique — BP 118 +d000675,Riigikontroll,EST,EE,15013,Tallinn,Kiriku tn 2 +d000676,Ville de Vincennes,FRA,FR107,94300,Vincennes,53 bis rue de Fontenay +d000677,VRTEC POD GRADOM,SVN,SI,1000,Ljubljana,Praprotnikova ulica 2 +d000678,Druckerei Schmerbeck GmbH,DEU,DE227,84184,Tiefenbach,Gutenbergstr. 12 +d000679,Keysight Technologies Deutschland GmbH,DEU,DE,,Böblingen, +d000680,"Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle",DEU,DED41,09111,Chemnitz,Friedensplatz 1 +d000681,Vrtec Viški gaj,SVN,SI,1000,Ljubljana,Reška ulica 31 +d000682,Biming,FRA,FRK26,69007,Lyon,24 rue Jean-Baldassini +d000683,BRIARI'S IND,ROU,RO411,,Carcea,"Strada Calea Bucuresti, Nr. 2" +d000684,Unipolsai assicurazioni SpA,ITA,ITH55,,Bologna, +d000685,Idraulica F.lli Sala,ITA,IT,,Concordia sulla Secchia (MO), +d000686,"EMSOR, S. L.",ESP,ES300,28050,Madrid,"C/ Isabel Colbrand, 10-12, local 138" +d000687,"Medias International, trgovanje in trženje z medicinskim materialom d.o.o.",SVN,SI,1000,Ljubljana,Leskoškova cesta 9D +d000688,Biomedis M.B. trgovina d.o.o.,SVN,SI,2000,Maribor,Jurančičeva ulica 11 +d000689,ERNE AG Bauunternehmung,CHE,CH0,8064,Zürich,Bernerstraße Nord 202 +d000690,Przedsiębiorstwo Handlowo-Usługowe Anmar Sp. z o.o. Sp. k.,POL,PL514,50-502,Wrocław,ul. Hubska 44 +d000691,Eco-Equip SAM,ESP,ES511,08223,Terrassa,"C/ Esla, 34" +d000692,Heinäveden kunta,FIN,FI1D3,,Heinävesi, +d000693,Bravida Norge AS (hovedenhet),NOR,NO081,0596,Oslo,Østre akervei 90 +d000694,Unielektro GmbH,DEU,DEB21,,Trier, +d000695,A la Carte Uniforms OÜ,EST,EE,11313,Tallinn,Töökoja tn 8 +d000696,"O2 Czech Republic, a.s.",CZE,CZ01,140 22,Praha 4 - Michle,Za Brumlovkou 266/260193336 +d000697,Fritsch Knodt Klug + Partner mbH Architekten,DEU,DE254,,Nürnberg, +d000698,Étamine,FRA,FRK26,69120,Vaulx-en-Velin,10 allée des Canuts +d000699,"Gemeente Amsterdam, Personeel en Organisatieadvies",NLD,NL,1102 CW,Amsterdam,Anton de Komplein 150 +d000700,Decutis,FRA,FRI21,19300,Malemort,9001 route de Beynat +d000701,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d000702,Municipiul Cluj-Napoca,ROU,RO113,400001,Cluj-Napoca,Str. Moților nr. 1-3 +d000703,Penta Általános Építőipari Korlátolt Felelősségű Társaság,HUN,HU,2100,Gödöllő,Kenyérgyári út 1/E. +d000704,"DGPW, S. A.",PRT,PT112,4789-180,Gême,"Centro Empresarial de Gême, pavilhão A8" +d000705,4PL Central Station Nordic AB,SWE,SE,211 20,Malmö,Elbegatan 5 +d000706,Kassenzahnärztliche Vereinigung Bayerns,DEU,DE212,81369,München,Fallstraße 34 +d000707,Alcaldía del Ayuntamiento de San Bartolomé de Lanzarote,ESP,ES70,35550,San Bartolomé,"Plaza León y Castillo, 8" +d000708,Amt Parchimer Umland — Der Amtsvorsteher,DEU,DE80O,19370,Parchim,Walter-Hase-Straße 42 +d000709,b. i. g. sicherheit gmbh,DEU,DEE02,06116,Halle Saale,Fiete-Schulze-Str. 15 +d000710,Gemeente Krimpen aan den IJssel,NLD,NL,,Krimpen aan den IJssel, +d000711,Moog GmbH.,DEU,DE1,88693,Deggenhausertal,Im Gewerbegebiet 8 +d000712,Nordic Energy Research,NOR,NO,0170,Oslo,Stensberggata 27 +d000713,Staatl. Bauamt Erlangen-Nürnberg,DEU,DE254,90408,Nürnberg,Bucher Str. 30 +d000714,Siemens Healthcare Sp. z o.o.,POL,PL911,03-821,Warszawa,Żupnicza 11 +d000715,AE Dozoring,SVK,SK010,,,Str. Somolického nr. 1/B +d000716,Autoridade Nacional de Segurança Rodoviária,PRT,PT,2734-507,Barcarena,"Avenida de Casal de Cabanas, Parque de Ciências e Tecnologia de Oeiras" +d000717,"Z+M Logistics, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Gorkého 621/26, Moravská Ostrava" +d000718,Kone,FRA,FRL0,06200,Nice,455 promenade des Anglais +d000719,"Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.",SVN,SI,2000,Maribor,Zagrebška cesta 22 +d000720,Consorzio Innova società cooperativa,ITA,ITH55,40128,Bologna,via Giovanni Papini 18 +d000721,Castrén Engine Osakeyhtiö,FIN,FI1B1,,Helsinki, +d000722,AVID,GBR,UK,EC3R 8HL,London,20 St Dunstans Hill +d000723,de Rolf groep bv,NLD,NL,4051 CV,Ochten,Mercuriusweg 14 +d000724,Service départemental d'incendie et de secours de Seine-et-Marne,FRA,FR102,77001,Melun Cedex,"56 avenue de Corbeil, BP 70109" +d000725,"Nemocnica s poliklinikou Dunajská Streda, a.s.",SVK,SK021,929 01,Dunajská Streda,Veľkoblahovská 23 +d000726,Fehlings Weiß Gleistechnik und Entsorgung GmbH,DEU,DE300,12437,Berlin,Palisadenstraße 40 +d000727,Põllumajandusuuringute Keskus,EST,EE,75501,Saku vald,Teaduse tn 4 +d000728,Vermögen und Bau Baden-Württemberg Amt Mannheim und Heidelberg Dienstsitz Mannheim,DEU,DE126,68161,Mannheim,"L 4, 4-6" +d000729,Région Normandie,FRA,FRD11,14035,Caen Cedex,CS 50523 +d000730,SOS Environnement Nettoyage,FRA,FRG04,72700,Rouillon,3 impasse Chanteloup +d000731,Bau- und Liegenschaftsbetrieb NRW Bielefeld,DEU,DEA41,33602,Bielefeld,August- Bebel-Straße 91 +d000732,"Kemofarmacija, veletrgovina za oskrbo zdravstva, d.d.",SVN,SI,1000,Ljubljana,Cesta na Brdo 100 +d000733,Department of Contracts,MLT,MT,FRN-1600,Floriana,Notre Dame Ravelin +d000734,Commune de la Grande-Motte,FRA,FRJ13,34280,La Grande-Motte,place du 1er Octobre 1974 +d000735,"BG Ingénieurs Conseils SAS, le cotraitant",FRA,FR107,94200,Ivry-sur-Sein,"Metro Sud, 1 BD Hippolyte-Marques" +d000736,Arcobaleno Multiservice srl,ITA,ITC4C,20090,Cesano Boscone (MI),via Magellano 4/6 +d000737,Communauté de communes Les Portes Briardes,FRA,FR102,77330,Ozoir-la-Ferrière,43 avenue du Général de Gaulle +d000738,Gemeente Lansingerland,NLD,NL,,Bergschenhoek, +d000739,"Elektrocentar Petek, d.o.o.",HRV,HR,10310,Ivanić Grad,Etanska cesta 8 +d000740,"Roez, s.r.o.",SVK,SK023,934 01,Levice,Tyršova 2354/2 +d000741,MAMMUT Deutschland GmbH & Co.KG,DEU,DE600,,Hamburg, +d000742,Comune di Montefalcone nel Sannio,ITA,ITF22,86033,Montefalcone nel Sannio,vico 1° V. De Fanis +d000743,FSMA,BEL,BE1,1000,Bruxelles,Rue du Congrès 12-14 +d000744,CCI de région Nord-de-France,FRA,FRE1,59031,Lille Cedex,299 boulevard de Leeds +d000745,"Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.",SVN,SI,2000,Maribor,Zagrebška cesta 22 +d000746,Deurganckdoksluis nv,BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d000747,Staatsbetrieb Sächsische Informatik Dienste,DEU,DED2,01445,Radebeul,Dresdner Straße 78 A +d000748,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4 b +d000749,Bundesamt für Seeschifffahrt und Hydrographie,DEU,DE600,20359,Hamburg, +d000750,Občina Rečica ob Savinji,SVN,SI,3332,Rečica ob Savinji,Rečica ob Savinji 55 +d000751,CGI Norge AS,NOR,NO,0605,oslo,Grenseveien 86 +d000752,"Interiéry Riljak, s.r.o.",SVK,SK031,027 41,Oravský Podzámok,33 +d000753,Stadtwerke München GmbH,DEU,DE212,80287,München,Emmy-Noether-Straße 2 +d000754,Vegacom a.s.,CZE,CZ01,142 01,Praha 4–Lhotka,Novodvorská 1010/14 +d000755,DISP Centre-Est Dijon,FRA,FRC11,21033,Dijon Cedex,"72 A rue d'Auxonne, BP 13331" +d000756,Forsvarsministeriets Ejendomsstyrelse,DNK,DK,9800,Hjørring,Arsenalvej 55 +d000757,Kur- und Touristikunternehmen der Stadt Bad Salzungen (kAöR),DEU,DEG0P,36433,Bad Salzungen,Am Flößrasen 1 +d000758,"Cobra Instalaciones y Servicios, S. A.",ESP,ES,28016,Madrid,"C/ Cardenal Marcelo Spinola, 10" +d000759,Mida Soft Business,ROU,RO321,062076,București,Str. Cetatea Histria nr. 7 +d000760,"Nomago, storitve mobilnosti in potovanj, d.o.o.",SVN,SI,1000,Ljubljana,Vošnjakova ulica 3 +d000761,G. Strauß,DEU,DE713,63071,Offenbach,Bieberer Str. 207 +d000762,"Dnevnik, družba medijskih vsebin, d.d.",SVN,SI,1000,Ljubljana,Kopitarjeva ulica 2 +d000763,A G I HK spol. s r.o.,CZE,CZ052,500 03,Hradec Králové,Špitálská 182/3 +d000764,Malermeister Hofmann,DEU,DED51,04288,Leipzig,Liebertwolkwitzer Straße 77 +d000765,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschiz,"Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" +d000766,Fis SA,CHE,CH,1216,Cointrin,"Le Grand-Saconnex, route de l'Aéroport 29-31" +d000767,Prior und Preußner GmbH und Co KG,DEU,DE944,49084,Osnabrück,Dammstr. 16-20 +d000768,Univerza v Mariboru,SVN,SI,2000,Maribor,Slomškov trg 15 +d000769,Medinova zastopstva in trgovina d.o.o.,SVN,SI,1000,Ljubljana,Ukmarjeva ulica 6 +d000770,Giotto water srl,ITA,ITC48,27058,Voghera,via Prati Nuovi +d000771,"Grupo Control Empresa de Seguridad, S. A.",ESP,ES611,04004,Almería,"C/ Soldado Español, 12" +d000772,Subsecretaría de la Consellería de Sanidad y Salud Pública,ESP,ES523,46010,Valencia,"C/ Micer Mascó, 31-33" +d000773,Communauté urbaine Le Creusot — Montceau-les-Mines,FRA,FRC13,71206,Le Creusot Cedex,"château de la Verrerie, BP 90069" +d000774,Domeni d.o.o.,HRV,HR031,51211,Matulji,Frana Supila 11 +d000775,"Kemis kemični izdelki, predelava in odstranjevanje odpadkov d.o.o.",SVN,SI,1360,Vrhnika,Pot na Tojnice 42 +d000776,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000777,Krabu Grupp OÜ,EST,EE,11411,Tallinn,Kivimurru tn 34 +d000778,Generali Italia SpA,ITA,ITH55,,Bologna, +d000779,Idraulica F.lli Sala,ITA,IT,,Concordia sulla Secchia (MO), +d000780,Stadtwerke Eberbach (hier vertreten durch die Stadtverwaltung Eberbach),DEU,DE715,69412,Eberbach,"Stadtbauamt, Leopoldsplatz 1" +d000781,Kanta-Hämeen sairaanhoitopiirin kuntayhtymä,FIN,FI1C2,,Hämeenlinna, +d000782,Weinrich Office GmbH,DEU,DEG01,,Erfurt, +d000783,Città di Lucca — Amministrazione comunale,ITA,ITI12,55100,Lucca,via Santa Giustina 6 +d000784,Västra Götalandsregionen,SWE,SE232,462 80,Vänersborg,Regionens Hus +d000785,Wasserverband Weddel-Lehre,DEU,DE91,38162,Cremlingen,Hauptstr. 2b +d000786,TRPN (Terrassement réseau publics de Normandie),FRA,FRD2,76700,Gainneville,ZA Le Clos des Perdrix Côte des Châtaigniers +d000787,fesa e. V.,DEU,DE13,79098,Freiburg,Gerberau 5a +d000788,Senn AG,CHE,CH0,4665,Oftringen,Bernstraße 9 +d000789,Kristiansand Kommune,NOR,NO,4685,Nodeland,Postboks 4 +d000790,"E 3, Energetika, ekologija, ekonomija, d.o.o.",SVN,SI,5000,Nova Gorica,Erjavčeva ulica 24 +d000791,Bundesagentur für Arbeit Regionales Einkaufszentrum Südwest,DEU,DE,60528,Frankfurt am Main,Saonestr. 2-4 +d000792,Vodafone România,ROU,RO321,020276,București,Str. Barbu Văcărescu nr. 201 +d000793,Communauté d'agglomération du Soissonnais,FRA,FRE21,02880,Cuffies,"Les Terrasses du Mail, 11 avenue François Mitterrand, 0288" +d000794,Commune Meaux,FRA,FR102,77107,Meaux Cedex,place de l'Hôtel de Ville Jacques Chirac — BP 227 +d000795,Ministrstvo za okolje in prostor Direkcija Republike Slovenije za vode,SVN,SI,1000,Ljubljana,Hajdrihova ulica 28C +d000796,Total direct énergie SA,FRA,FRL,75015,Paris,2 bis rue Louis Armand +d000797,"Notes CS, a.s.",CZE,CZ010,149 00,Praha,Türkova 2319 5b +d000798,AEA Architectes,FRA,FRF11,67000,Strasbourg,3a rue du 22 Novembre +d000799,Achats du groupe biens de consommation,CHE,CH0,3000,Berne 65,Hilfikerstr. 3 +d000800,Samifra,FRA,FRC12,58641,Varennes-Vauzelles,le Bengy +d000801,AMO 2T,FRA,FRE23,80440,Boves,8 rue Alphonse Tellier +d000802,Grupa Azoty Zakłady Chemiczne Police S.A.,POL,PL42,72-010,Police,ul. Kuźnicka 1 +d000803,Valeor,FRA,FRL05,83300,Draguignan,109 rue Jean Aicard +d000804,Elektro Esser,DEU,DEG0B,98617,Utendorf,Metzelser Weg 116 +d000805,"Surovina, družba za predelavo odpadkov d.o.o.",SVN,SI,2000,Maribor,Ulica Vita Kraigherja 5 +d000806,Hebyfastigheter AB,SWE,SE121,744 21,Heby,Box 29 +d000807,Leonor Neto Lopes,PRT,PT170,,Lisboa, +d000808,"Martín Casillas, S. L. U.",ESP,ES618,,Sevilla, +d000809,Phœnix pharma,FRA,FR1,,Créteil, +d000810,RAG Rohrleitungs- und Anlagenbau GmbH,DEU,DE949,49716,Meppen,Backemuder Str. 16 +d000811,Renault Retail Group Courbevoie,FRA,FR105,92400,Courbevoie,8 boulevard Georges-Clémenceau +d000812,"Esclapes e Hijos, S. L.",ESP,ES521,03007,Alicante,"Avenida Saturno, s/n" +d000813,BewGe AVS / Helaba / transact,DEU,DE24,95444,Bayreuth,Josephsplatz 8 (c/o AVS GmbH) +d000814,Winkels Servicegesellschaft mbH,DEU,DE300,,Berlin, +d000815,"UTE Otipsa Consultores, S. L. — Viasur, Prevención e Ingeniería, S. A.",ESP,ES,04004,Almería,Rambla Obispo Orberá +d000816,"Ayesa Advanced Technologies, S. A., Alfatec Sistemas, S. L., Unión Temporal de Empresas, Ley 18/1982, de 26 de mayo",ESP,ES62,,Murcia, +d000817,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 — Haus 6 +d000818,Tressol,FRA,FRJ13,34500,Béziers,ZAC de Montimaran +d000819,UAB „Asseco Lietuva“,LTU,LT,,Vilnius, +d000820,Entsorgungsbetriebe Essen GmbH,DEU,DEA13,45141,Essen,Pferdebahnstraße 32 +d000821,Matra S.R.L.,ROU,RO414,235600,Scornicești,Bulevardul Muncii nr. 11 +d000822,"Vojenské lesy a statky ČR, s.p.",CZE,CZ010,160 00,Praha 6,"Pod Juliskou 1621/5, Dejvice" +d000823,RATP,FRA,FR101,75599,Paris Cedex 12,"Lac B916, 54 quai de la Rapée" +d000824,Gemeente Capelle aan den IJssel,NLD,NL,,Capelle aan den IJssel, +d000825,Lindbak AS,NOR,NO082,7038,Trondheim,Nordslettvegen 1 +d000826,S.C. ELMED S.R.L.,ROU,RO114,430111,Baia Mare,"Strada Slavici Ion, Nr. 3" +d000827,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d000828,G Travel Østfold,NOR,NO074,1504,Moss,Pb 802 +d000829,CHU de Montpellier,FRA,FRJ13,34295,Montpellier Cedex 5,191 avenue du Doyen-Gaston-Giraud +d000830,B&W Bautenschutz,DEU,DEA37,48431,Rheine,Windhorststr. 2B +d000831,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d000832,Service départemental métropolitain d'incendie de secours,FRA,FRK26,69421,Lyon Cedex 03,17 rue Rabelais +d000833,hectas Facility Services Stiftung & Co. KG,DEU,DE300,,Berlin, +d000834,"Statutární město Brno, městská část Brno–Líšeň",CZE,CZ064,628 00,Brno,Jírova 2 +d000835,OPCO atlas,FRA,FR101,75013,Paris,25 quai Panhard et Levassor +d000836,Wirtschaftsbetriebe Duisburg AöR,DEU,DEA12,47059,Duisburg,Schifferstr. 190 +d000837,Fakultní nemocnice Plzeň,CZE,CZ032,305 99,Plzeň,Edvarda Beneše 1128/13 +d000838,"ITMA, S. L. U.",ESP,ES,33428,Llanera,"C/ B, parcela 60, nave 5, polígono Asipo" +d000839,Scottish Water,GBR,UKM,G33 6FB,Glasgow,6 Buchanan Gate +d000840,Ville de Nantes,FRA,FRG01,,Nantes, +d000841,IKK classic.de,DEU,DE,01099,Dresden, +d000842,UAB „Goodpoint“,LTU,LT,LT-46326,Kaunas,Saulėgrąžų g. 26 +d000843,Stockholm Innovation & Growth AB,SWE,SE110,,Stockholm, +d000844,"Stadt Mönchengladbach, Dezernat Planen, Bauen, Mobilität, Umwelt - VI/V - Vergabestelle -",DEU,DEA15,41236,Mönchengladbach,Markt 11 +d000845,Spitalul Municipal Câmpulung Muscel,ROU,RO311,115100,Câmpulung,Str. Dr. Costea nr. 8 +d000846,Absobo studio SAS,FRA,FRI12,33074,Bordeaux,23 parvis des Chartrons +d000847,Aktsiaselts Pinus,EST,EE,10618,Tallinn,Paldiski mnt 107 +d000848,Medika d.d.,HRV,HR050,10000,Zagreb,Capraška 1 +d000849,Brandenburgischer Landesbetrieb für Liegenschaften und Bauen (BLB) — Zentrale Vergabestelle,DEU,DE40H,15806,Zossen,An der Wache 2 +d000850,Cetim,FRA,FR,60304,Senlis Cedex,"52 avenue Félix Louat, BP 80067" +d000851,Krakowski Szpital Specjalistyczny im. Jana Pawła II,POL,PL213,31-202,Kraków,ul. Prądnicka 80 +d000852,ISL ingénierie,FRA,FRJ13,34170,Castelnau-le-Lez,65 avenue Clément Ader +d000853,Klinikum Hochsauerland GmbH,DEU,DEA57,59755,Arnsberg,"Goethestraße 15, 59755 Arnsberg" +d000854,Verdo Teknik A/S,DNK,DK032,25481992,Randers NV,Agerskellet 7 +d000855,NFP Nemzeti Fejlesztési Programiroda Nonprofit Korlátolt Felelősségű Társaság,HUN,HU,1139,Budapest,Pap Károly utca 4–6. +d000856,Bio Technic România S.R.L.,ROU,RO321,060015,București,"Str. Plevnei nr. 196, sector 6" +d000857,Miasto Bielsko-Biała Urząd Miejski w Bielsku-Białej,POL,PL225,43-300,Bielsko-Biała,pl. Ratuszowy 9 +d000858,AEP Estrich GmbH,DEU,DE1,74369,Löchgau,Friederike-Franck-Straße 12 +d000859,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000860,Enel Italia SpA in nome e per conto di e-distribuzione SpA,ITA,ITI43,00198,Roma (RM),viale Regina Margherita 125 +d000861,OMV Petrom Marketing,ROU,RO321,013329,București,"Str. Coralilor nr. 22, sector 1" +d000862,Conduent Business Solutions AG,CHE,CH,,Bern, +d000863,Občina Mozirje,SVN,SI,3330,Mozirje,Šmihelska cesta 2 +d000864,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d000865,Sodexo AB,SWE,SE,169 03,Solna,Dalvägen 22 +d000866,Vestra Industry S.R.L.,ROU,RO212,,Cătămărești-Deal,Str. Mihai Eminescu nr. 85 +d000867,"Bilbao Exhibition Centre, S. A.",ESP,ES213,,Bilbao, +d000868,GEAPRODUKT trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d000869,Domanys,FRA,FRC14,89000,Auxerre,9 rue de Douaumont +d000870,Energotech S.A.,ROU,RO321,061334,București,"Str. Timișoara nr. 104 B, sector 6" +d000871,"ACOLAV, podjetje za storitve, d.o.o.",SVN,SI,1241,Kamnik,Prešernova ulica 4 +d000872,Atelier du Val de Sambre,FRA,FRE11,59600,Maubeuge,251 rue du Pont de Pierres +d000873,Kemijski inštitut,SVN,SI,1000,Ljubljana,Hajdrihova ulica 19 +d000874,"Slovak Telekom, a.s.",SVK,SK01,817 62,Bratislava,Bajkalská 28 +d000875,BTL ROMANIA APARATURA MEDICALA S.R.L.,ROU,RO321,040184,Bucuresti,"Strada CPT MIRCEA VASILESCU, Nr. 12-14, Sector: 4" +d000876,Drum Asfalt,ROU,RO111,410270,Oradea,Șoseaua Borșului nr. 14/A +d000877,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d000878,VĮ Lietuvos automobilių kelių direkcija,LTU,LT,LT-03109,Vilnius,J. Basanavičiaus g. 36 +d000879,Nohl Eisennach GmbH,DEU,DEG0N,99817,Eisenach,An der Feuerwache 4 +d000880,"AKR1, s.r.o.",CZE,CZ01,140 00,Praha 4 - Nusle,Svatoslavova 589/9 +d000881,Valstybės sienos apsaugos tarnyba prie Lietuvos Respublikos vidaus reikalų ministerijos,LTU,LT,LT-03116,Vilnius,Savanorių pr. 2 +d000882,Greenfish,BEL,BE100,1050,Ixelles,Avenue Louise 279 +d000883,SEMAB,FRA,FRI11,,Bergerac, +d000884,"Anmedic, družba za trgovino s profesionalno medicinsko opremo in pripomočki, d.o.o.",SVN,SI,1000,Ljubljana,Šmartinska cesta 53 +d000885,GE Healthcare,FRA,FR,78457,Vélizy Cedex,24 avenue de l'Europe +d000886,"Stadt Mönchengladbach, Dezernat Planen, Bauen, Mobilität, Umwelt – VI/V – Vergabestelle",DEU,DEA15,41236,Mönchengladbach,Markt 11 +d000887,WSA Weser- Jade- Nordsee; Technische Fachstelle Nordawest,DEU,DE94G,26919,Brake,Hinrich-Schnitger- Straße 20 +d000888,Rupert App GmbH & Co.,DEU,DE148,88299,Leutkirch,Unterzeiler Weg 3 +d000889,Deutsches Zentrum für Luft- und Raumfahrt e. V. (DLR),DEU,DEA23,51147,Köln,Linder Höhe +d000890,kreuger wilkins architekten gbr,DEU,DE111,,Stuttgart, +d000891,CAE STS LTD,GBR,UKJ28,,Burgess Hill, +d000892,(Uczestnik) Tramco Spółka z o.o. Wolskie,POL,PL,05-860,Płochocin,ul. Wolska 14 +d000893,"Mollier, inženiring, storitve, proizvodnja, trgovina d.o.o.",SVN,SI,3000,Celje,Opekarniška cesta 3 +d000894,Chambre de Métiers et de l'Artisanat des Hauts-de-France,FRA,FRE,59011,Lille Cedex,place des Artisans — CS 12010 +d000895,"Intersurgical España, S. L.",ESP,ES30,,Móstoles, +d000896,Kristiansand kommune,NOR,NO,4685,Nodeland,Postboks 4 +d000897,Anticimex Aktiebolag,SWE,SE232,100 74,Stockholm,Box 47025 +d000898,Derichebourg SNG Mandataire,FRA,FRK26,69310,Pierre-Benite,84 boulevard de l'Europe +d000899,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d000900,KLS spol. s.r.o.,SVK,SK031,010 01,Žilina,Martina Rázusa 9 +d000901,"ČEZ Distribuce, a.s.",CZE,CZ042,,Děčín IV-Podmokly, +d000902,RER VEST,ROU,RO111,410270,Oradea,"Strada Vladimirescu Tudor, Nr. 79" +d000903,IFOK GmbH,DEU,DE715,64625,Bensheim,Berliner Ring 89 +d000904,CC Pharma GmbH,DEU,DE,,Densborn, +d000905,"Vygon, S. A. U.",ESP,ES523,,Paterna, +d000906,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d000907,Stadtverwaltung Balingen,DEU,DE143,72336,Balingen,Neue Straße 31 +d000908,VšĮ Klaipėdos universitetinė ligoninė,LTU,LT,LT-92288,Klaipėda,Liepojos g. 41 +d000909,FOCUS TRADING '94 S.R.L.,ROU,RO321,011657,Bucuresti,"Strada Tudor Stefan, Nr. 10, Sector: 1" +d000910,Ríkiskaup,ISL,IS,IS-105,Reykjavik,Borgartun 7c +d000911,Energimyndigheten,SWE,SE122,631 04,Eskilstuna,Box 310 +d000912,Inspectoratul General al Poliţiei Române,ROU,RO321,050041,Bucureşti,Str. Mihai Vodă nr. 6 +d000913,Marinko Zubčić- pripremni radovi na gradilištu,HRV,HR,23241,Poličnik,Murvica IK 7a +d000914,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d000915,Roudenn Grafik,FRA,FRH01,22194,Plérin, +d000916,Consejería de Desarrollo Autonómico,ESP,ES230,26071,Logroño,"Avenida Zaragoza, 21" +d000917,Engie,FRA,FRK26,69246,Lyon,127 avenue Barthélémy Buyer +d000918,ExperTeach Gesellschaft für Netzwerkkompetenz mbH,DEU,DE71C,63128,Dietzenbach,Waldstraße 94 +d000919,PLG Paris Île-de-France,FRA,FR103,95140,Garges-lès-Gonesse,29 avenue des Morillons +d000920,HTM,FRA,FRI15,64210,Bidart,56 allée Antoine d'Abbadie Bâtiment Enerpole +d000921,Fresenius Kabi Polska Sp. z o.o.,POL,PL,02-305,Warszawa,Al. Jerozolimskie 134 +d000922,"Mundiaudit, S. L.",ESP,ES,,Las Palmas de Gran Canaria,"C/ Goya, 7" +d000923,Land Schleswig-Holstein endvertreten durch Gebäudemanagement Schleswig-Holstein AöR,DEU,DEF03,23566,Lübeck,Schillstraße 1-3 +d000924,blankService Torsten Werner,DEU,DE300,13088,Berlin,Meyerbeerstraße 58 +d000925,ARGE Kutter Hts Bauunternehmung GmbH/Ludwig Pfeiffer Hoch- und Tiefbau GmbH & Co. KG,DEU,DEE0A,06311,Helbra, +d000926,MOGA družba za urejanje okolja d.o.o.,SVN,SI,2000,Maribor,Zemljičeva ulica 21 +d000927,Quadrat Études,FRA,FR101,75012,Paris,45 rue de Lyon +d000928,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d000929,Spirale Print,FRA,FR101,75017,Paris,2-4 rue Baye +d000930,Inspyr énergies environnement,FRA,FRI15,64000,Pau,2 avenue Pierre Angot +d000931,Tinmar Energy S.A.,ROU,RO321,014476,București,Str. Floreasca nr. 246C +d000932,Ministry for the Environment Climate Change and Planning — MPU,MLT,MT,SVR 1301,Santa Venera,"Permanent Secretariat Offices, 6 Qormi Road" +d000933,"Žale Javno podjetje, d.o.o.",SVN,SI,1000,Ljubljana,Med hmeljniki 2 +d000934,Banskobystrický samosprávny kraj,SVK,SK032,974 01,Banská Bystrica,Nám. SNP 23 +d000935,"Aema Hispánica, S. L.",ESP,ES300,28036,Madrid,"C/ Santiago Bernabéu, 4, 4" +d000936,ANDYTEH CONCEPT S.R.L.,ROU,RO321,031126,Bucuresti,"Strada Negoiu, Nr. 6" +d000937,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d000938,"Landkreis München, vertreten durch die Münchner Verkehrs- und Tarifverbund GmbH",DEU,DE21H,80538,München,Thierschstr. 2 +d000939,"Icartare, S. L.",ESP,ES618,,Sevilla, +d000940,Arthrex Adria d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 269 G +d000941,Zaloker & Zaloker trgovinska in proizvodna d.o.o.,SVN,SI,1000,Ljubljana,Kajuhova ulica 9 +d000942,Krankenhaus Düren gGmbH,DEU,DEA26,52351,Düren,Roonstraße 30 +d000943,Stadtwerke Eberbach (hier vertreten durch die Stadtverwaltung Eberbach),DEU,DE715,69412,Eberbach,"Stadtbauamt, Leopoldsplatz 1" +d000944,Bock GmbH,DEU,DEG0F,,Ilmenau, +d000945,"Xanadu, s.r.o.",CZE,CZ01,106 00,Záběhlice Praha 10,Žirovnická 2389/1a +d000946,AMJ Turku Audio Oy,FIN,FI1C1,,Lieto, +d000947,Vrtec Ptuj,SVN,SI,2250,Ptuj,Puhova ulica 6 +d000948,Markt Berchtesgaden,DEU,DE215,83471,Berchtesgaden,Rathausplatz 1 +d000949,Miasto Stołeczne Warszawa Dzielnica Mokotów,POL,PL911,02-517,Warszawa,ul. Rakowiecka 25/27 +d000950,Bauelemente Herbst GmbH,DEU,DE7,63628,Bad Soden Salmünster,Am Palmusacker 2 +d000951,BCH Compresseurs,FRA,FRK27,73800,Porte-de-Savoie,422 rue de la Jacquère +d000952,Weatherford Atlas GIP S.A.,ROU,RO,100189,Ploiești,Str. Clopoței nr. 2A +d000953,SANTIS Training AG,CHE,CH0,8048,Zürich,Hohlstrasse 550 +d000954,SWCO Polska Sp. z o.o.,POL,PL415,60-829,Poznań,ul. Franklina Roosevelta 22 +d000955,Spitalul Clinic de Boli Infecțioase și Pneumoftiziologie „Dr. Victor Babeș” Timișoara,ROU,RO424,300310,Timișoara,Str. Adam Gheorghe nr. 13 +d000956,"Fraunhofer-Gesellschaft, Einkauf und Gerätewirtschaft C2",DEU,DE212,80686,München,Hansastraße 28 +d000957,Codema International GmbH,DEU,DE713,63065,Offenbach am Main,Frankfurter Straße 1 +d000958,"Confeções São Gregório, Lda.",PRT,PT111,,Cristelo (Pias),Monção +d000959,"Monitorización y Medidas, S. L.",ESP,ES300,28223,Pozuelo de Alarcón,"C/ Virgilio, 25" +d000960,Duktus (Wetzlar) GmbH & Co. KG,DEU,DE722,35576,Wetzlar,Sophienstraße 52-54 +d000961,Atelier 5,FRA,FRL01,83000,Toulon,5 rue Gozza +d000962,Alenium consultants,FRA,FR1,,Paris, +d000963,"Timed, s.r.o.",SVK,SK01,821 01,Bratislava,Trnavská cesta 112 +d000964,Tuomi Logistiikka Oy,FIN,FI,FI-33840,Tampere,Särkijärvenkatu 1 +d000965,Maandag Interim Professionals bv,NLD,NL,,Rotterdam, +d000966,Stadt Neumarkt in der Oberpfalz,DEU,DE236,92318,Neumarkt in der Oberpfalz,Rathausplatz 1 +d000967,Anton Gerl GmbH,DEU,DEA2,50996,Köln,"131, Industriestrasse" +d000968,MIPS Deutschland GmbH & Co. KG,DEU,DE71D,65343,Eltville,Im Kappelhof 1 +d000969,Burnickl Ingenieur GmbH,DEU,DE23,92355,Velburg, +d000970,Nemocnice AGEL Jeseník a.s.,CZE,CZ071,790 01,Jeseník,Lipovská 103/39 +d000971,Svenska Inredningsfabrikanters Försäljnings Aktiebolag,SWE,SE232,411 25,Göteborg,Viktoriagatan 24 +d000972,Ministerstvo spravedlnosti České republiky,CZE,CZ010,128 10,Praha 2,Vyšehradská 16 +d000973,Vermögen und Bau Baden-Württemberg Amt Ludwigsburg,DEU,DE115,71638,Ludwigsburg,Karlsplatz 5 +d000974,Gegenbauer Services GmbH,DEU,DE300,,Berlin, +d000975,"Stadt Halle (Saale), Fachbereich Recht, Team Vergabe Bauleistungen/Bauplanungen",DEU,DEE02,06108,Halle (Saale),Marktplatz 1 +d000976,Landgesellschaft Mecklenburg-Vorpommern mbH,DEU,DE80O,19067,Leezen,Lindenallee 2a +d000977,Stadt Salzgitter,DEU,DE912,38226,Salzgitter,Joachim-Campe-Straße 6-8 +d000978,"Mylan Healthcare GmbH (A Viatris company), Zweigniederlassung Bad Homburg",DEU,DE71,61352,Bad Homburg,Benzstraße 1 +d000979,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d000980,Atlas Sport,ROU,RO125,540256,Târgu Mureş,Str. Voinicenilor nr. 62 +d000981,Kreis Steinfurt,DEU,DEA37,48565,Steinfurt,Tecklenburger Str. 10 +d000982,DEMGRO nv,BEL,BE,8800,Roeselare,Zwaaikomstraat 12 +d000983,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000984,"Medias International, trgovanje in trženje z medicinskim materialom d.o.o.",SVN,SI,1000,Ljubljana,Leskoškova cesta 9D +d000985,Institut klinické a experimentální medicíny,CZE,CZ010,140 00,Praha,Vídeňská 1958/9 +d000986,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d000987,Väylävirasto,FIN,FI,FI-00521,Helsinki,PL 33 (Opastinsilta 12 A) +d000988,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000989,Orano nuclear packages and services (mandataria),FRA,FR,,Montigny-le-Bretonneux, +d000990,Università degli studi di Milano — Bicocca,ITA,ITC4C,20126,Milano,piazza dell'Ateneo Nuovo 1 +d000991,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d000992,Consejo Rector del Instituto de Atención Social y Sociosanitaria del Cabildo Insular de Gran Canaria,ESP,ES70,35003,Las Palmas de Gran Canaria,"C/ Tomas Morales, 3" +d000993,"Universitäts- und Hansestadt Greifswald, Der Oberbürgermeister, Stadtbauamt, Abt. Bauverwaltung",DEU,DE80N,17489,Greifswald,Markt 15 +d000994,Universitätsklinikum Jena,DEU,DEG03,07747,Jena,Paul-Schneider-Straße 2 +d000995,"Liberecká obalovna, s.r.o.",CZE,CZ051,460 01,Liberec,Hrádecká 247 +d000996,ebök GmbH,DEU,DE14,72072,Tübingen,Schellingstraße 4/2 +d000997,Pac-Production Sweden AB,SWE,SE124,701 48,Örebro,Box 409 +d000998,Krogmann Ing. Holzbau GmbH,DEU,DE94F,49393,Lohne,Kroger Pickerweg 142 +d000999,Gemeindeverwaltung Floh-Seligenthal,DEU,DEG0B,98593,Floh-Seligenthal,Bahnhofstraße 4 +d001000,FOCUS TRADING '94 S.R.L.,ROU,RO321,011657,Bucuresti,"Strada Tudor Stefan, Nr. 10, Sector: 1" +d001001,"Abbott Rapid Diagnostics Healthcare, S. L.",ESP,ES511,,L'hospitalet de Llobregat (Barcelona), +d001002,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d001003,Société concessionnaire française pour la construction et l'exploitation du tunnel routier sous le Mont-Blanc (ATMB),FRA,FRK28,74130,Bonneville,1440 route de Cluses +d001004,RWTH Aachen University Dezernat 10.0,DEU,DEA2D,52072,Aachen,Süsterfeldstr 65 +d001005,DB Fahrzeuginstandhaltung GmbH (Bukr 49),DEU,DE30,60326,Frankfurt am Main,Weilburger Straße 22 +d001006,Conrad Innenausbau GmbH,DEU,DEE0C,06406,Bernburg, +d001007,Pro tech foudre,FRA,FRI11,24400,Saint-Michel-de-Double, +d001008,Tischlerei Loch e. K.,DEU,DEG0G,99444,Blankenhain, +d001009,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d001010,SoGeNuS SpA,ITA,ITI32,,Maiolati Spontini,via Cornacchia 12 +d001011,SDIS 24,FRA,FRI11,24009,Périgueux,CS 91002 +d001012,Stadt Lüdinghausen,DEU,DEA35,59348,Lüdinghausen,Borg 2 +d001013,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001014,MÁV-START Vasúti Személyszállító Zrt.,HUN,HU110,1087,Budapest,Könyves Kálmán körút 54–60. +d001015,"Open Source and Security Services, S. L.",ESP,ES511,08018,Barcelona, +d001016,"Emirates Plastic Industries Hispania, S. L.",ESP,ES300,,Madrid, +d001017,"Azpiegiturak, S. A. M. P.",ESP,ES213,,Bilbao,"C/ Islas Canarias, 21, 2.º, 48015 Bilbao (Bizkaia)" +d001018,Solutions 30 EUR energy,FRA,FR1,93200,Saint-Denis,39-42 boulevard d'Ormano +d001019,Holl Flachdachbau GmbH,DEU,DEE02,06112,Halle (Saale), +d001020,"Geosan Group, a.s.",CZE,CZ,280 02,Kolín,U Nemocnice 430 +d001021,"Freistaat Bayern, vertreten durch das Bayerische Staatsministerium der Justiz, federführend handelnd in Gesellschaft nach bürgerlichem Recht, zu der sich die am Projekt beteiligten Länder zusammengeschlossen haben",DEU,DE2,80335,München,Prielmayerstraße 7 +d001022,NTT Poland sp. z o.o.,POL,PL,,Warszawa, +d001023,Afry Finland Oy,FIN,FI,FI-01620,Vantaa,Jaakonkatu 3 +d001024,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d001025,Gemeente Krimpenerwaard,NLD,NL,,Stolwijk, +d001026,Lieksan seurakunta,FIN,FI1D3,,Lieksa, +d001027,melchior + wittpohl Ingenieurgesellschaft GbR,DEU,DE600,,Hamburg, +d001028,PKE Electronics GmbH,AUT,AT,4030,Linz,Emil-Rathenau Straße 3 +d001029,Fa. Schlingmann GmbH & Co. KG,DEU,DE94E,49201,Dissen, +d001030,Ružinovský domov seniorov,SVK,SK010,821 09,Bratislava-Ružinov,Sklenárova 14 +d001031,Haemato Pharm GmbH,DEU,DE,,Schönefeld, +d001032,Gemeente Barendrecht,NLD,NL,,Barendrecht, +d001033,Direcția Generală de Asistență Socială și Protecția Copilului Olt,ROU,RO414,230119,Slatina,Str. Drăgănești nr. 7 +d001034,Consorzio Progetto Multiservizi,ITA,ITI43,,Roma, +d001035,Botte Fondations,FRA,FR107,94550,Chevilly-Larue,"5 rue Ernest Flammarion, ZAC du Petit Leroy" +d001036,Qualiterre,FRA,FRD1,61100,Flers,rue Ferdinand Lucas +d001037,Judetul Mureș,ROU,RO125,540026,Târgu Mureș,Piața Victoriei nr. 1 +d001038,Javno podjetje Vodovod Kanalizacija Snaga d.o.o.,SVN,SI,1000,Ljubljana,Vodovodna cesta 90 +d001039,Mairie de la Ciotat,FRA,FRL04,13600,La Ciotat,hotel de ville Rond-Point des Messageries Maritimes +d001040,Mülheimer Seniorendienste GmbH,DEU,DEA16,45475,Mülheim an der Ruhr,Auf dem Bruch 70 +d001041,Instalaciones y Mantenimientos Imafer,ESP,ES111,,Narón,"Polígono industrial Río Pozo, c/ Vidrieros, parcela W-2" +d001042,Thomas Keble School,GBR,UKK13,GL6 7DY,Gloucestershire,"Eastcombe, Stroud" +d001043,MANUS ANTWERPEN Vzw,BEL,BE,2018,Antwerpen 1,Mechelsesteenweg 128-136 +d001044,Ville de Choisy-le-Roi,FRA,FR107,94607,Choisy-le-Roi,place Gabriel Péri +d001045,WSH Wurzinger Klimatechnik GmbH,DEU,DE251,91625,Schnelldorf-Hilpertsweiler,Nikolaus-Otto-Str. 5 +d001046,Bacs et jardins,FRA,FRY10,97118,Saint-François,"route des Maraîchers, Dubedou" +d001047,Leibniz-Institut für Troposphärenforschung e.V.,DEU,DED,04318,Leipzig,Permoserstrasse 15 +d001048,Vertex Pharmaceutical Ireland Limited,IRL,IE,D02 EK84,Dublin 2,"28-32, Pembroke Street Upper" +d001049,"Technische Universität Ilmenau, Dezernat Finanzen, SG Beschaffung",DEU,DEG0F,98693,Ilmenau,Max-Planck-Ring 14 +d001050,"Coprapec — Cooperativa Agrícola de Compra e Venda de Montemor-o-Novo, C. R. L.",PRT,PT,7050-355,Montemor-o-Novo,"Rua 5 de Outubro, 76" +d001051,Hoch- und Tiefbau Dresden GmbH & Co. KG,DEU,DED2,01257,Dresden,Sachsenwerkstraße 31 +d001052,Computacenter AG & Co. oHG,DEU,DE3,12099,Berlin,Mariendorfer Damm 1 +d001053,Road Maintenance Services Ltd,MLT,MT,ZTN 2475,Zejtun [Iż-Żejtun Ċittà Beland],RMS Triq F Ghio +d001054,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d001055,"Krajská zdravotní, a.s.",CZE,CZ042,401 13,Ústí nad Labem,Sociální péče 3316/12A +d001056,Test Trading S.R.L.,ROU,RO321,020296,București,Str. Gheorghe Ţiţeica nr. 171 +d001057,Fankhauser Estriche GmbH,AUT,AT,,Kramsach, +d001058,ANDYTEH CONCEPT S.R.L.,ROU,RO321,031126,Bucuresti,"Strada Negoiu, Nr. 6" +d001059,NGT costruzioni srl,ITA,ITF46,,Foggia, +d001060,Østfold Fylkeskommune,NOR,NO082,1706,Sarpsborg,Oscar Pedersens vei 39 +d001061,Ginger CEBTP,FRA,FR,78990,Élancourt,12 avenue Gay Lussac — ZAC La Clef Saint-Pierre +d001062,Pielaveden kunta,FIN,FI1D2,,Pielavesi, +d001063,Métropole de Lyon,FRA,FRK26,69505,Lyon,20 rue du Lac — CS 33569 +d001064,Kyu Lab,FRA,FR101,75008,Paris,136 boulevard Haussmann +d001065,PreZero Service Centrum Sp. z o.o.,POL,PL712,99-300,Kutno,ul. Łąkoszyńska 127 +d001066,AXA assicurazioni SpA,ITA,ITC4C,,MILANO, +d001067,Kone GmbH,DEU,DE92,30179,Hannover,Vahrenwalder Straße 317 +d001068,"Labormed podjetje za trgovino, projektiranje in svetovanje d.o.o., Ljubljana",SVN,SI,1000,Ljubljana,Peričeva ulica 29 +d001069,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d001070,Bayer s.r.o.,CZE,CZ01,155 00,Praha 5,Siemensova 2717/4 +d001071,Vodovod Novska d.o.o.,HRV,HR028,44330,Novska,Adalberta Knoppa 1a +d001072,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d001073,"Z + M Partner, spol. s r.o.",CZE,CZ080,702 00,Ostrava,Valchařská 3261/17 +d001074,Medeq OÜ,EST,EE,10135,Tallinn,Veerenni tn 24 +d001075,Abacus Medicine A/S,DNK,DK,,Kopenhagen, +d001076,Avfall Sør AS,NOR,NO092,,Kristiansand S, +d001077,bahl & bahl architektur,DEU,DE248,91301,Forchheim,Wiesentstr. 37a +d001078,Hölig Metallbau GmbH & Co. KG,DEU,DED2E,01665,Diera-Zehren,Riesaer Straße 1 a +d001079,Maxigel S.R.L.,ROU,RO316,100070,Ploiești,Str. Laboratorului nr. 29B +d001080,Die Autobahn GmbH des Bundes – Niederlassung Südbayern,DEU,DE212,80335,München,Seidlstr. 7-11 +d001081,Collectivité de Corse,FRA,FRM,20187,Ajaccio,"direction de la commande publique, hôtel de la collectivité de Corse, 22 cours Grandval" +d001082,Siemens AG Building Technologies,DEU,DEE0,01139,Dresden,Washingtonstr. 16/16 A +d001083,APAJH ESAT en Roudil,FRA,FRJ27,81500,Lavaur,1 chemin en Roudil +d001084,Espoon kaupunki,FIN,FI1B1,FI-02070,Espoo,PL 640 +d001085,Institut des ursulines ASBL,BEL,BE100,1081,Koekelberg,Rue Jules Debecker 71 +d001086,Santa Casa da Misericórdia de Lisboa,PRT,PTZZZ,1250-264,Lisboa,"Rua das Taipas, 1" +d001087,Arker Stúdió Építészeti és Kereskedelmi Kft.,HUN,HU232,7400,Kaposvár,Dózsa György utca 21. 433 +d001088,"Thomy F.E., medicinska zastopstva, trgovina, marketing in posredovanje, d.o.o.",SVN,SI,1236,Trzin,Brodišče 24 +d001089,Adamas — affaires publiques,FRA,FRK26,69438,Lyon,55 boulevard des Brotteaux +d001090,"Consejería de Agricultura, Ganadería, Pesca y Desarrollo Sostenible",ESP,ES61,41071,Sevilla,"C/ Tabladilla, s/n" +d001091,Commune de Rillieux-la-Pape,FRA,FRK26,69140,Rillieux-la-Pape,165 rue Ampère +d001092,Allen & Overy LLP,GBR,UKI,000000,Londres,"One Bishops Square, E1 6ad" +d001093,Impel Facility Services Sp. z o.o.,POL,PL514,53-111,Wrocław,Ślężna 118 +d001094,"Ebone Servicios Educación Deporte, S. L.",ESP,ES,18100,Andalucía,"Avenida Fernando de los Ríos, 11, portal 1, oficina 4" +d001095,FILANTROPIA ORTODOXA ALBA IULIA FILIALA DANES,ROU,RO125,547200,Danes,"Strada PRINCIPALA, Nr. 92" +d001096,PSA Retail la Défense,FRA,FR105,92250,La Garenne-Colombes,9 Boulevard national +d001097,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d001098,"PKE Deutschland GmbH, NL Leipzig",DEU,DED53,04435,Schkeuditz,Edisonstraße 44 +d001099,"ITMA,S.L.U.",ESP,ES,33428,Llanera,"Polígono ASIPO, Calle B, parcela 60, nave 5" +d001100,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d001101,Sennebogen Maschinenfabrik GmbH,DEU,DE223,94315,Straubing,Sennebogenstraße 10 +d001102,OSNOVNA ŠOLA VERŽEJ,SVN,SI,9241,Veržej,Puščenjakova ulica 7 +d001103,SAXHO Guest Supplies GmbH,DEU,DED2,01067,DD,Hamburger Str.31 +d001104,Bellesini società cooperativa sociale,ITA,ITH20,,Trento,via Degasperi 32/1 +d001105,SADA AG,CHE,CH0,8152,Glattpark,Vega-Straße 3 +d001106,Abrechnungszentrum Emmendingen,DEU,DE133,79312,Emmendingen,An der B3 Haus Nr. 6 +d001107,A1 Hrvatska d.o.o.,HRV,HR050,10000,Zagreb,Vrtni put 1 +d001108,Retravailler EGP,FRA,FR101,75020,Paris,23 rue Olivier Métra +d001109,"THT Polička, s.r.o.",CZE,CZ053,572 01,Polička,Starohradská 316 +d001110,"Liegenschaftsfonds Berlin Projektgesellschaft mbH & Co.KG, vertreten durch die Berliner Immobilienmanagement GmbH",DEU,DE300,10178,Berlin,Alexanderstraße 3 +d001111,Institut Cartogràfic i Geològic de Catalunya,ESP,ES511,08038,Barcelona,"Parc de Montjuic, s/n" +d001112,"Bezirksamt Pankow von Berlin, Abt. SchulSportFMG, SE FM, Fachbereich Hochbau",DEU,DE300,10407,Berlin,Storkower Straße 113 +d001113,Ministerstvo obrany,CZE,CZ,160 00,Praha,Tychonova 221/1 +d001114,"RJ Autocares, S. L.",ESP,ES3,28906,Getafe,"C/ Solidaridad, 6" +d001115,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d001116,Storstockholms brandförsvar,SWE,SE110,111 83,Stockholm,Box 1328 +d001117,Stephanix,FRA,FR,42150,La Ricamarie,12 rue Jean Moulin +d001118,"Deutsche Bundesbank, Beschaffungszentrum",DEU,DE712,60329,Frankfurt am Main,Taunusanlage 5 +d001119,Università degli studi dell'Insubria,ITA,ITC41,21100,Varese,via Ravasi 2 +d001120,Instytut Matki i Dziecka,POL,PL911,01-211,Warszawa,ul. Kasprzaka 17A +d001121,Wiener Linien GmbH & Co. KG,AUT,AT130,1031,Wien,Erdbergstraße 202 +d001122,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Straße 8 +d001123,Somogy Megyei Kaposi Mór Oktató Kórház,HUN,HU232,7400,Kaposvár,Tallián Gyula utca 20–32. +d001124,"Kemis kemični izdelki, predelava in odstranjevanje odpadkov d.o.o.",SVN,SI,1360,Vrhnika,Pot na Tojnice 42 +d001125,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001126,Bundesverband für Lautsprache und Integration hörgeschädigter Menschen e. V.,DEU,DE,67227,Frankenthal,Europaring 18 +d001127,"Gemeente Amsterdam, Facilitair Bureau",NLD,NL,1011 PN,Amsterdam,Amstel 1 +d001128,PP Solutions GmbH & Co. KG,DEU,DE72,35418,Buseck,Fischbach 15 +d001129,Osaühing Reaalprojekt,EST,EE,71008,Viljandi linn,Tallinna tn 45 +d001130,Wallbergs Åkeri i Hennan AB,SWE,SE313,827 94,Ljusdal,Bränta Färilavägen 43 +d001131,Hidrostal Kereskedelmi és Javító Korlátolt Felelősségű Társaság,HUN,HU221,9087,Nyúl,Potyondi út 3. +d001132,Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos,LTU,LT,LT-50161,Kaunas,Eivenių g. 2 +d001133,Infomed S.R.L.,ROU,RO321,020475,București,"Str. Ion Movilă nr. 16, sector 2" +d001134,Linde Gas A/S,DNK,DK012,2750,Ballerup,Lautruphøj 2-6 +d001135,Rotes Kreuz Tirol gemeinnützige Rettungsdienst GmbH,AUT,AT,6063,Rum, +d001136,Agencia de Ciberseguretat de Catalunya,ESP,ES511,08908,L'Hospitalet de Llobregat,"C/ Salvador Espriu, 45-51" +d001137,Eiffage Énergie Systèmes IDF SAS,FRA,FR108,95300,Pontoise,10 rue Lavoisier +d001138,"PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d001139,AB Ängelholmshem,SWE,SE224,262 22,Ängelholm,Box 1111 +d001140,VĮ Lietuvos automobilių kelių direkcija,LTU,LT,LT-03109,Vilnius,J. Basanavičiaus g. 36 +d001141,SAS Clean Paysage,FRA,FRD11,14123,Ifs,1017 boulevard Charles Cros +d001142,Gemeinde Lonsee,DEU,DE145,89173,Lonsee,Hindenburgstr. 16 +d001143,Département de la Savoie,FRA,FRK27,73018,Chambéry,"château des Ducs de Savoie, CS 31802" +d001144,ASEI — ESAT René Caminade,FRA,FRJ23,,Colomiers, +d001145,Kimal,FRA,FRK26,69550,Amplepuis,37 rue Jeannette Ponteille +d001146,"Medis, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d001147,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d001148,CAR s.c.p.a.,ITA,ITI43,00012,Guidonia Montecelio (RM),via Tenuta del Cavaliere 1 +d001149,Département des Bouches-du-Rhône,FRA,FRL04,13256,Marseille Cedex 20,52 avenue de St-Just +d001150,Ciserom,ROU,RO121,515800,Sebeș,Str. Dorin Pavel nr. 78 +d001151,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d001152,Københavns Kommune - Økonomiforvaltningen,DNK,DK02,2400,København NV,Borups Allé 177 +d001153,Univerzitetni klinični center Maribor,SVN,SI032,2000,Maribor,Ljubljanska ulica 5 +d001154,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d001155,Autoridade Nacional de Segurança Rodoviária,PRT,PT,2734-507,Barcarena,"Avenida de Casal de Cabanas, Parque de Ciências e Tecnologia de Oeiras" +d001156,"Stadt Maulbronn, vertreten durch die Gt-service GmbH",DEU,DE12B,75433,Maulbronn,Klosterhof 31 +d001157,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d001158,Gemeindeverband Bezirkskrankenhaus Schwaz,AUT,AT,6130,Schwaz,Swarovskistrasse 1-3 +d001159,Ventilationskontroll Aeolus Aktiebolag,SWE,SE232,414 58,Göteborg,Fiskhamnsgatan 8e +d001160,Robotron Datenbank-Software GmbH,DEU,DED2,01189,Dresden,Stuttgarter Straße 29 +d001161,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d001162,Colligio AB,SWE,SE,791 71,Falun,Åsgatan 30 +d001163,Autostrada del Brennero SpA,ITA,ITH20,38121,Trento,via Berlino 10 +d001164,Charité Universitätsmedizin Berlin,DEU,DE300,10117,Berlin,Charitéplatz 1 +d001165,GERSTEL GmbH & Co. KG,DEU,DEA16,45473,Mülheim an der Ruhr,Eberhard-Gerstel-Platz 1 +d001166,"Stadt Frankfurt am Main, Amt für Bau und Immobilien",DEU,DE712,60594,Frankfurt am Main,Gerbermühlstraße 48 +d001167,Bundesministerium für Wirtschaft und Energie,DEU,DE300,10115,Berlin,Scharnhorststraße 34-37 +d001168,"Unilabor, družba za prodajo farmacevtskih izdelkov in medicinskih pripomočkov, d.o.o.",SVN,SI,1000,Ljubljana,Leskoškova cesta 12 +d001169,ZV KDZ Oberland Zentrale Beschaffungsstelle,DEU,DE216,83646,Bad Tölz,Prof.-Max-Lange-Platz 9 +d001170,ESAT Jean Pierrat,FRA,FR103,78531,Buc,"80 rue Hélène Boucher, BP 80119" +d001171,CUC Federazione dei comuni del Montebellunese per conto del Comune di Montebelluna,ITA,ITH34,31044,Montebelluna,corso Mazzini 118 +d001172,C&S Umwelttechnik GmbH,DEU,DEA1F,46485,Wesel,Mercatorstr. 40 +d001173,Kommunales Vergabezentrum Kreis Groß-Gerau für den Kreis Groß-Gerau,DEU,DE717,64521,Groß-Gerau,Wilhelm-Seipp-Str. 4 +d001174,Commune Saint-Martin-en-Bresse,FRA,FRC13,71620,Saint-Martin-en-Bresse,1 place du Monument +d001175,Stereoscape Oy,FIN,FI,,Helsinki, +d001176,Lancom inženiring računalniških sistemov d.o.o.,SVN,SI,2000,Maribor,Tržaška cesta 63 +d001177,Ministerul Afacerilor Interne – Direcția Generală Anticorupție,ROU,RO321,041337,Bucureşti,Șoseaua Olteniţei nr. 390A +d001178,INGUS — Ingenieurdienst Umweltsteuerung GmbH,DEU,DE92,30163,Hannover,Hubertusstr. 2 +d001179,Smabtp,FRA,FRH,75738,Paris,8 rue Louis Armand — CS 71201 +d001180,Stadt Tönisvorst,DEU,DEA1E,47918,Tönisvorst,Bahnstraße 15 +d001181,FRESENIUS KABI ROMANIA,ROU,RO122,,Ghimbav,"Strada Henri Coanda, Nr. 2" +d001182,"Ziberi Idriz s.p. - zelenjava in sadje ""Kivi""",SVN,SI,2250,Ptuj,Miklošičeva ulica 9 +d001183,Datanet Systems S.R.L.,ROU,RO321,050099,București,"Str. Independenței nr. 179, sector 5, judet: București, localitate: București, cod poștal: 050099" +d001184,SAP Deutschland SE & Co. KG,DEU,DE128,69190,Walldorf,Hasso-Plattner-Ring 7 +d001185,Hortibreiz,FRA,FR,56854,Caudan, +d001186,Defence Forces Ireland,IRL,IE061,Blackhorse Ave,Dublin 7,McKee Barracks +d001187,"Trado-Bus, s.r.o.",CZE,CZ063,674 01,Třebíč,Průmyslová 159 +d001188,Relico Oy,FIN,FI1C1,,Turku, +d001189,Stuttgart Netze GmbH,DEU,DE11,70190,Stuttgart,Stöckachstraße 48 +d001190,Limoges Habitat,FRA,FRI23,87010,Limoges Cedex,"224 rue François Perrin, CS 90398" +d001191,Luan Vision,ROU,RO111,417166,Oradea,Str. Margaretelor nr. 18 +d001192,Porsgrunn kommune,NOR,NO091,3915,Porsgrunn,Storgata 153 +d001193,HEP–Operator distribucijskog sustava d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 37 +d001194,Association verte vallée,FRA,FRY10,97119,Vieux-Habitants,route de Grande Rivière +d001195,Löwen Medien Service GmbH,DEU,DE911,38104,Braunschweig, +d001196,Tischlerei Füreder GmbH,AUT,AT31,4020,Linz,Hollabererstraße 6 +d001197,LJP automobiles,FRA,FRK22,07120,Pradons,3315 route de Ruoms +d001198,"TresTech, s.r.o.",CZE,CZ010,140 00,Praha 4,Hornokrčská 707/7 +d001199,Centre social protestant Berne-Jura,CHE,CH0,2720,Tramelan,Rue de la Promenade 14 +d001200,"Landesbetrieb für Hochwasserschutz und Wasserwirtschaft Sachsen-Anhalt, Vergabestelle Nord",DEU,DEE03,39104,Magdeburg,Otto-von-Guericke-Str. 5 +d001201,La Poste,FRA,FR,75015,Paris,9 rue du Colonel Pierre Avia — CPA 303 +d001202,Paquet développement,FRA,FRE11,59680,Obrechies,97 rue du Grand Chemin +d001203,"Medicoengineering d.o.o., podjetje za projektiranje, inženiring, izvajanje in vodenje investicijskih projektov",SVN,SI,1236,Trzin,Prevale 1 +d001204,CC Albères Côte Vermeille Illibéris,FRA,FRJ15,66704,Argelès-sur-Mer,3 impasse Charlemagne +d001205,Région Normandie,FRA,FRD11,14035,Caen Cedex,CS 50523 +d001206,"Pro Medens, trgovina z medicinskimi materiali d.o.o.",SVN,SI,6210,Sežana,Partizanska cesta 123B +d001207,Lemoine Espaces Verts,FRA,FRE12,62128,Heninel,6 rue de Saint-Martin +d001208,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d001209,"Labohem trgovina, zastopstvo, posredništvo, d.o.o.",SVN,SI,1230,Domžale,Kettejeva ulica 16 +d001210,"Consejería Delegada Mancomunada de Actuacions Ambientals Integrals, S. L.",ESP,ES523,46700,Gandía,"C/ Tossal, 8, bajo" +d001211,Enfrasys,FRA,FRK26,69140,Rillieux-la-Pape,482 rue des Mercières +d001212,"Makom Trgovina, d.o.o.",SVN,SI,3320,Velenje,Koroška cesta 64 +d001213,"Skat Skupina, družba za organizacijo in izvedbo celovitih pisarniških storitev d.o.o.",SVN,SI,6310,Izola - Isola,Polje 21 +d001214,TEERX Lifescience GmbH,DEU,DE30,10115,Berlin,Rheinsberger Str. 76 +d001215,Ville de Saint-Brevin,FRA,FRG01,44250,Saint-Brevin-les-Pins,Place de l'Hôtel de Ville +d001216,"Bundesrepublik Deutschland, vertreten durch das Beschaffungsamt des Bundesministeriums des Innern",DEU,DEA22,53119,Bonn,Brühler Straße 3 +d001217,Siemens SAS,FRA,FRF33,57084,Metz,6 rue Marie de Coëtlosquet +d001218,Allavoine Parc et Jardins,FRA,FR10,91570,Bièvres,4 route de Favreuse +d001219,Universitair Ziekenhuis Gent,BEL,BE234,9000,Gent,Corneel Heymanslaan 10 +d001220,"Eulen Servicios Sociosanitarios, S. A.",ESP,ES213,,Bilbao, +d001221,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d001222,Generální ředitelství cel,CZE,CZ010,140 00,Praha 4,Budějovická 1387/7 +d001223,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d001224,Santa Casa da Misericórdia de Lisboa,PRT,PTZZZ,1250-264,Lisboa,"Rua das Taipas, 1" +d001225,"Consejería de Agricultura, Desarrollo Rural, Población y Territorio",ESP,ES431,06800,Mérida,"Avenida Luis Ramallo, s/n" +d001226,"Medis, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d001227,S.C. Campeador S.R.L.,ROU,RO112,420096,Bistrița,Calea Moldovei nr. 13 +d001228,Électricité de France SA,FRA,FRL,13015,Marseille,7 rue André Allar +d001229,MVZ Taunus GmbH,DEU,DE718,61352,Bad Homburg v. d. H.,Zeppelinstraße 20 +d001230,FTPB,FRA,FR,53410,Saint-Pierre-la-Cour, +d001231,Direktoratet for forvaltning og økonomistyring (DFØ),NOR,NO,0130,Oslo,Postboks 7154 +d001232,"PRO-GEM svetovanje, marketing, d.o.o. Ljubljana",SVN,SI,1000,Ljubljana,Cesta na Brdo 85 +d001233,"Geosan Group, a.s.",CZE,CZ,280 02,Kolín,U Nemocnice 430 +d001234,Architektengruppe Schweitzer GmbH,DEU,DE911,38102,Braunschweig,Obergstraße 4 +d001235,BioNTech Manufacturing GmbH,DEU,DE,,Mainz, +d001236,Rääkkylän kunta,FIN,FI1D3,,Rääkkylä, +d001237,CAA di Giorgio Nicoli srl,ITA,ITH55,,Crevalcore, +d001238,Haut-Commissariat à la protection nationale,LUX,LU000,1471,Luxembourg,"211, route d'Esch" +d001239,Marketing at the Mill Ltd,GBR,UKG21,,London,20-22 Wenlock Road +d001240,Open Software srl,ITA,ITH35,,Mirano, +d001241,Electriciteitswerken W. van den Hanenberg bv,NLD,NL,5386 EB,Geffen,Papendijk 49 +d001242,Isoplaf,FRA,FRD,14540,Bourguébus, +d001243,Schultes Holzschlägerung,AUT,AT32,5710,Kaprun,Schlossstraße 15 +d001244,"D.S.U., družba za svetovanje in upravljanje, d.o.o.",SVN,SI,1000,Ljubljana,Dunajska cesta 160 +d001245,Consentec GmbH,DEU,DEA2D,,Aachen, +d001246,Sweco AB (Publ),SWE,SE110,100 26,Stockholm,Box 34044 +d001247,Commissariat à l'énergie atomique et aux énergies alternatives,FRA,FR,91191,Gif-sur-Yvette Cedex,CEA Paris Saclay — bâtiment 482 — PC nº 70 +d001248,Regionalny Zakład Zagospodarowania Odpadów Sp. z o.o.,POL,PL416,63-400,Ostrów Wielkopolski,ul. Staroprzygodzka 121 +d001249,Siemens AG Österreich,AUT,AT,1210,Wien,Siemensstraße 90 +d001250,Ministerstvo obrany,CZE,CZ010,160 01,Praha 6,Tychonova 1 +d001251,Staatliches Hochbauamt Freiburg,DEU,DE131,79104,Freiburg,Kartäuserstraße 61b +d001252,"ŽALE Javno podjetje, d.o.o.",SVN,SI,1000,Ljubljana,Med hmeljniki 2 +d001253,Bildungswerk der Hessischen Wirtschaft e.V.,DEU,DE,64295,Darmstadt,Rheinstrasse 94-96a +d001254,Groupement de coopération sanitaire Cœur Grand Est,FRA,FRF32,55107,Verdun,"Centre hospitalier Verdun Saint-Mihiel, 2 rue Anthouard" +d001255,Sandviken Energi AB,SWE,SE313,,Sandviken, +d001256,Stadt Bamberg/Zentrale Beschaffungs- und Vergabestelle,DEU,DE241,96049,Bamberg,Untere Sandstraße 34 +d001257,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001258,Christian Ruppert IT-Consulting,DEU,DEB3J,55218,Ingelheim,Auf dem Graben 12 +d001259,"Abast Systems & Solutions, S. L.",ESP,ES511,,Barcelona, +d001260,"Harald Bruhns GmbH, Vertriebscenter Berlin",DEU,DE405,13407,Berlin,Montanstraße 6 +d001261,Exatech,FRA,FR104,91370,Verrières-le-Buisson,18 rue des Gardes +d001262,Turun kaupunki,FIN,FI1C1,FI-20101,Turku,"PL 630 (käyntiosoite: Linnankatu 31, 2. krs)" +d001263,Region Halland,SWE,SE231,301 80,Halmstad,Box 517 +d001264,Staatliches Amt für Landwirtschaft und Umwelt Mittleres Mecklenburg,DEU,DE803,18069,Rostock,An der Jägerbäk 3 +d001265,Stad Roeselare,BEL,BE256,8800,Roeselare,Botermarkt 2 +d001266,"Pro Medens, trgovina z medicinskimi materiali d.o.o.",SVN,SI,6210,Sežana,Partizanska cesta 123B +d001267,Molnlycke healthcare,FRA,FRL04,13471,Marseille Cedex 02,europrogramme 40 boulevard de Dunkerque — CS 41221 +d001268,Inköp Gävleborg,SWE,SE313,826 80,Söderhamn,Kommunalförbundet Inköp Gävleborg Köpmannen 7 +d001269,Maroni Transport International,FRA,FRY30,97393,Saint-Laurent-du-Maroni,"ZA La Charbonnière, 02 rue du Bas" +d001270,Gmina Miejska Kraków – Urząd Miasta Krakowa,POL,PL213,31-004,Kraków,pl. Wszystkich Świętych 3–4 +d001271,"SIJ, podjetje za proizvodnjo in ekonomske storitve z marketingom, d.o.o.",SVN,SI,1230,Domžale,Krumperška ulica 11 +d001272,"SBS Seidor, S. L.",ESP,ES511,08500,Vic,"C/ Eix Onze de Setembre, 41" +d001273,Enedis,FRA,FR,92079,Paris La Défense,Tour Enedis 34 place des Corolles Courbevoie +d001274,COWI A/S,DNK,DK,2800,kongens Lyngby,Parallelvej 2 +d001275,Direcția Generală de Asistență Socială și Protecția Copilului Argeș,ROU,RO311,110347,Pitești,Str. Drăgăşani nr. 8 +d001276,Eximtur,ROU,RO113,400366,Cluj-Napoca,Str. Nichita Stănescu nr. 16 +d001277,SUTURA Képviseleti és Kereskedelmi Korlátolt Felelősségű Társaság,HUN,HU,1097,Budapest,Gubacsi út 47. +d001278,Wallfahrtsstadt Werl,DEU,DEA5B,59457,Werl,Hedwig-Dransfeld-Str. 23 +d001279,"Provincia di Brescia — settore della Stazione appaltante, centrale unica di committenza area vasta Brescia",ITA,ITC47,25121,Brescia,via Musei 32 +d001280,Spitalul Clinic Județean Mureș,ROU,RO125,540072,Târgu Mureș,Str. Bernady György nr. 6 +d001281,Drager France,FRA,FR,92182,Antony Cedex,25 rue Georges Besse +d001282,"Universitäts- und Hansestadt Greifswald, Der Oberbürgermeister, Stadtbauamt, Abt. Bauverwaltung",DEU,DE80N,17489,Greifswald,Markt 15 +d001283,"Göteborgs Stad, Lokalförvaltningen",SWE,SE232,402 26,Göteborg,Box 5163 +d001284,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d001285,VIANOVA 87 Közmű és Útépítő Zártkörűen Működő Részvénytársaság,HUN,HU110,1215,Budapest,Vasas utca 65–67. +d001286,Radomskie Przedsiębiorstwo Energetyki Cieplnej RADPEC S.A.,POL,PL921,26-616,Radom,ul. Żelazna 7 +d001287,Saulea Conseil,FRA,FR101,75020,Paris,2b rue de l'Ermitage +d001288,"Urbaser, S. A.",ESP,ES30,28031,Madrid,"Camino de las Hormigueras, 171" +d001289,"Subsecretaría de Asuntos Exteriores, Unión Europea y Cooperación",ESP,ES300,28012,Madrid,"Plaza de la Provincia, 1" +d001290,Van Amerongen facilitair bedrijf bv,NLD,NL,6827 BH,Arnhem,Dr. C. Lelyweg 6 +d001291,Bilbao Compañía Anónima de Seguros y Reaseguros,ESP,ES,48992,Neguri (Vizcaya),"Paseo del Puerto, 20" +d001292,Lancashire County Council,GBR,UKD4,PR1 8XJ,Preston,"3rd Floor CCP, County Hall" +d001293,CMAR PACA,FRA,FRL04,13008,Marseille,5 boulevard Pèbre +d001294,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d001295,Landsnet hf.,ISL,IS,109,Reykjavik,Gylfaflot 9 +d001296,S.C. Editronic Internațional S.R.L.,ROU,RO321,030354,București,"Str. Patinoarului nr. 7, sector 3, județ București, localitate: București, cod poștal: 030354" +d001297,Hanke Bauelemente OHG,DEU,DEA45,33813,Oerlinghausen,Industriestraße 1a +d001298,Unipolsai assicurazioni SpA,ITA,ITH55,,Bologna, +d001299,Santa Casa da Misericórdia de Lisboa,PRT,PTZZZ,1250-264,Lisboa,"Rua das Taipas, 1" +d001300,Ets pub. du mus. d'Orsay mus. Orangerie,FRA,FR101,75007,Paris,62 rue de Lille +d001301,SM aménagement hydraulique Val Yvette,FRA,FR104,91165,Saulx-les-Chartreux,12 avenue Salvador Allende +d001302,Direktoratet for Kriminalforsorgen,DNK,DK,1401,København K,Strandgade 100 +d001303,Fiskgrossisten i Lysekil AB,SWE,SE232,471 61,Myggenäs,Almösundsvägen 3 +d001304,Kabis Consulting Konrad Piesyk,POL,PL22,42-202,Częstochowa,"ul. Wały Dwernickiego 117/121, lok. P211" +d001305,"Timestamp — Sistemas de Informação, S. A.",PRT,PTZZZ,1700-036,Lisboa,"Praça de Alvalade, 6, 11.º frente" +d001306,IPSEN Pharma GmbH,DEU,DE21,81677,München,Einsteinstr. 174 +d001307,Autocont a.s.,CZE,CZ080,702 00,Ostrava,Hornopolní 3322/34 +d001308,Šilutės rajono savivaldybės administracija,LTU,LT023,LT-99133,Šilutė,Dariaus ir Girėno g. 1 +d001309,J.P. van Eesteren bv,NLD,NL,2803 MC,Gouda,Hanzeweg 16 +d001310,TMI Flex,NLD,NL,,Amsterdam, +d001311,CA Portes de France — Thionville,FRA,FRF33,57972,Yutz,"Hôtel de Communauté Esp. Cormontaigne, 4 avenue Gabriel-Lippmann, CS 30054" +d001312,Azienda ospedale-università Padova,ITA,ITH36,35128,Padova,via Giustiniani 1 +d001313,Intendente de Ferrol,ESP,ES111,15490,Ferrol (A Coruña),"C/ Irmandiños, s/n, Arsenal Militar" +d001314,"Stadt Plauen, Vergabestelle",DEU,DED44,08523,Plauen,Unterer Graben 1 +d001315,Wojewódzki Szpital Zespolony im. Stanisława Rybickiego,POL,PL71,96-100,Skierniewice,ul. Rybickiego 1 +d001316,Gemeente Cranendonck,NLD,NL,6020 AB,Budel,Postbus 2090 +d001317,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Straße 8 +d001318,EuRec Environmental Technology GmbH,DEU,DEG0P,,Krayenberggemeinde OT Merkers, +d001319,Florence Consulting Group srl,ITA,ITI14,,Sesto Fiorentino (FI),viale Luciano Lama 23 +d001320,Mesto Brezno,SVK,SK032,977 01,Brezno,Nám. M.R.Štefánika 1 +d001321,Sander Elektrische Anlagen GmbH,DEU,DE112,71287,Weissach,"Boschstrasse, 4, 4" +d001322,Rompetrol Downstream,ROU,RO321,011028,București,Piața Presei Libere nr. 3-5 +d001323,Fakultní nemocnice Plzeň,CZE,CZ032,305 99,Plzeň,Edvarda Beneše 1128/13 +d001324,Siemens AG Niederlassung Saarbrücken,DEU,DEC01,66115,Saarbrücken,Werner-von-Siemens-Allee 4 +d001325,Vantaan kaupunki,FIN,FI1B1,FI-01030,Vantaa,PL 1100 +d001326,COTA,BEL,BE,10000,Bruxelles,7 rue de la Révolution +d001327,Alten Belgium,BEL,BE100,1060,Saint-Gilles,Charleroise Steenweg 112 +d001328,VRTEC VIŠKI GAJ,SVN,SI,1000,Ljubljana,Reška ulica 31 +d001329,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Straße 8 +d001330,Staatliches Hochbauamt Freiburg,DEU,DE131,79104,Freiburg,Kartäuserstraße 61b +d001331,Fresenius Kabi Polska Sp. z o.o.,POL,PL911,02-305,Warszawa,Al. Jerozolimskie 134 +d001332,Viešoji įstaiga CPO LT,LTU,LT,LT-01104,Vilnius,Gedimino pr. 38 +d001333,Municipiul Oradea,ROU,RO111,410100,Oradea,Str. Unirii nr. 1 +d001334,Ingenieurbüro Gollwitzer GmbH,DEU,DE215,83435,Bad Reichenhall,Heimfeld 5 +d001335,Ville de Bergerac,FRA,FRI11,24100,Bergerac,19 rue Neuve d'Argenson +d001336,Danish Red Cross,DNK,DK011,2100,Copenhagen OE,Blegdamsvej 27 +d001337,CBC équipement,FRA,FR108,95740,Frepillon,ZAE du Montubois 2 chemin de la Justice +d001338,ASST Nord Milano,ITA,ITC4C,20099,Sesto San Giovanni,viale Matteotti 83 +d001339,Prevozništvo Iztok Pucer s.p.,SVN,SI,1310,Ribnica,Lepovče 22 +d001340,"Geoprogres, spol. s r.o.",CZE,CZ,193 00,Praha 9 - Horní Počernice,Stoliňská 819/6 +d001341,Univerzitetni klinični center Maribor,SVN,SI032,2000,Maribor,Ljubljanska ulica 5 +d001342,LHD Group France SAS,FRA,FR,69100,Villeurbanne,150-160 rue du 8 Mai 1945 +d001343,Spitalul Universitar de Urgență „Elias”,ROU,RO321,011461,Bucureşti,Str. Mărăști nr. 17 +d001344,Konsorcjum Szczotka: Zakład Usług Leśnych Andrzej Szczotka,POL,PL411,64-930,Szydłowo,Krępsko 69A +d001345,INTER KOOP družba za trgovino in proizvodnjo d.o.o.,SVN,SI,2000,Maribor,Zrkovska cesta 97 +d001346,MVZ Donauisar Klinikum Dingolfing GmbH,DEU,DE22C,84130,Dingolfing,Teisbacher Str. 1 +d001347,"Deutsche Bundesbank, Beschaffungszentrum",DEU,DE712,60329,Frankfurt am Main,Taunusanlage 5 +d001348,SH-Produkter AS,NOR,NO,7052,Trondheim,Strindveien 32 +d001349,Brandschutztechnik Müller GmbH,DEU,DEG0C,99869,Drei Gleichen, +d001350,Zentraldienst der Polizei des Landes Brandenburg,DEU,DE40H,15806,Zossen,Am Baruther Tor 20 +d001351,Gmina Miasta Gdyni,POL,PL633,81-382,Gdynia,Piłsudskiego 52/54 +d001352,ORES Assets,BEL,BE32B,6041,Gosselies,Avenue Jean Mermoz 14 +d001353,Monti,FRA,FR108,95300,Ennery,82/84 chemin de la Chapelle-Saint-Antoine +d001354,"Kyocera Document Solutions Czech, s.r.o.",CZE,CZ010,190 00,Praha 9,Českomoravská 2420/15 +d001355,Comune di Cardito (NA),ITA,ITF33,80024,Comune di Cardito (NA),piazza Giuseppe Garibaldi 1 +d001356,Spijtenburg Werving en Advies bv,NLD,NL,,Breda, +d001357,Gemeente Gouda,NLD,NL,,Gouda, +d001358,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d001359,"Italcomma Slovakia, s.r.o.",SVK,SK,010 01,Žilina,Dolné Rudiny 1 +d001360,Stichting voor Onderwijs op Islamitische grondslag in Midden- en Oost-Nederland (SIMON),NLD,NL,3831 NV,Leusden,De Mulderij 10 +d001361,K.A. Rasmussen AS,EST,EE,10621,Tallinn,Kadaka tee 36 +d001362,Wasserverband Weddel-Lehre,DEU,DE91,38162,Cremlingen,Hauptstr. 2b +d001363,LimaCorporate S.p.A.,ITA,IT,33038,Villanova di San Daniele del Friuli (UD),"Via Nazionale, 52" +d001364,"SANOLABOR, podjetje za prodajo medicinskih, laboratorijskih in farmacevtskih proizvodov, d.d.",SVN,SI,1000,Ljubljana,Leskoškova cesta 4 +d001365,Stadt Neumarkt i. d. OPf.,DEU,DE236,92318,Neumarkt in der Oberpfalz,Rathausplatz 1 +d001366,"Bundesministerium für Kunst, Kultur, öffentlichen Dienst und Sport",AUT,AT,1030,Wien,Radezkystraße 2 +d001367,Alza.cz a.s.,CZE,CZ010,170 00,Praha,Jateční 1530/33 +d001368,SARL HO travail,FRA,FRJ24,,Marciac, +d001369,Viking Life-Saving Equipment,DNK,DK,6710,Esbjerg,Sædding Ringvej 13 +d001370,Servicefirmaet Renell A/S,DNK,DK013,3000,Helsingør, +d001371,DMRV Duna Menti Regionális Vízmű Zártkörűen Működő Társaság,HUN,HU120,2600,Vác,Kodály Zoltán út 3. +d001372,"Landesbetrieb Bau- und Liegenschaftsmanagement Sachsen-Anhalt (BLSA), Zentrale Vergabestelle (ZVS)",DEU,DEE03,39014,Magdeburg,"PF 3964 (Tessenowstraße 1, 39114 Magdeburg)" +d001373,Ville de Neuilly-sur-Seine,FRA,FR105,92522,Neuilly-sur-Seine Cedex,96 avenue Achille Peretti +d001374,"Universität Zürich, Portfoliomanagement Assetmanagement",CHE,CH0,8006,Zürich,Stampfenbachstraße 73 +d001375,Gemeente Vlaardingen,NLD,NL,,Vlaardingen, +d001376,"O2 Czech Republic, a.s.",CZE,CZ,140 22,Praha 4 - Michle,Za Brumlovkou 266/2 +d001377,Międzygminne Przedsiębiorstwo Gospodarki Odpadami Sp. z o.o.,POL,PL426,78-320,Połczyn-Zdrój,Wardyń Górny 35 +d001378,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d001379,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d001380,Strasbourg électricité réseaux,FRA,FRF11,67000,Strasbourg,26 boulevard du Président Wilson +d001381,Siemens Financial Services,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d001382,Carl Zeiss SpA con socio unico,ITA,IT,,Milano, +d001383,AOK — Rheinland-Pfalz / Saarland — Die Gesundheitskasse,DEU,DEB,67304,Eisenberg,Virchowstraße 30 +d001384,ESP sécurité,FRA,FR103,78180,Montigny-le-Bretonneux,6 rue Jean-Pierre Timbaud +d001385,Ethos Engineering srl,ITA,ITC18,,Alessandria, +d001386,Junta de Gobierno de la Diputación Provincial de Lugo,ESP,ES112,27001,Lugo,"C/ San Marcos, 8" +d001387,"Stadt Offenburg, Fachbereich Bauservice, Zentrale Vergabestelle",DEU,DE134,77654,Offenburg,Wilhelmstraße 12 +d001388,Compania Națională Aeroporturi București S.A.,ROU,RO322,075150,Otopeni,Calea Bucureștilor nr. 224E +d001389,Gemeente Leidschendam-Voorburg,NLD,NL,,Leidschendam, +d001390,Siun sote – Pohjois-Karjalan sosiaali- ja terveyspalvelujen kuntayhtymä,FIN,FI1D,,Joensuu, +d001391,Ol To VVS AS,NOR,NO092,4700,Vennesla,Lundevegen 40 +d001392,Voglauer Gschwandtner & Zwilling GmbH,AUT,AT,5441,Abtenau, +d001393,"Consejería de Administracion Autonómica, Medio Ambiente y Cambio Climático",ESP,ES120,33005,Oviedo,"C/ Trece Rosas, 2, EASMU, 4.ª planta" +d001394,Centre hospitalier Pierre-Oudot,FRA,FRK24,38302,Bourgoin-Jallieu,30 avenue du Médipôle +d001395,Argenta sp. z o.o. sp. k.,POL,PL415,60-401,Poznań,ul. Polska 114 +d001396,"ha-vel internet, s.r.o.",CZE,CZ,712 00,Ostrava,Olešní 587/11a +d001397,Schorr Architekten Partnerschaft,DEU,DE21M,83377,Vachendorf,Am Weichselbaum 14 +d001398,"Orlen Unipetrol Doprava, s.r.o.",CZE,CZ042,436 70,Litvínov,Růžodol č.p. 4 +d001399,Au forum du bâtiment,FRA,FR106,93400,Saint-Ouen,3 boulevard Jean Jaurès +d001400,HWK Trier,DEU,DEB21,,Trier, +d001401,Papeterie Pichon SAS,FRA,FRK25,42340,Veauche,750 rue Colonel Louis Lemaire +d001402,Pop Industry S.R.L.,ROU,RO414,230070,Slatina,"Strada, Nr." +d001403,Holzfällung Hausbacher,AUT,AT32,5600,St. Johann im Pongau,Hallmoos 22 +d001404,De LOCHTING vzw,BEL,BE,8800,Roeselare,Oude Stadenstraat 15 +d001405,"Abast Systems & Solutions, S. L.",ESP,ES511,,Barcelona, +d001406,Mark Medical trgovina in storitve d.o.o.,SVN,SI,6210,Sežana,Partizanska cesta 109 +d001407,DREAL Grand-Est,FRA,FR,57070,Metz,2 rue Augustin Fresnel +d001408,"Compañía Española Petrolífera, S. A. (CEPSA)",ESP,ES618,28042,Madrid,"Campo de las Naciones, avenida del Partenón, 12" +d001409,Ville de Fleury-Mérogis,FRA,FR104,91700,Fleury-Mérogis,"12, rue Roger Clavier" +d001410,kreuger wilkins architekten,DEU,DE111,70176,Stuttgart,Rosenbergstr. 52a +d001411,Hlavní město Praha,CZE,CZ010,110 00,Praha,Mariánské náměstí 2 +d001412,"Clean Garant Gebäudereinigung, Dr. Winkler GmbH",DEU,DE300,13439,Berlin,Dannenwalder Weg 91 +d001413,Siemens Healthcare SAS,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d001414,SLTP (Societe laonnoise de travaux publics),FRA,FRD22,02000,Étouvelles,13 rue de la Rivière +d001415,Terreauciel,FRA,FRJ23,31100,Toulouse,108 route d'Espagne +d001416,Technisphère — cotraitant,FRA,FRJ23,31200,Toulouse,place Paul Riché +d001417,"Göteborgs Stad, Lokalförvaltningen",SWE,SE232,402 26,Göteborg,Box 5163 +d001418,"OFA, s.r.o.",CZE,CZ010,130 00,Praha,Jičínská +d001419,Ministerul Apărării Naționale – Unitatea Militară 01020,ROU,RO113,405200,Dej,"Str. Tudor Vladimirescu nr. 1, mun. Dej, județ Cluj" +d001420,Centre social protestant Berne-Jura,CHE,CH0,2720,Tramelan,Rue de la Promenade 14 +d001421,"PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d001422,SARL 1 pacte littoral,FRA,FRL04,13400,Aubagne,480 RN 8 quartier des Fyols — CS 30960 +d001423,"Stadt Leipzig, Amt für Gebäudemanagement",DEU,DED51,04092,Leipzig,Prager Straße 118-136 +d001424,Dimira srl,ITA,ITI43,00166,Roma,via della Maglianella 65/E +d001425,Mindsoft IT Solutions S.R.L.,ROU,RO126,,Sibiu,Str. Moldovei nr. 56 +d001426,"LENIA DT Security, spol. s r.o",CZE,CZ,102 00,Praha,U hostivařského nádraží 556 12 +d001427,Stadt Laage,DEU,DE,18299,Laage,Am Markt 7 +d001428,Deutsche Post AG,DEU,DE300,,10317 Berlin, +d001429,Tallinna Teede Aktsiaselts,EST,EE,13816,Tallinn,Betooni tn 24 +d001430,Dirección General de Telecomunicaciones y Digitalización,ESP,ES220,31621,Sarriguren (Navarra),"C/ Cabárceno 6, 3.ª planta" +d001431,Gebr. Stumpp GmbH & Co. KG,DEU,DE143,72336,Balingen,Rosenfelder Straße 58 +d001432,Studia digital,FRA,FRK26,13790,Rousset,605 avenue Olivier Perroy +d001433,Dr. Gustav Schädla GmbH & Co.KG,DEU,DE929,30177,Hannover, +d001434,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d001435,Landkreis Neunkirchen,DEU,DEC03,66564,Ottweiler,Wilhelm-Heinrich-Straße 36 +d001436,W. R. Berkley Spain,ESP,ES,28046,Madrid,"Paseo de la Castellana, 141, 18.ª planta" +d001437,"Marijanović, obrt za proizvodnju i usluge",HRV,HR,32245,Podgrađe,Kralja Tomislava 4 +d001438,UAB „Labochema LT“,LTU,LT,LT-03151,Vilnius,Vilkpėdės g. 22 +d001439,Roche farmacevtska družba d.o.o.,SVN,SI,1000,Ljubljana,Stegne 13G +d001440,Oscar Downstream,ROU,RO322,77125,Măgurele,Str. Atomiștilor nr. 14 +d001441,Umeå kommun,SWE,SE,901 84,Umeå,Upphandlingsbyrån +d001442,VšĮ Vilniaus universiteto ligoninė Santaros klinikos,LTU,LT,LT-08661,Vilnius,Santariškių g. 2 +d001443,Rud. Otto Meyer Technik GmbH & Co.KG,DEU,DE1,73430,Aalen,Gartenstraße 105 +d001444,Klüh Cleaning GmbH,DEU,DEA11,40211,Düsseldorf,Am Wehrhahn 70 +d001445,Jan-Olof Sundbergs Åkeri Aktiebolag,SWE,SE232,524 00,Alingsås,Pl 6231 +d001446,Malermester Knutson AS,NOR,NO092,4636,Kristiansand S,Skibåsen 26 C +d001447,Stadt Dortmund- Vergabe und Beschaffungszentrum,DEU,DEA52,44135,Dortmund,Viktoriastr. 15 +d001448,DEMGRO nv,BEL,BE,8800,Roeselare,Zwaaikomstraat 12 +d001449,"Stadt Halle (Saale), Fachbereich Recht, Team Vergabe Bauleistungen/Bauplanungen",DEU,DEE02,06108,Halle (Saale),Marktplatz 1 +d001450,Statutární město České Budějovice,CZE,CZ031,370 01,České Budějovice,nám. Přemysla Otakara II. 1/1 +d001451,Stereoscape Oy,FIN,FI,,Helsinki, +d001452,Bio-Rad Laboratories GmbH,DEU,DE21H,85622,Feldkirchen,Kapellenstraße 12 +d001453,Furesø Kommune,DNK,DK013,3500,Værløse,Stiager 2 +d001454,Forstunternehmen Schaupper,AUT,AT32,5660,Taxenbach,Feldhöflstraße 2 +d001455,José Paulo Silva Guimarães Ferreira,PRT,PT170,,Lisboa, +d001456,SAS Nies et fils,FRA,FRK22,07600,Vals-les-Bains,6 avenue Chabalier +d001457,Servizi integrati srl,ITA,ITF45,00187,Roma,via Sistina 121 +d001458,Ingenieurteam Nord GbR,DEU,DE80L,18435,Stralsund,Hainholzstraße 6a +d001459,Graitec Innovation GmbH,DEU,DE929,30453,Hannover,Davenstedter Str. 60 +d001460,Pharmafarm,ROU,RO125,060044,Corunca,Str. Principală nr. 1B/1 +d001461,Ville de Charleroi,BEL,BE32B,6000,Charleroi,Place Charles II 14-15 +d001462,"Novartis Farmaceutica, S. A.",ESP,ES511,08013,Barcelona,"Gran Via Corts Catalanes, 764" +d001463,GrassMark Oy,FIN,FI1C1,,Lieto, +d001464,Geosat,FRA,FRE11,59000,Lille,4 rue Augereau +d001465,"Pohjois-Karjalan koulutuskuntayhtymä, Riveria",FIN,FI1D3,,Joensuu, +d001466,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4 b +d001467,Gemeinde Hallwang,AUT,AT,5300,Hallwang,Dorfstraße 45 +d001468,Valstybės vaiko teisių apsaugos ir įvaikinimo tarnyba prie SADM,LTU,LT,LT-01120,Vilnius,Labdarių g. 8 +d001469,GrassMark Oy,FIN,FI1C1,,Lieto, +d001470,Korton Computer Communication (KCC) bv,NLD,NL,,Nieuw-Vennep, +d001471,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001472,"Euler Hermes Aktiengesellschaft agissant en qualité de mandataire pour le compte et au nom du gouvernement de la République fédérale d''allemagne, représentée par le ministère fédéral des affaires économiques et de l'énergie",DEU,DE600,,Hamburg,"Gasstraße 29, 22761" +d001473,"HEP Energija, trgovanje in prodaja električne energije, d.o.o.",SVN,SI,1000,Ljubljana,Dunajska cesta 151 +d001474,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d001475,Bundesagentur für Arbeit Regionales Einkaufszentrum NRW,DEU,DE,40474,Düsseldorf,Josef-Gockeln-Str. 7 +d001476,Croatia osiguranje d.d.,HRV,HR050,10000,Zagreb,Vatroslava Jagića 33 +d001477,MMM Multi-Media-Marketing Austria GmbH,AUT,AT,4020,Linz,Promenade25B / Stiege 2 +d001478,Informática el Corte Inglés,PRT,PTZZZ,2790-143,Carnaxide,"Rua Quinta do Pinheiro, 16, 4.º A" +d001479,Spitalul Municipal de Urgență Roman,ROU,RO214,611027,Roman,Str. Tineretului nr. 28 +d001480,Ausbau 2000 Osnabrück GmbH,DEU,DE944,49084,Osnabrück,Franz Lenz Str. 2 +d001481,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d001482,Strict Prest,ROU,RO113,400157,Cluj-Napoca,Str. Ploiești nr. 1 +d001483,Česká republika – Ministerstvo vnitra,CZE,CZ010,,Praha 7, +d001484,"Presidencia de la Agencia Estatal Consejo Superior de Investigaciones Científicas, M. P.",ESP,ES300,28006,Madrid,"C/ Serrano, 117" +d001485,costituendo R.T.I. KPMG advisory SpA — INFO.C.E.R. srl,ITA,ITI4,,Roma, +d001486,Erda Plus,ROU,RO126,,Șelimbăr,Str. 1 Decembrie nr. 42 +d001487,Gemeindeverband Bezirkskrankenhaus Schwaz,AUT,AT,6130,Schwaz,Swarovskistraße 1-3 +d001488,Funeralia GmbH,DEU,DED42,09427,Ehrenfriedersdorf,Max-Wenzel-Straße 16 +d001489,FAW gGmbH,DEU,DE,18069,Rostock,Carl-Hopp-Str. 4a +d001490,"CESIT Seguridad, S. L.",ESP,ES24,50011,Zaragoza,"C/ Miquel Roca y Junyent, local 206" +d001491,Trameco,ROU,RO111,410605,Oradea,Str. Borşului nr. 14A +d001492,Županijska bolnica Čakovec,HRV,HR061,40000,Čakovec,Ivana Gorana Kovačića 1e +d001493,Partners Medical Solution S.R.L.,ROU,RO321,014033,București,"Str. Vadul Moldovei nr. 22, sector 1" +d001494,Wilhelm Brugger,AUT,AT323,5300,Hallwang,Döbringstraße 22 +d001495,"Medias International, trgovanje in trženje z medicinskim materialom d.o.o.",SVN,SI,1000,Ljubljana,Leskoškova cesta 9D +d001496,Mindsoft IT Solutions S.R.L.,ROU,RO126,,Sibiu,Str. Moldovei nr. 56 +d001497,FVB Sverige AB,SWE,SE125,721 37,Västerås,Isolatorvägen 8 +d001498,Monting d.o.o.,HRV,HR050,10000,Zagreb,Svetice 21 +d001499,Tiebel Dach GmbH vom First bis zum Giebel,DEU,DED2,01159,Dresden,Reisewitzer Straße 44 +d001500,Studentenwerk Würzburg,DEU,DE263,97072,Würzburg,Am Studentenhaus 1 +d001501,Università degli studi di Milano — Bicocca,ITA,ITC4C,20126,Milano,piazza dell'Ateneo Nuovo 1 +d001502,"Dirección de Compras de la Corporación de Radio y Televisión Española, S. A.",ESP,ES300,28223,Pozuelo de Alarcón,"Avenida Radio Televisión, 4" +d001503,EDF SA,FRA,FR,75017,"8 rue Floréal, Paris 17",Direction des achats informatique et télécoms — Tour EDF — 20 place de la Défense +d001504,Mestna občina Ljubljana,SVN,SI,1000,Ljubljana,Mestni trg 1 +d001505,Artisana Medical S.R.L.,ROU,RO321,021468,București,"Str. Teleajen nr. 50, sector 2" +d001506,Opiskelija-asunnot Oy Joensuun Elli,FIN,FI1D3,,Joensuu, +d001507,"MEDIS, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d001508,Furesø Kommune,DNK,DK013,3500,Værløse,Stiager 2 +d001509,Roche România,ROU,RO321,020335,București,Piața Presei Libere nr. 3-5 +d001510,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d001511,Bergander u. Broich,DEU,DEA46,32457,Porta Westfalica, +d001512,Stadt Ludwigsburg,DEU,DE115,71638,Ludwigsburg,Wilhelmstraße 11 +d001513,Gemeinde Stuvenborn,DEU,DEF0D,24568,Kattendorf,Winsener Str. 2 +d001514,Fresenius Kabi România,ROU,RO122,,Ghimbav,Str. Henri Coandă nr. 2 +d001515,"Landesbetrieb Bau- und Liegenschaftsmanagement Sachsen-Anhalt (BLSA), Zentrale Vergabestelle (ZVS)",DEU,DEE03,39014,Magdeburg,"PF 3964 (Tessenowstraße 1, 39114 Magdeburg)" +d001516,Zentrale Beschaffungsstelle bei dem Landgericht Magdeburg,DEU,DEE03,,Magdeburg, +d001517,Conseil général du Var,FRA,FRL05,83076,Toulon,"Direction des infrastructures et de la mobilité, 390 avenue des Lices, CS 41303" +d001518,"Roez, s.r.o.",SVK,SK023,934 01,Levice,Tyršova 2354/2 +d001519,Subra mesures,FRA,FRJ23,31000,Toulouse,7 rue Jean de Guerlins +d001520,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d001521,Lieksan kaupunki,FIN,FI1D3,,Lieksa, +d001522,LUAN VISION,ROU,RO111,417166,Oradea,"Strada Margaretelor nr. 18, Nr. 18" +d001523,Mesto Komárno,SVK,SK023,945 01,Komárno,Nám. gen. Klapku 1 +d001524,Autohaus Schneider GmbH & Co. KG,DEU,DEA56,58332,Schwelm,Wörther Straße 8-12 +d001525,Eesti Keskkonnateenused AS,EST,EE,10621,Tallinn,Artelli tn 15 +d001526,Stiftelsen Bodenbo,SWE,SE332,961 17,Boden,Box 801 +d001527,Bolnišnica Sežana,SVN,SI,6210,Sežana,Cankarjeva ulica 4 +d001528,"J.S. Evro-Medical Company družba za trgovino, proizvodnjo in storitve d.o.o.",SVN,SI,2000,Maribor,Jarnikova ulica 7 +d001529,Betelec,FRA,FR,51100,Reims, +d001530,Mülheimer Seniorendienste GmbH,DEU,DEA16,45475,Mülheim an der Ruhr,Auf dem Bruch 70 +d001531,Miasto Bielsko-Biała Urząd Miejski w Bielsku-Białej,POL,PL225,43-300,Bielsko-Biała,pl. Ratuszowy 9 +d001532,AB Bostaden i Umeå,SWE,SE,901 06,Umeå,Box 244 +d001533,In Extenso Innovation Croissance,FRA,FR,06410,Biot,"2000 route des Lucioles Les Algorithmes, Thalès B" +d001534,Dirección General de Recursos Económicos del Servicio Canario de la Salud,ESP,ES70,35004,Las Palmas de Gran Canaria,"C/ Juan XXIII, 17, 3.ª planta" +d001535,Orifarm GmbH,DEU,DE,,Leverkusen, +d001536,180 degrés Ingénierie,FRA,FRI12,33100,Bordeaux,1 quai Deschamps +d001537,Powiat Bocheński – Starostwo Powiatowe w Bochni,POL,PL217,32-700,Bochnia,ul. Kazimierza Wielskiego 31 +d001538,Nova Mosilana as,CZE,CZ,,Brno, +d001539,Deutsche Nationalbibliothek,DEU,DE712,60322,Frankfurt am Main,Adickesallee 1 +d001540,Elis,FRA,FR105,92210,Saint-Cloud,5 boulevard Louis Loucheur +d001541,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001542,Stadt Würzburg,DEU,DE263,97070,Würzburg,Rückermainstr. 2 +d001543,Schenker Storen AG,CHE,CH0,5012,Schönenwerd,Stauwehrstraße 34 +d001544,Gemeente Bodegraven-Reeuwijk,NLD,NL,,Bodegraven, +d001545,Buchhandlung Peter Weda GmbH,DEU,DEA1E,41379,Brüggen, +d001546,Helsingin Diakonissalaitoksen Hoiva Oy,FIN,FI1B1,,Helsinki, +d001547,Szociális és Gyermekvédelmi Főigazgatóság,HUN,HU,1132,Budapest,Visegrádi utca 49. +d001548,Sonepar IDF,FRA,FR105,92240,Malakoff,5 avenue Jules Ferry +d001549,BT Italia SpA,ITA,ITC4C,,Milano (MI), +d001550,Dinan Agglomération,FRA,FRH01,22106,Dinan Cedex,"8 boulevard Simone-Veil, CS 56357" +d001551,"Metalka Media, podjetje za prodajo medicinskih pripomočkov, d.o.o.",SVN,SI,1000,Ljubljana,Cesta v Gorice 34C +d001552,Wielkopolskie Centrum Onkologii,POL,PL,61-866,Poznań,Garbary 15 +d001553,École nationale vétérinaire d'Alfort,FRA,FR107,94704,Maisons-Alfort Cedex,7 avenue du Général de Gaulle +d001554,Česká republika – Generální ředitelství cel,CZE,CZ010,140 96,Praha 4,Budějovická 7 +d001555,"Svet zdravia Nemocnica Topoľčany, a.s.",SVK,SK023,955 20,Topoľčany,Pavlovova 17 +d001556,Občina Dobje,SVN,SI,3224,Dobje pri Planini,Dobje pri Planini 26 +d001557,Département de la Manche,FRA,FRD12,50050,Saint-Lô,98 route de Candol +d001558,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d001559,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschiz,"Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" +d001560,"Traffic srl, P.I. 03310860782, sede legale in Amantea, via Salvo D’acquisto 17",ITA,ITF61,,Amantea, +d001561,Eiffage Énergies Haute-Normandie,FRA,FRD2,76800,Saint-Étienne-du-Rouvray,260 rue du Pré de la Roquette/parc d'activités de la Vente Olivier +d001562,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d001563,IT.Niedersachsen FG 54 — Zentrale Vergabestelle IT,DEU,DE9,30169,Hannover,Humboldtstraße 33 +d001564,"Medical Measurement Systems BV, nom commercial Laborie Médical Technologies",FRA,FR,75008,Paris,10 rue de Penthièvre +d001565,Lemvig Kommune,DNK,DK0,7620,Lemvig,Rådhusgade 2 +d001566,Asocierea dintre General Electric Global Services GmbH și GE Global Parts Products GmbH,CHE,CH04,5400,Aargau,"Brown Boveri Str. 7, 5401 Baden, Elveția" +d001567,Grupa Azoty Zakłady Azotowe Kędzierzyn S.A.,POL,PL52,47-220,Kędzierzyn-Koźle,ul. Mostowa 30A +d001568,Babiel,DEU,DEA11,40233,Düsseldorf,Erkrateher Straße 224 +d001569,Fliesen Schlegel GmbH,DEU,DEE08,06647,Finneland,"Bahnhofstraße, 15" +d001570,"4Jtech, s.r.o.",CZE,CZ010,155 21,Praha 5,Ringhofferova 115/1 +d001571,Atkins Ltd,GBR,UKJ2,KT18 5BW,Epsom,"Woodcote Grove, Ashley Road, Epsom, Surrey, KT18 5BW" +d001572,Stadt Erlangen,DEU,DE252,91052,Erlangen,Schuhstraße 40 +d001573,Ville de Persan,FRA,FR108,95340,Persan,65 avenue Gaston Vermeire +d001574,Reims Habitat Champagne Ardenne Office,FRA,FRF23,51100,Reims,71 avenue d'Épernay +d001575,Paziaud Agence Touren,FRA,FR107,94300,Vincennes,20 rue Félix Faure +d001576,Municipiul Oradea,ROU,RO111,410100,Oradea,Str. Unirii nr. 1 +d001577,Bundesministerium für Wirtschaft und Energie (BMWi),DEU,DEA22,53123,Bonn,Villemombler Straße 76 +d001578,Lidköpings kommun,SWE,SE232,531 88,Lidköping,Skaragatan 8 +d001579,Holzaufarbeitung Sporrer,DEU,DE,,Neualbenreuth, +d001580,UAB „Meda LT“,LTU,LT,,Vilniaus r., +d001581,Société équipement laboratoire industrie,FRA,FRJ23,31100,Toulouse,36 avenue de Larrieu +d001582,Société équipement laboratoire industrie,FRA,FRJ23,31100,Toulouse,36 avenue de Larrieu +d001583,Vrtec Pod gradom,SVN,SI,1000,Ljubljana,Praprotnikova ulica 2 +d001584,"Svenska Laboratorieförsäljningen Aktiebolag, LABFAB",SWE,SE313,826 50,Söderhamn,Södra Hamngatan 50 +d001585,Amt der Oberösterreichischen Landesregierung,AUT,AT31,4052,Ansfelden,Traunuferstraße 98a +d001586,CIP Avantaj,ROU,RO225,820048,Tulcea,Str. Păcii nr. 80 +d001587,Regionalny Szpital Specjalistyczny im. dr. Władysława Biegańskiego,POL,PL616,86-300,Grudziądz,ul. L. Rydygiera 15/17 +d001588,Česká republika - Český úřad zeměměřický a katastrální,CZE,CZ010,182 11,Praha 8,Pod sídlištěm 1800/9 +d001589,Blumer-Lehmann AG,CHE,CH055,9200,Gossau,Erlenhof 1 +d001590,Metz Művek Kft.,HUN,HU,3527,Miskolc,Teréz utca 6. +d001591,Landratsamt Coburg – Kommunaler Hochbau,DEU,DE247,96450,Coburg,Lauterer Straße 60 +d001592,Vittoria assicurazioni SpA,ITA,ITC4C,,Milano, +d001593,IAT GmbH,AUT,AT,,Kematen, +d001594,Město Veselí nad Moravou,CZE,CZ064,698 01,Veselí nad Moravou,tř. Masarykova 119 +d001595,"Omega svetovanje, inženiring, razvoj in raziskovanje, d.o.o.",SVN,SI,1000,Ljubljana,Dolinškova ulica 8 +d001596,Malco AS,NOR,NO092,4621,Kristiansand,Kjerrheibakken 18 +d001597,Macon,ROU,RO423,,Cristur,Șoseaua Hunedoarei nr. 1-3 +d001598,Pool Ecologia srl,ITA,ITI12,,Capannori (LU), +d001599,Schreiner Abschleppdienst GmbH,DEU,DEC01,66115,Saarbrücken,Angela-Braun-Str. 10 +d001600,Hidrocom d.o.o.,HRV,HR,33405,pitomača,A. Mihanovića bb +d001601,Kalmar läns landsting,SWE,SE213,,Kalmar, +d001602,Euro Défense — service Labrenne Propreté,FRA,FR105,92230,Gennevilliers,5 avenue Henri Colin +d001603,Johannes Kepler Universität Linz,AUT,AT,4040,Linz,Altenberger Straße 69 +d001604,"Leoss podjetje za laserje, elektroniko, optiko, senzorje in sisteme, d.o.o., Ljubljana",SVN,SI,1000,Ljubljana,Dunajska cesta 106 +d001605,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschiz,"Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" +d001606,CAP sciences CCSTI,FRA,FRI12,33300,Bordeaux,Hangar 20 quai Bacalan +d001607,Nv Wind aan de Stroom,BEL,BE211,2030,Antwerpen,p/a Zaha Hadidplein 1 +d001608,VWR International GmbH,DEU,DED21,01127,Dresden,Großhainer Straße 99 +d001609,Česká republika Ministerstvo práce a sociálních věcí,CZE,CZ010,120 00,Praha 2,Na Poříčním právu 1/376 +d001610,Gustave Roussy,FRA,FR107,94800,Villejuif,114 rue Édouard-Vaillant +d001611,Despierre SAS,FRA,FR108,95300,Ennery,7 chemin de la Chapelle-Saint-Antoine +d001612,Lindner Gerüstbau GmbH,DEU,DE40G,03099,Kolkwitz OT Krieschow,Zeppelinstr. 07 +d001613,Karelia Ammattikorkeakoulu Oy,FIN,FI1D3,,Joensuu, +d001614,Fa. Josef Kirschner,DEU,DE224,94562,Oberpöring,Plattlinger Straße 25 +d001615,Työterveyslaitos,FIN,FI,FI-00250,Helsinki,Topeliuksenkatu 41 b +d001616,Vergabe und Beschaffungszentrum Dortmund,DEU,DEA52,44135,Dortmund,Viktoriastraße 15 +d001617,Scan Expert,ROU,RO213,700032,Iași,Str. Sfântul Sava nr. 18 +d001618,Amt für Bau und Immobilien,DEU,DE712,60594,Frankfurt am Main,Gerbermühlstr. 48 +d001619,Samodzielny Publiczny Zakład Opieki Zdrowotnej w Łęcznej,POL,PL814,21-010,Łęczna,ul. Krasnystawska 52 +d001620,Securitas Sverige Aktiebolag,SWE,SE,102 29,Stockholm, +d001621,Aesculap Chifa Sp. z o.o.,POL,PL,64-300,Nowy Tomysl,ul. Tysiąclecia 14 +d001622,G 550 Simulator — Pilot training Gulfstream G 550,DEU,DE21L,82234,Weßling, +d001623,ccma,FRA,FR104,78711,Mantes-la-Ville,21 rue de la Touques +d001624,Pfizer Inc.,USA,,,New York, +d001625,"FUNDATIA ""KIWI CASA BUCURIEI""",ROU,RO125,540074,Targu Mures,"Strada Papiu Ilarian Alexandru, Nr. 7" +d001626,Télécom Services,FRA,FR105,92752,Nanterre,10 rue des Peupliers +d001627,Franke Dauerwerbung GmbH & Co. KG,DEU,DEA1,40474,Düsseldorf,Arena Straße 1 +d001628,Katinala Live Oy,FIN,FI1C2,,Katinala, +d001629,Usługi Leśne Karol Berner,POL,PL84,16-320,Bargłów Kościelny,Wólka Karwowska 14 +d001630,"Bundesrepublik Deutschland, vertreten durch das Bundesministerium des Inneren, für Bau und Heimat, vertreten durch das Bundesamt für Bauwesen und Raumordnung",DEU,DEA22,53179,Bonn,Deichmanns Aue 31-37 +d001631,Merck România S.R.L.,ROU,RO321,020334,București,"Str. Gara Herăstrău nr. 4D, sector 2" +d001632,ERC Konsultatsiooni Osaühing,EST,EE,10129,Tallinn,Väike-Ameerika tn 15-9 +d001633,"Z + M Partner, spol. s r.o.",CZE,CZ080,702 00,Ostrava,Valchařská 3261/17 +d001634,Selite SARL,FRA,FRY30,97351,Matoury,1294 route de la Chaumière — La Cotonnière Nord +d001635,Provence Cheminée,FRA,FRL04,13170,Les Pennes-Mirabeau,Chemin de Velaux +d001636,Fővárosi Közterület-fenntartó Zártkörűen Működő Nonprofit Részvénytársaság,HUN,HU110,1081,Budapest,Alföldi utca 7. +d001637,Zavod za javno zdravstvo Koprivničko-križevačke županije,HRV,HR063,48000,Koprivnica,Trg Tomislava dr. Bardeka 10/10 +d001638,M4 Ingenieure GmbH,DEU,DE212,80333,München,Augustenstraße 10 +d001639,"''SEDENT'' TRGOVINSKE STORITVE, SERVIS, JOŽEF SEVER S.P.",SVN,SI,2310,Slovenska Bistrica,Župančičeva ulica 7 +d001640,MINEC PRODUKTION AB,SWE,SE123,,Åtvidaberg, +d001641,"Atos Medical Spain, S. L.",ESP,ES51,,Barcelona,08007 +d001642,TTK GmbH,DEU,DE12,76131,Karlsruhe,Gerwigstraße 53 +d001643,Società reale mutua di assicurazioni,ITA,ITC11,,Torino, +d001644,Ernst & Young GmbH Wirtschaftsprüfungsgesellschaft,DEU,DE71A,65760,Eschborn,Mergenthalerallee 3-5 +d001645,Mairie d'Esbly,FRA,FR102,77450,Esbly,7 rue Victor-Hugo +d001646,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d001647,Sipic trgovina in proizvodnja d.o.o.,SVN,SI,1000,Ljubljana,Koprska ulica 94 +d001648,La Poste,FRA,FR,75015,Paris 15,9 rue du Colonel Pierre Avia +d001649,TREBOR DRUM CONSTRUCT SRL,ROU,RO111,410265,Oradea,"Strada Erofte Grigore, Nr. 1B" +d001650,ERA paysagiste,FRA,FR104,94200,Ivry-sur-Seine,72 avenue Jean Jaurès +d001651,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d001652,"Zarys International Group Sp. z o.o., Sp. k.",POL,PL229,41-808,Zabrze,ul. Pod Borem 18 +d001653,Leggere srl,ITA,ITC46,24127,Bergamo,via Grumello 57 +d001654,Vrtec Mojca,SVN,SI,1000,Ljubljana,Levičnikova ulica 11 +d001655,MVZ Klinikum am Luitpoldplatz Deggendorf GmbH,DEU,DE224,94469,Deggendorf,Luitpoldplatz 25 +d001656,Egis villes et transports,FRA,FRG01,,Nantes, +d001657,Eurovia liants Sud-Ouest,FRA,FRJ27,,Bressols, +d001658,Katinala Live Oy,FIN,FI1C2,,Katinala, +d001659,Joensuun ev.lut. seurakuntayhtymä,FIN,FI1D3,,Joensuu, +d001660,Viški vrtci,SVN,SI,1000,Ljubljana,Jamova cesta 23 +d001661,Klinikum Osnabrück GmbH,DEU,DE944,49076,Osnabrück,Am Finkenhügel 1 +d001662,"Mutua Universal Mugenat, Mutua Colaboradora con la Seguridad Social número 10",ESP,ES511,08022,Barcelona,"Avenida Tibidabo, 17-19" +d001663,Elettromeccanica Manfredini srl,ITA,IT,,Soliera (MO), +d001664,Helsingin ja Uudenmaan sairaanhoitopiirin kuntayhtymä,FIN,FI1B1,FI-00029,HUS,"PL 441 (Uutistie 5, FI-01770 Vantaa)" +d001665,Karl Storz Endoskopija d.o.o.,SVN,SI,1000,Ljubljana,Cesta v Gorice 34B +d001666,Groupe Sirius,FRA,FR101,75017,Paris,98 boulevard Malesherbes +d001667,Siena Educación,ESP,ES300,28003,Madrid,"C/ José Abascal, 57, 5-b" +d001668,Landkreis Osterholz,DEU,DE936,27711,Osterholz-Scharmbeck,Osterholzer Straße 23 +d001669,RoMed Kliniken - Kliniken der Stadt und des Landkreises Rosenheim GmbH,DEU,DE213,83022,Rosenheim,Pettenkoferstraße 10 +d001670,Dubost Environnement,FRA,FRF33,57000,Metz,15 rue au Bois +d001671,"Abbott Laboratories, s.r.o.",CZE,CZ01,160 00,Praha 6 - Dejvice,Evropská 2591/33d +d001672,GEAPRODUKT trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d001673,Stadt Wien – Wiener Wohnen,AUT,AT130,1030,Wien,Rosa-Fischer-Gasse 2 +d001674,"Kostak, komunalno in gradbeno podjetje, d.d.",SVN,SI,8270,Krško,Leskovška cesta 2A +d001675,Donauisar KlinikService GmbH,DEU,DE224,94469,Deggendorf,Perlasberger Str. 41 +d001676,Compania Națională de Administrare a Infrastructurii Rutiere S.A. prin DRDP Cluj,ROU,RO113,400205,Cluj-Napoca,Str. Decebal nr. 128 +d001677,Helber + Ruff Beratende Ingenieure PartG mbB,DEU,DE115,71640,Ludwigsburg (Württemberg),Mömpelgardstraße 16 +d001678,Tomst s.r.o.,CZE,CZ010,141 00,Praha 4,Michelská 964/78 +d001679,Inter Koop družba za trgovino in proizvodnjo d.o.o.,SVN,SI,2000,Maribor,Zrkovska cesta 97 +d001680,Atea Sverige AB,SWE,SE110,164 93,Kista,Box 18 +d001681,Metallwarenfabrik Walter H. Becker GmbH,DEU,DE22A,84371,Triftern,Anzenkirchener Straße 4 +d001682,Le Bureau Suéde AB,SWE,SE,111 22,Stockholm,Lilla Bantorget 11 +d001683,Opéra national de Paris,FRA,FR101,75012,Paris,120 rue de Lyon +d001684,Deutsche Gesetzliche Unfallversicherung e. V. (DGUV),DEU,DE300,10117,Berlin,Glinkastr. 40 +d001685,Tosama Tovarna sanitetnega materiala d.o.o.,SVN,SI,1230,Domžale,Šaranovičeva cesta 35 +d001686,Orifarm GmbH,DEU,DE,,Leverkusen, +d001687,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d001688,Commune de Trets,FRA,FRL04,13530,Trets,place du 14 Juillet +d001689,Bati action,FRA,FRI12,33600,Pessac, +d001690,"Landeshauptstadt München, Baureferat",DEU,DE212,81671,München,Friedenstraße 40 +d001691,Association Les Serres des Prés/ETS La Ferme des Jésuites,FRA,FRE11,59279,Mardyck-Loon-Plage,283 rue de Quenez +d001692,Øvre Romerike Innkjøpssamarbeid,NOR,NO082,2050,Jessheim,Furusetgt 12 +d001693,Procurator Sverige AB,SWE,SE232,431 26,Mölndal,Box 1004 +d001694,ADX groupe,FRA,FRC14,53200,Château-Gontier, +d001695,Kalmar läns landsting,SWE,SE213,392 44,Kalmar,Sjöbrings väg 4A plan 2 +d001696,"Arthur Nikisch, Dipl.-Ing. (FH)",DEU,DE22B,,Bogen, +d001697,Wesemann GmbH,DEU,DE922,28857,Syke,Max-Planck-Straße 15-25 +d001698,Centre communal d'action sociale de Pontault-Combault,FRA,FR102,77340,Pontault-Combault,30 avenue des Marguerites +d001699,Brenntag,ROU,RO322,077040,Chiajna,Str. Gării nr. 1 +d001700,Elektrotechnik Butz GmbH,DEU,DEE07,39130,Magdeburg,Poststr. 7 +d001701,Umwelttechnik Bornemann GmbH,DEU,DE80,18182,Bentwisch,Am Graben 12 +d001702,Gemeente Pijnacker-Nootdorp,NLD,NL,,Pijnacker, +d001703,"Eulen Servicios Sociosanitarios, S. A.",ESP,ES213,,Bilbao, +d001704,Gras Savoye Guadeloupe,FRA,FRY10,97122,Baie-Mahault,immeuble Connexion — boulevard Marquisat de Houelbourg — BP 2064 +d001705,Mittetulundusühing Valga Arvutikeskus,EST,EE,68204,Valga vald,Vabaduse tn 22-7 +d001706,GrassMark Oy,FIN,FI1C1,,Lieto, +d001707,Vrtec Ciciban,SVN,SI,1000,Ljubljana,Šarhova ulica 29 +d001708,Weco TMC S.R.L.,ROU,RO321,023782,București,"Strada, Nr." +d001709,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001710,Konsorcjum Urtica Sp. z o.o. PGF S.A.,POL,PL,54-613,Wrocław,ul. Krzemieneicka 120 +d001711,McCann FitzGerald Solictiors,IRL,IE,D02 X576,Dublin,"Riverside One, Sir John Rogerson's Quay" +d001712,"Landesamt für Finanzen Dienststelle Regensburg, Abt. 3T AGA IuK",DEU,DE232,93047,Regensburg,Bahnhofstraße 7 +d001713,Puolustusvoimien logistiikkalaitos,FIN,FI197,FI-33541,Tampere,Hatanpään valtatie 30 +d001714,"Ferretería La Hondura, S. L.",ESP,ES704,35600,Puerto del Rosario,"Parque industrial La Hondura, 2, del polígono I" +d001715,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d001716,"Cardio Medical družba za trgovino in storitve, d.o.o.",SVN,SI,1236,Trzin,Špruha 1 +d001717,Osaühing Arimee,EST,EE,80042,Pärnu linn,Lao tn 8-10 +d001718,Direktion für Inneres und Justiz des Kantons Bern Amt für Geoinformation,CHE,CH0,3013,Bern,Reiterstraße 11 +d001719,"Finson - prevozi potnikov in blaga, posredništvo pri prodaji izdelkov in kompenzacije Sonja Rigler s.p.",SVN,SI,1310,Ribnica,Cesta IX 5 +d001720,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d001721,Conseil départemental de l'Hérault,FRA,FRJ13,34087,Montpellier,"hôtel du département, mas d'alco, 1977 avenue des Moulins" +d001722,"Rioboco — Serviços Gerais, Engenharia e Manutenção, S. A.",PRT,PT,3480-391,Vagos,Vagos +d001723,Geonius Groep bv,NLD,NL,6160 BB,Geleen,Postbus 1097 +d001724,Hirsch GmbH,DEU,DE2,81369,München,Euckenstraße 17 +d001725,Sodexo Entreprises Administrations,FRA,FRI12,33185,Le Haillan,5 allée des Musardises +d001726,"Department of Agriculture, Food and the Marine",IRL,IE,Kildare Street,Dublin 2,Agriculture House +d001727,B.Braun Medical AB,SWE,SE110,182 12,Danderyd,Box 110 +d001728,Tinmar Energy S.A.,ROU,RO321,014476,București,Str. Floreasca nr. 246C +d001729,"A Koda Plus, tehnična oprema objektov d.o.o.",SVN,SI,1000,Ljubljana,Celovška cesta 175 +d001730,Board Paradise s. r. o.,SVK,SK,971 01,Prievidza,Bojnická cesta 24/21 +d001731,Gemeente Rotterdam,NLD,NL,3002 AN,Rotterdam,Wilhelminakade 179 +d001732,"Instituto Técnico de Alimentação Humana (ITAU), S. A.",PRT,PT,2794-022,Carnaxide,"Rua da Garagem, 10, 2.º piso" +d001733,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d001734,"Göteborgs Stad, Lokalförvaltningen",SWE,SE232,402 26,Göteborg,Box 5163 +d001735,Institution et développement,FRA,FR105,92260,Fontenay-aux-Roses,27 rue Jean-Noël-Pelnard +d001736,Naturstyrelsen,DNK,DK0,7183,Randbøl,Førstballevej 2 +d001737,Chabanne Architecte,FRA,FRK26,69009,Lyon,38 quai Pierre Scize +d001738,"Bundesministerium für Wirtschaft und Energie (BMWi), Referat I C 4",DEU,DEA22,53123,Bonn,Villemombler Str. 76 +d001739,IT Baden-Württemberg,DEU,DE111,70469,Stuttgart,Krailenshalden Str. 44 +d001740,"PKS stavby, a.s.",CZE,CZ,591 01,Žďár nad Sázavou,Brněnská 126/38 +d001741,EPG Projektledning AB,SWE,SE232,414 63,Göteborg,"Amerikaskjulet, Emigrantvägen 2B" +d001742,Bio-Rad Laboratories Aktiebolag,SWE,SE110,172 22,Sundbyberg,Box 1097 +d001743,Calzaturificio F.lli Soldini SpA,ITA,ITI18,,Capolona, +d001744,Revatrin Grupp OÜ,EST,EE,74011,Viimsi vald,Metsa tee 15 +d001745,"Representaciones Fermín Escribano, S. L.",ESP,ES423,16100,Valverde del Júcar,"C/ San Pedro, 15" +d001746,DMRV Duna Menti Regionális Vízmű Zártkörűen Működő Társaság,HUN,HU120,2600,Vác,Kodály Zoltán út 3. +d001747,Stadtverwaltung Grimma,DEU,DED52,04668,Grimma,Markt 16/17 +d001748,Ortho-Clinical Diagnostics NV,BEL,BE,1930,Zaventem,Da Vincilaan 1 +d001749,Venturo Investment S.R.L.,ROU,RO321,030901,București,Str. Prof. Barcianu Daniel nr. 20 +d001750,Stierlen GmbH,DEU,DE124,,Rastatt,Lochfeldstraße 30 +d001751,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d001752,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4 b +d001753,Kivikandur OÜ,EST,EE,76902,Harku vald,Järvekalda tee 1 +d001754,ENDOMEDICA GmbH,DEU,DEE0,06120,Halle / Saale,Weinbergweg 23 +d001755,OÜ Võlukaloss,EST,EE,74305,Anija vald,Tuleviku tn 5 +d001756,Econocom Products et Solutions,FRA,FRD,92800,Puteaux,4 quai de Dion Bouton +d001757,OMV Petrom Marketing,ROU,RO321,013329,București,"Str. Coralilor nr. 22, sector 1" +d001758,"Landkreis Börde, Zentrale Vergabestelle",DEU,DEE07,39387,Oschersleben (Bode),Triftstr. 9-10 +d001759,Chrome Computers S.R.L.,ROU,RO321,021366,București,"Str. Gheorghe Pop de Băsești nr. 61-63, sector 2" +d001760,Javni vzgojno izobraževalni zavod Osnovna šola Destrnik - Trnovska vas,SVN,SI,2253,Destrnik,Janežovski Vrh 45 +d001761,Swerock AS,NOR,NO,0609,Oslo,Postboks 6704 Etterstad +d001762,ITS akciová společnost,CZE,CZ010,130 52,Praha 2,Vinohradská 184 +d001763,Métropole Rouen Normandie,FRA,FRD22,76176,Rouen,108 allée François-Mitterrand +d001764,Rudolf Weber Gebäudereinigung und Gebäudedienste GmbH + Co. KG,DEU,DEA13,45127,Essen,Lazarettstraße 13 +d001765,Ministerstvo spravedlnosti České republiky,CZE,CZ010,128 10,Praha 2,Vyšehradská 16 +d001766,Hungaropharma Gyógyszerkereskedelmi Zártkörűen Működő Részvénytársaság,HUN,HU110,1061,Budapest,Király utca 12. +d001767,DAA Deutsche Angestellten-Akademie GmbH,DEU,DEA2,53111,Bonn,Kaiser-Karl-Ring 12 +d001768,"M&M Intercom trgovina in storitve, d.o.o.",SVN,SI,1000,Ljubljana,Letališka cesta 33F +d001769,Grupa Azoty Zakłady Azotowe Puławy S.A.,POL,PL81,24-110,Puławy,al. Tysiąclecia Państwa Polskiego 13 +d001770,Geaprodukt trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d001771,Dipharma Arzneimittel GmbH,DEU,DE,,Limburg a. d. Lahn, +d001772,"Sonepar Ibérica Spain, S. A. U.",ESP,ES30,28914,Leganés,"C/ Ramón y Cajal, 24" +d001773,Volvo Danmark A/S,DNK,DK0,2630,Taastrup,Højager 7 +d001774,Ettevõtluse Arendamise Sihtasutus,EST,EE,11412,Tallinn,Lasnamäe tn 2 +d001775,Regionale Vervoerscentrale Stedendriehoek PlusOV,NLD,NL,7241 CR,Lochem,Hanzeweg 8 +d001776,Endoelektronik.pl Sp. z o.o. Sp. K.,POL,PL923,05-840,Brwinów, +d001777,Chabanne Ingénierie,FRA,FRK26,69001,Lyon,1 montée de la Butte +d001778,LMJD Dennerle Motzet Architekten Part mbB,DEU,DE212,81241,München,Planegger Straße 33 +d001779,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d001780,Bundesagentur für Arbeit Regionales Einkaufszentrum NRW,DEU,DE,40474,Düsseldorf,Josef-Gockeln-Str. 7 +d001781,BT Group plc,GBR,UKN,EC1A 7AJ,London,81 Newgate Street +d001782,Landratsamt Greiz,DEU,DEG0L,07973,Greiz,Dr. Rathenau-Platz 11 +d001783,Castrén Engine Osakeyhtiö,FIN,FI1B1,,Helsinki, +d001784,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d001785,Technologie hlavního města Prahy,CZE,CZ010,170000,Praha,"Praha 7, Dělnická 213/12" +d001786,MEVA-TEC s.r.o.,CZE,CZ042,413 01,Roudnice nad Labem,Chelčického 1228 +d001787,Vesthimmerlands Kommune,DNK,DK050,9600,Aars,Vestre Boulevard 7 +d001788,Jannach & Picker GmbH,AUT,AT33,6134,Vomp,Au 44 +d001789,"Dopravný podnik mesta Prešov, akciová spoločnosť",SVK,SK041,080 06,Ľubotice,Bardejovská 7 +d001790,Storio Sp. z o.o. sp.k.,POL,PL214,32-020,Wieliczka,ul. Reformacka 25 +d001791,Baromed Kereskedelmi és Szolgáltató Kft,HUN,HU321,1064,Budapest,Székely Bertalan utca 10. 3/40. +d001792,Staatliche Schlösser Burgen und Gärten Sachsen gGmbH,DEU,DED21,01099,Dresden,Stauffenbergallee 2a +d001793,Flyttningsbyrån Halmstad AB,SWE,SE,302 31,Halmstad,Slottsmöllan +d001794,Helsingin Asumisoikeus Oy,FIN,FI1B1,FI-00880,Helsinki,Sahaajankatu 3 +d001795,Camera di commercio di Milano Monza Brianza Lodi,ITA,ITC4C,20123,Milano,via Meravigli 9/b +d001796,Computacenter AG & Co. oHG,DEU,DE,12099,Berlin,Mariendorfer Damm 1 +d001797,Amt für Bau und Immobilien,DEU,DE712,60594,Frankfurt am Main,Gerbermühlstrasse 48 +d001798,"O2 Czech Republic, a.s.",CZE,CZ,140 22,Praha 4 - Michle,Za Brumlovkou 266/2 +d001799,Ingenieurbüro Schoberth & Partner mbb,DEU,DE215,83435,Bad Reichenhall,Nonn 52 +d001800,UK Export Finance,GBR,UKI,,London,"1 Horse Guards Road, Sw1a 2hq" +d001801,Glas.- und Gebäudereinigung Adams GmbH,DEU,DEE0B,06179,Teutschenthal OT Holleben,Ernst-Thälmann-Str. 57 +d001802,"Universität Kassel, vertreten durch den Präsidenten",DEU,DE731,34109,Kassel,Mönchebergstr. 19 +d001803,UAB „Baltpola“,LTU,LT,LT-05273,Vilnius,Grigalaukio g. 34-98 +d001804,BWI GmbH,DEU,DE212,80637,München,Dachauer Straße 128 +d001805,RWE Generation SE,DEU,DEA13,45141,Essen,RWE Platz 3 +d001806,Gähler und Partner AG,CHE,CH0,5408,Ennetbaden,Sonnenbergstrasse 1 +d001807,Geocor Trade Imp-Exp,ROU,RO223,900455,Constanța,Str. 1 Mai nr. 106 +d001808,Grupa Azoty Zakłady Azotowe Kędzierzyn S.A.,POL,PL52,47-220,Kędzierzyn-Koźle,ul. Mostowa 30A +d001809,Legume Fructe Com S.R.L.,ROU,RO321,031455,București,"Str. Alex. Moruzzi nr. 11A, sector 3" +d001810,Országos Mentőszolgálat,HUN,HU,1055,Budapest,Markó utca 22. +d001811,Farid industrie SpA,ITA,ITC11,,Vinovo, +d001812,The Flower Family bv,NLD,NL,,Amsterdam, +d001813,GEN-I Hrvatska d.o.o.,HRV,HR050,10000,Zagreb,Radnička cesta 54 +d001814,Brézillon SAS,FRA,FR10,60280,Margny-lès-Compiègne,128 rue de Beauvais +d001815,FEI Europe B.V.,NLD,NL41,5651GG,Eindhoven,"Achtseweg Noord 5, 5651GG Eindhoven, Nizozemsko" +d001816,Human Care HC AB (publ),SWE,SE110,117 43,Stockholm,Årstaängsvägen 21 B +d001817,UTE Auna-Arquican-Corviola,ESP,ES705,35200,Telde,"C/ Diego Soprani y Ponce de León, 5, 2.º derecha" +d001818,"Etiazul, S. L.",ESP,ES,35420,Moya,"C/ Alcalde Pedro Moreno, 74" +d001819,"Urkia, Sociedad Cooperativa",ESP,ES213,,Dima, +d001820,Rogaland Fylkeskommune,NOR,NO0A1,4010,Stavanger,Arkitekt Eckhoffsgate 1 +d001821,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d001822,Stadt Kaufbeuren,DEU,DE272,87600,Kaufbeuren,Kaiser-Max-Straße 1 +d001823,Greenfish,BEL,BE100,1050,Ixelles,Avenue Louise 279 +d001824,Υπουργείο Υγείας,CYP,CY,1448,Λευκωσία,Προδρόμου 1 και Χείλωνος 17 +d001825,Hans Meier Landmaschinen OHG,DEU,DE80N,17509,Rubenow, +d001826,Topo Études,FRA,FRH04,,Lisieux, +d001827,Stadtverwaltung Ellwangen – Hochbauamt,DEU,DE11D,73479,Ellwangen (Jagst),Spitalstraße 4 +d001828,Siemens Healthcare SAS,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d001829,Stadt Neumarkt in der Oberpfalz,DEU,DE236,92318,Neumarkt in der Oberpfalz,Rathausplatz 1 +d001830,Sveriges domstolar,SWE,SE,551 81,Jönköping,Kyrkogatan 34 +d001831,Centre hospitalier universitaire — Hôpitaux de Rouen,FRA,FRD22,76031,Rouen Cedex,1 rue de Germont +d001832,"ha-vel internet, s.r.o.",CZE,CZ,712 00,Ostrava,Olešní 587/11a +d001833,Digitech SA,FRA,FRC13,13322,Marseille,21 avenue Fernand Sardou +d001834,Ville de Montpellier,FRA,FRJ13,34267,Montpellier Cedex 2,1 place Georges Frêche +d001835,Estimprim,FRA,FR,,Autechaux,6 ZA La Craye +d001836,"Eltima trgovina, zastopanje in posredovanje, d.o.o.",SVN,SI,1218,Komenda,Pod brezami 3 +d001837,F.Delbanco GmbH Co. KG,DEU,DE,21339,PO Box 1447,Bessemerstrasse 3 +d001838,Macon,ROU,RO423,,Cristur,Șoseaua Hunedoarei nr. 1-3 +d001839,"HSI, spol. s r.o.",CZE,CZ010,130 00,Praha 3 - Žižkov,V kapslovně 2767/2 +d001840,Sytral,FRA,FRK26,69487,Lyon,"21 boulevard Vivier Merle, CS 63815" +d001841,ETS ENST sup. consulaire Grenoble EC MA,FRA,FRK24,38000,Grenoble,12 rue Pierre-Sémard +d001842,Reichmann Gebäudetechnik GmbH,DEU,DEG0G,,Bad Berka, +d001843,Takeda GmbH,DEU,DE1,78467,Konstanz,Byk-Gulden-Straße 2 +d001844,Johnson et Johnson,FRA,FR,92130,Issy-les-Moulineaux, +d001845,Västra Götalandsregionen,SWE,SE232,462 80,Vänersborg,Östergatan 1 +d001846,MGDIS,FRA,FR,56000,Vannes,"Parc d'innovation Bretagne Sud, allée Nicolas-le-Blanc" +d001847,"Centro Hospitalar Universitário de Lisboa Norte, E. P. E.",PRT,PT170,1649-035,Lisboa,Lisboa +d001848,Credipar,FRA,FR103,78300,Poissy,"Centre Expertise Métiers Régions PSA, 2-10 boulevard de l'Europe" +d001849,Conseil général de la Nièvre,FRA,FRC12,58002,Nevers,2 rue de la Chaumière +d001850,"Estanflux, S. A.",ESP,ES511,08023,Barcelona,"C/ Gomis, 1" +d001851,MMTP Guyane SAS,FRA,FRY30,97354,Remire-Montjoly,130 b route du Mahury +d001852,Łukasz Dawidowski prowadzący działalność gospodarczą pod firmą Nevora Projekt Łukasz Dawidowski,POL,PL633,80-280,Gdańsk,Szymanowskiego 18/28 +d001853,Orifarm GmbH,DEU,DEA24,51381,Leverkusen,Fixheider Straße 4 +d001854,"KEFO, kemija in farmacija, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 29 +d001855,Architekturbüro Reiner Schlientz,DEU,DE27D,86720,Nördlingen,Heugasse 4 +d001856,S.C. J'Info Tours S.R.L.,ROU,RO321,010458,București,Str. Jules Michelet nr. 1 +d001857,"Stadt Bruchsal, Geschäftsstelle Zentrale Vergaben",DEU,DE123,76646,Bruchsal,Otto-Oppenheimer-Platz 5 +d001858,"Universität zu Köln, Abt. Einkauf",DEU,DEA23,50923,Köln,Albertus-Magnus-Platz +d001859,Triadis Services,FRA,FRJ23,31140,Saint-Alban,"ZI du Terroir, 27 avenue Léon Jouhaux" +d001860,Landkreis Altenburger Land,DEU,DEG0M,04600,Altenburg,Lindenaustraße 9 +d001861,"Miltenyi Biotec, S. L.",ESP,ES30,28223,Pozuelo de Alarcón (Madrid),"C/ Luis Buñuel, 2" +d001862,Fluxguide Ausstellungssysteme GmbH,AUT,AT130,1070,Wien,Kandlgasse 15/5 +d001863,"Ingeniería, Estudios y Proyectos Europeos, S. L.",ESP,ES30,28944,Fuenlabrada,"Cº de Castilla, 10" +d001864,Vrånghults Ägg,SWE,SE232,531 97,Lidköping,Örslösa Källstorp 187 +d001865,Communauté d'agglomération Lens-Liévin,FRA,FRE12,62302,Lens Cedex,Rue Marcel-Sembat +d001866,Železnice Slovenskej republiky,SVK,SK,813 61,Bratislava-mestská časť Staré Mesto,Klemensova 8 +d001867,"ECOLAB podjetje za proizvodnjo pralnih sredstev in drugih kemičnih proizvodov, trgovino in storitve d.o.o.",SVN,SI,2000,Maribor,Vajngerlova ulica 4 +d001868,"Technische Universität Ilmenau, Dezernat Finanzen, SG Beschaffung",DEU,DEG0F,98693,Ilmenau,Max-Planck-Ring 14 +d001869,"Palma, Mednarodno turistično podjetje, d.o.o., Celje",SVN,SI,3000,Celje,Lilekova ulica 5 +d001870,Kauniaisten kaupunki,FIN,FI1B1,,Kauniainen, +d001871,Hrvatski Telekom d.d.,HRV,HR,10000,Zagreb,Radnička cesta 21 +d001872,Commune de Bastia,FRA,FRM,20410,Bastia,avenue Pierre Giudicelli +d001873,Octapharma AG,CHE,CH,8853,Lachen,Seidenstrasse 2 +d001874,Orifarm GmbH,DEU,DE,,Leverkusen, +d001875,Gemeente Brielle,NLD,NL,3231 AP,Brielle,Slagveld 36 +d001876,Baromed Kereskedelmi és Szolgáltató Kft,HUN,HU321,1064,Budapest,Székely Bertalan utca 10. 3/40. +d001877,"Ditcom, s.r.o.",CZE,CZ010,140 00,Praha 4, +d001878,Stadt Straubing,DEU,DE223,94315,Straubing,Theresienplatz 2 +d001879,"OHL Servicios Ingesan, S. A.",ESP,ES511,,Cornellà de Llobregat, +d001880,Hasenkamp Internationale Transporte GmbH,DEU,DE300,50226,Frechen, +d001881,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001882,Lehnert GmbH,DEU,DE721,35463,Fernwald,Ruhberg 11 +d001883,Tempo-Team Group,NLD,NL,,Diemen, +d001884,Elektro Toni d.o.o.,HRV,HR0,22000,Šibenik,Daska 92 +d001885,Préli,FRA,FR1,,Le Plessis-Trévise, +d001886,St. Martini Krankenhaus in Duderstadt,DEU,DE929,37115,Duderstadt,Göttinger Straße 34 +d001887,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d001888,Centre hospitalier de Valence,FRA,FRK23,26953,Valence,"179 boulevard Maréchal-Juin, Direction achats, travaux, logistique" +d001889,Österreichische Bundesforste AG,AUT,AT,3002,Purkersdorf,Pummergasse 10-12 +d001890,medika Medizintechnik GmbH,DEU,DE244,95032,Hof, +d001891,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4b +d001892,Kommunales Vergabezentrum Kreis Groß-Gerau für Kreis Groß-Gerau,DEU,DE717,64521,Groß-Gerau,Wilhelm-Seipp-Str. 4 +d001893,Ruokolahden Vanhustentaloyhdistys ry,FIN,FI,,Ruokolahti, +d001894,Legallais,FRA,FRD11,14200,Hérouville-Saint-Clair,7 rue d'Atalante +d001895,JASP (mandataire),FRA,FRK26,69100,Villeurbanne,88 rue d'Alsace +d001896,Gold Medical Kft.,HUN,HU110,1221,Budapest,Hasadék utca 22. B. ép. +d001897,Subsecretaría - Consellería de Hacienda y Modelo Económico,ESP,ES523,46003,Valencia,"C/ Palau, 12" +d001898,ABM Catering Ltd,GBR,UKG13,CV34 4AF,Warwick,"Eagle Court, Saltisford" +d001899,"Consejería de Agricultura, Desarrollo Rural, Población y Territorio",ESP,ES431,06800,Mérida,"Avenida Luis Ramallo, s/n" +d001900,O2 Czech Republic a.s.,CZE,CZ,140 22,Praha 4–Michle,Za Brumlovkou 266/2 +d001901,PP Solutions GmbH & Co. KG,DEU,DE72,35418,Buseck,Fischbach 15 +d001902,Universität Bielefeld,DEU,DEA41,33615,Bielefeld,Universitätsstraße 25 +d001903,Dynacite — OPH de l'Ain,FRA,FRK21,01013,Bourg-en-Bresse cedex,390 boulevard du 8 Mai 1945 +d001904,Novello SAS,FRA,FRH02,29413,Landerneau Cedex,"ZI Saint-Éloi Plouedern, BP 33" +d001905,"SANOLABOR, podjetje za prodajo medicinskih, laboratorijskih in farmacevtskih proizvodov, d.d.",SVN,SI,1000,Ljubljana,Leskoškova cesta 4 +d001906,Sotsiaalkindlustusamet,EST,EE,10617,Tallinn,Paldiski mnt 80 +d001907,Dell SAS,FRA,FRJ13,34938,Montpellier Cedex 9,1 rond-point Benjamin-Franklin +d001908,Junta de Gobierno del Ayuntamiento de Málaga,ESP,ES617,29016,Málaga,"Avenida de Cervantes, 4" +d001909,PreZero Service Centrum Sp. z o.o.,POL,PL712,99-300,Kutno,ul. Łąkoszyńska 127 +d001910,Direction départementale des territoires (DDT) — Rhône,FRA,FRK,69003,Lyon,direction départementale des territoires (DDT) — Rhône — Service bâtiment durable et accessibilité (SBDA) — unité Assistance et maîtrise d'ouvrage en bâtiment (AMOB) 165 rue Garibaldi — CS 33862 69401 Lyon Cedex 03 +d001911,Arcadis ESG,FRA,FR,75014,Paris,200-216 rue Raymond Losserand +d001912,Redlich Haus- und Freizeittechnik GmbH & Co. KG,DEU,DEE07,39345,Bülstringen OT Wieglitz,Pfingstbusch 2 +d001913,"Elinkeino-, liikenne- ja ympäristökeskus",FIN,FI,FI-33100,Tampere,Yliopistonkatu 38 +d001914,PGF S.A.,POL,PL,91-342,Łódź,ul. Zbąszyńska 3 +d001915,Unomed spol. s r. o. Unomed GmbH. - v jazyku nemeckom Unomed Ltd. - v jazyku anglickom,SVK,SK022,911 01,Trenčín,Zlatovská 2211 +d001916,Bildungswerk der Niedersächsischen Wirtschaft gemeinnützige GmbH,DEU,DE,30163,Hannover,Höfestr. 19-21 +d001917,Education Procurement Service (EPS),IRL,IE,Co. Limerick,Castletroy,University of Limerick +d001918,Deutsche Post InHaus Services GmbH,DEU,DEA22,53121,Bonn, +d001919,Stichting IEA Secretariaat Nederland,NLD,NL,,Amsterdam, +d001920,Lernen fördern e. V.,DEU,DEA37,49477,Ibbenbüren, +d001921,Adecco Industrial Flex Solutions bv,NLD,NL,,Zaltbommel, +d001922,Total Marketing France,FRA,FR,92000,Nanterre,562 avenue du Parc de l’Île +d001923,Commune de Pimprez,FRA,FRE22,60170,Pimprez,rue de l'Église +d001924,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d001925,Oktal Pharma d.o.o.,HRV,HR050,10020,Zagreb,Utinjska 40 +d001926,Velde AS,NOR,NO0A1,4308,Sandnes,Noredalsveien 294 +d001927,Unipolsai assicurazioni SpA,ITA,ITH55,,Bologna, +d001928,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4 b +d001929,Design & Build,FRA,FRG05,85101,Les Herbiers,"29 avenue des Sables, CS 10117" +d001930,Gherardi Construction SAS,FRA,FRF12,68120,Richwiller,1 route de Kingersheim +d001931,Getica 95 Com S.R.L.,ROU,RO222,125300,Râmnicu Sărat,"Strada, Nr." +d001932,Tallinna Tehnikaülikool,EST,EE,19086,Tallinn,Ehitajate tee 5 +d001933,Servicefirmaet Renell A/S,DNK,DK013,3000,Helsingør, +d001934,Sictom Sud Allier,FRA,FRK11,03500,Bayet,10 rue les Bouillots +d001935,Trenitalia SpA,ITA,ITI43,00161,Roma,piazza della Croce Rossa 1 +d001936,Institut Curie,FRA,FR10,75005,Paris,26 rue d'Ulm +d001937,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d001938,SRM Medical,ROU,RO321,050566,București,Str. Pretorienilor nr. 6 +d001939,SMACL,FRA,FRH,79031,Niort,141 rue Salvador Allende +d001940,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d001941,Maandag Interim Professionals bv,NLD,NL329,1014 AK,Amsterdam,Transformatorweg 94 +d001942,Valtex & Co. trgovina in zastopstva d.o.o.,SVN,SI,1000,Ljubljana,Koprska ulica 62A +d001943,Gemeente Zoetermeer,NLD,NL,,Zoetermeer, +d001944,Trebbe Bouw bv,NLD,NL,8000 AG,Zwolle,Postbus 250 +d001945,Remiks Husholdning AS,NOR,NO074,9018,Tromsø,Ringvegen 180 +d001946,Meddtl,FRA,FR1,92055,La Défense Cedex,grande arche — Paroi Sud +d001947,Mayenne communauté,FRA,FRG03,53103,Mayenne Cedex,"10 rue de Verdun, CS 60111" +d001948,Bundesagentur für Arbeit Regionales Einkaufszentrum Nord,DEU,DE,30147,Hannover,Postfach +d001949,Kalmar läns landsting,SWE,SE213,392 44,Kalmar,Sjöbrings väg 4A plan 2 +d001950,Weatherford Atlas GIP S.A.,ROU,RO,100189,Ploiești,Str. Clopoței nr. 2A +d001951,"Makom Trgovina, d.o.o.",SVN,SI,3320,Velenje,Koroška cesta 64 +d001952,Kemp Schalkwijk bv,NLD,NL,3998 WJ,Schalkwijk,Neereind 33 +d001953,Göteborgs Stads Bostads AB,SWE,SE232,402 21,Göteborg,Box 5044 +d001954,Mesto Pezinok,SVK,SK010,902 14,Pezinok,Radničné nám. 7 +d001955,"MM interier, s.r.o.",SVK,SK,028 01,Brezovica,Niže Vsi 413/9 +d001956,Guarda Nacional Republicana — Direcção de Recursos Logísticos — Divisão de Aquisições,PRT,PT,1149-064,Lisboa,"Rua Cruz de Santa Apolónia, 16" +d001957,Fliesen und Natursteine Kubitscheck,DEU,DE225,94545 Hohenau,Schönbrunnerhäuser 814, +d001958,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d001959,"Universitäts- und Hansestadt Greifswald, Der Oberbürgermeister, Stadtbauamt, Abt. Bauverwaltung",DEU,DE80N,17489,Greifswald,Markt 15 +d001960,Jihomoravský kraj,CZE,CZ064,602 00,Brno,Žerotínovo náměstí 449/3 +d001961,Relico Oy,FIN,FI1C1,,Turku, +d001962,KOMPAS Turistično podjetje d.d.,SVN,SI,1000,Ljubljana,Dunajska cesta 117 +d001963,Conpat Scarl,ITA,ITI43,,Roma, +d001964,STAO PL Établissement 44,FRA,FRG01,44105,Nantes Cédex 4,"27 boulevard du Maréchal-Alphonse-Juin, CS 30520" +d001965,"Z+M Logistics, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Gorkého 621/26, Moravská Ostrava" +d001966,CHUBB France,FRA,FRF23,51100,Reims,"ZA Sud Est, rue Aloyes Senefelder" +d001967,Ilić-Šumarstvo d.o.o.,HRV,HR,32254,Vrbanja,Ljudevita Gaja 42 +d001968,Katinala Live Oy,FIN,FI1C2,,Katinala, +d001969,Bruker Italia srl unipersonale,ITA,ITC4C,20158,Milano,viale V. Lancetti 43 +d001970,Albert Ziegler GmbH,DEU,DE11C,89537,Giengen/Brenz,Alber-Ziegler Straße 1 +d001971,Bourges Julie,FRA,FR101,75020,Paris,5 rue Ligner +d001972,France télévisions,FRA,FR,75907,Paris Cedex 15,7 esplanade Henri de France +d001973,bioMerieux Polska sp. z o.o.,POL,PL911,01-518,Warszawa,ul. generała Józefa Zajączka 9 +d001974,Department of Contracts,MLT,MT,FRN 1600,Floriana,Notre Dame Ravelin +d001975,Taksi J.Suviranta,FIN,FI1D3,FI-80170,Joensuu,Ahvenentie 23 c 5 +d001976,Ministrstvo za zdravje,SVN,SI,1000,Ljubljana,Štefanova ulica 5 +d001977,Association Diapason,FRA,FRG05,85600,Montaigu-Vendée,"13 rue des Ajoncs, Boufféré" +d001978,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d001979,Servelect S.R.L.,ROU,RO113,400573,Cluj-Napoca,Str. Teleorman nr. 23 +d001980,"Kastor - Medical Dental podjetje za veleprodajo, zastopanje, inženiring in zunanjo trgovino, Ljubljana, Vošnjakova 6",SVN,SI,1000,Ljubljana,Vošnjakova ulica 6 +d001981,Proprette s.r.o.,CZE,CZ,190 00,Praha,Zásadská 569/3 +d001982,"Presidencia de la Agencia Estatal Consejo Superior de Investigaciones Científicas, M. P.",ESP,ES300,28006,Madrid,"C/ Serrano, 117" +d001983,Administrația Prezidențială,ROU,RO321,76258,Bucureşti,Str. Cotroceni nr. 1 +d001984,Steber-Tours GmbH,DEU,DE27C,,Mindelheim, +d001985,"Empresa Municipal de Mobilidade e Estacionamento de Lisboa (EMEL), E. M., S. A.",PRT,PT,1750-150,Lisboa,"Alameda das Linhas de Torres, 198-200" +d001986,Gemeente Wassenaar,NLD,NL,,Wassenaar, +d001987,Občina Bistrica ob Sotli,SVN,SI,3256,Bistrica ob Sotli,Bistrica ob Sotli 17 +d001988,ALS Finland Oy,FIN,FI1D3,,Outokumpu, +d001989,De LOCHTING vzw,BEL,BE,8800,Roeselare,Oude Stadenstraat 15 +d001990,Gemeente Maassluis,NLD,NL,,Maassluis, +d001991,"Land Hessen, vertreten durch das Hessische Competence Center -Zentrale Beschaffung-",DEU,DE7,65203,Wiesbaden,Rheingaustraße 186 +d001992,GARB družinsko grafično podjetje d.o.o.,SVN,SI,2211,Pesnica pri Mariboru,Dolnja Počehova 14F +d001993,"Infraestruturas de Portugal, S. A.",PRT,PT170,2809-013,Almada,"Praça da Portagem, Almada" +d001994,Le Syndicat des eaux du bassin de l'Ardèche,FRA,FRK22,07200,Largentière, +d001995,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d001996,UAB „B. Braun Medical“,LTU,LT,LT-05132,Vilnius,Viršuliškių skg. 34-1 +d001997,AIG Europe SA rappresentanza per l'Italia,LUX,LU0,,Lussemburgo, +d001998,OTE ingénierie,FRA,FR104,67403,Illkirch,1 rue de la Lisière +d001999,"Česká pošta, s.p.",CZE,CZ01,225 99,Praha 1,Politických vězňů 909/4 +d002000,Electroechipament,ROU,RO422,325300,Bocșa,Str. Bichistin nr. 37 +d002001,Paranova Pack A/S,DNK,DK,,Herlev, +d002002,Accord Healthcare Italia,ITA,ITC4C,,Milano, +d002003,Fujitsu Technology Solutions,DEU,DE254,90451,Nürnberg,Colmberger Str. 2 +d002004,S & T Plus s.r.o.,CZE,CZ,142 00,Praha,Novodvorská 994/138 +d002005,"Anmedic, družba za trgovino s profesionalno medicinsko opremo in pripomočki, d.o.o.",SVN,SI,1000,Ljubljana,Šmartinska cesta 53 +d002006,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d002007,Automaten Terres,DEU,DEB25,,Hockweiler, +d002008,Gemi Center S.R.L.,ROU,RO421,310328,Arad,Str. N. Titulescu nr. 7 +d002009,„Sungrant Sp. z o.o.”,POL,PL841,15-542,Białystok,ul. Ciesielska 2/23 +d002010,Gemeente Midden-Delfland,NLD,NL,,Schipluiden, +d002011,UMO Sp. z o.o.,POL,PL,05-220,Zielonka,ul. Henryka Sienkiewicza 61 +d002012,Gold Medical Kft.,HUN,HU110,1221,Budapest,Hasadék utca 22. B. ép. +d002013,"Continental Obras y Mantenimiento, S. L.",ESP,ES620,,Cartagena, +d002014,Kuepper-Weisser GmbH,DEU,DE136,,Bräunlingen, +d002015,Centro Social Paroquial de São Tiago de Urra,PRT,PT186,7300-570,São Tiago de Urra,"Largo da Igreja, 18" +d002016,VšĮ Vilniaus Gedimino technikos universitetas,LTU,LT,,Vilnius, +d002017,GBLT,NLD,NL,801JZ,Zwolle,Lubeckplein 2 +d002018,Artélia,FRA,FR107,94600,Choisy-le-Roi Cedex,"département Eau & Génie urbain, 47 avenue de Lugo" +d002019,Mindef/Armée de l'air/SAGF/SSAM 33 504,FRA,FRI12,33068,Bordeaux Cedex,"Détachement Air 204, Beauséjour, CS 21152" +d002020,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002021,Hera SpA,ITA,ITH55,40127,Bologna,viale Carlo Berti Pichat 2/4 +d002022,Allianz IARD,FRA,FRY10,97185,Jarry Cedex,ZAC de Houelbourg Sud — BP 2458 +d002023,"Diagnóstica Longwood, S. L.",ESP,ES,,No especificado, +d002024,Ormco BV,NLD,NL,3821BR,Amersfoort,Basicweg 20 +d002025,Grupa Azoty Zakłady Chemiczne Police S.A.,POL,PL42,72-010,Police,ul. KUźnicka 1 +d002026,Charité Universitätsmedizin Berlin,DEU,DE300,10117,Berlin,Charitéplatz 1 +d002027,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d002028,Klinički bolnički centar Zagreb,HRV,HR050,10000,Zagreb,Kišpatićeva 12 +d002029,LB Elektro- und Verkehrsanlagenbau GmbH & Co.KG,DEU,DE229,94253,Bischofsmais,Gewerbepark 11 +d002030,Riigi Tugiteenuste Keskus,EST,EE,10122,Tallinn,Lõkke tn 4 +d002031,Presidencia de la Diputación Provincial de Cuenca,ESP,ES423,16001,Cuenca,"C/ Aguirre, 1" +d002032,Tallinna Tehnikaülikool,EST,EE,19086,Tallinn,Ehitajate tee 5 +d002033,Gruhl & Kunze Gebäudemanagement GmbH,DEU,DE731,34117,Kassel,Weißenburgstraße 10 +d002034,SEDA,FRA,FRE21,02007,Laon Cedex,"Pôle d'activités du Griffon, 10 rue Pierre Gilles de Gennes, CS 10658" +d002035,Talián Bálint Attila,HUN,HU232,7562,Segesd,Pálmaház utca 1. +d002036,LRA Dingolfing-Landau,DEU,DE22C,84130,Dingolfing,Obere Stadt 1 +d002037,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d002038,"Securitas Seguridad España, S. A.",ESP,ES,28051,Madrid,"C/ Entrepeñas, 27" +d002039,Wissenschaftsstadt Darmstadt — Der Magistrat,DEU,DE711,64283,Darmstadt,Luisenplatz 5a +d002040,Unipolsai assicurazioni SpA,ITA,ITH55,,Bologna, +d002041,Alexis Dansette SARL,FRA,FR,,Villenoy, +d002042,OÜ Nelijakk,EST,EE,63306,Põlva vald,Võru tn 4 +d002043,Commissariat à l'énergie atomique et aux énergies alternatives,FRA,FR,91191,Gif-sur-Yvette Cedex,CEA Paris Saclay — bâtiment 482 — PC nº 70 +d002044,SAS Kabelis,FRA,FR,29610,Plouigneau, +d002045,Ministrstvo za notranje zadeve,SVN,SI041,1000,Ljubljana,Štefanova ulica 2 +d002046,"Sanolabor, podjetje za prodajo medicinskih, laboratorijskih in farmacevtskih proizvodov, d.d.",SVN,SI,1000,Ljubljana,Leskoškova cesta 4 +d002047,Pohjois-Karjalan hankintatoimi,FIN,FI1D3,FI-80110,Joensuu,Linnunlahdentie 2 +d002048,"Extra Lux, proizvodno in trgovsko podjetje d.o.o., Ljubljana",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 17B +d002049,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d002050,UTE Avantía — Inteec,ESP,ES612,,Cádiz, +d002051,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d002052,Taksipalvelu M. Lappalainen Oy,FIN,FI1D3,FI-80400,Ylämylly,Kuoringantie 32 +d002053,Rostislav Chládek,CZE,CZ064,669 02,Znojmo,Lužická 2433/14 +d002054,Mladinska knjiga Trgovina d.o.o.,SVN,SI,1000,Ljubljana,Slovenska cesta 29 +d002055,Wiener Gesundheitsverbund – Serviceeinheit Einkauf (SEE),AUT,AT130,1110,Wien,"Guglgasse 17, 2. OG" +d002056,Občina Braslovče,SVN,SI,3314,Braslovče,Braslovče 22 +d002057,Aliud Pharma GmbH,DEU,DE,,Laichingen, +d002058,Gemeente Brielle,NLD,NL,,Brielle, +d002059,Vestland fylkeskommune,NOR,NO0A,5020,Bergen,Postboks 7900 +d002060,Università degli studi di Roma «La Sapienza» — Dipartimento di scienze biochimiche «A. Rossi Fanelli»,ITA,ITI43,00185,Roma,p.le Aldo Moro 5 +d002061,SAS Igetec (cotraitant),FRA,FRK12,15000,Aurillac,5 rue Georges-Pompidou +d002062,Holzfällung Hausbacher,AUT,AT32,5600,St. Johann im Pongau,Hallmoos 22 +d002063,Jan Håkansson Byggplanering Aktiebolag,SWE,SE232,431 49,Mölndal,Alfagatan 20 +d002064,SCI Docks en Seine,FRA,FR101,75013,Paris,"34 quai d'Austerlitz, 26 quai d'Austerlitz" +d002065,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d002066,Česká republika – Úřad vlády České republiky,CZE,CZ01,118 01,Praha 1,nábřeží Edvarda Beneše 128/4 +d002067,Telecom Italia SpA,ITA,ITC4C,,Milano (MI), +d002068,UAB „Gitana“,LTU,LT,LT-96320,Klaipėda,"Bičiulių g. 32, Budrikų k." +d002069,Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung Einkauf und Gerätewirtschaft C 2 — Vergabestelle Bau,DEU,DE212,80686,München,Hansastraße 28 +d002070,OP Security,CZE,CZ064,602 00,Brno,Kpt. Jaroše 1927/8 +d002071,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d002072,Österreichische Postbus AG,AUT,AT,,Wien, +d002073,"Medtronic Ibérica, S. A.",ESP,ES3,,Madrid,28050 +d002074,Ferrocarriles de la Generalidad de Cataluña,ESP,ES511,08017,Barcelona,"C/ de los Vergós, 44" +d002075,Strängnäs kommun,SWE,SE122,645 80,Strängnäs,Nygatan 10 +d002076,Ajuntament de Granollers,ESP,ES511,08401,Granollers,"Plaça Porxada, 6" +d002077,Albert Ziegler GmbH,DEU,DE11C,89537,Giengen/Brenz,Alber-Ziegler Straße 1 +d002078,Biomedis M.B. trgovina d.o.o.,SVN,SI,2000,Maribor,Jurančičeva ulica 11 +d002079,Aamodt Bygg AS,NOR,NO092,4642,Søgne,Østre Lohnelier 65 +d002080,UTE Auna-Arquican-Corviola,ESP,ES705,35200,Telde,"C/ Diego Soprani y Ponce de León, 5, 2.º derecha" +d002081,Universität Wien,AUT,AT,1010,Wien,Universitätsring 1 +d002082,"Eulen, S. A.",ESP,ES300,,Madrid, +d002083,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d002084,Medirest,FRA,FR101,,Châtillon, +d002085,OPCO Atlas,FRA,FR101,75013,Paris,25 quai Panhard et Levassor +d002086,Eos cooperativa sociale,ITA,ITH34,31033,Castelfranco Veneto,via Ospedale10 +d002087,Imprimerie Chauveau,FRA,FRB02,28630,Gellainville, +d002088,Klinikum rechts der Isar der TU,DEU,DE212,81675,München,Ismaninger Str. 22 +d002089,Alta kommune,NOR,NO074,9506,Alta,Postboks 1403 +d002090,Macofil,ROU,RO412,210001,Târgu Jiu,Str. Bârsești nr. 217 +d002091,Invibio Consulting,ROU,RO213,700020,Iași,Str. Anastasie Panu nr. 42 +d002092,Ville de Jeumont,FRA,FRE11,59460,Jeumont,boulevard de Lessines +d002093,IKK classic,DEU,DE,01099,Dresden, +d002094,Firma Intuitive Surgical Deutschland GmbH,DEU,DE131,79108,Freiburg,Am Flughafen 6 +d002095,Forschungszentrum Jülich GmbH — Projektträger Jülich,DEU,DEA26,52428,Jülich,Wilhelm-Johnen-Straße +d002096,B. Braun Medical,ROU,RO424,,Sânandrei,Str. Bernd Braun nr. 1 +d002097,"Land Hessen, vertreten durch das Hessische Competence Center – Zentrale Beschaffung",DEU,DE7,65203,Wiesbaden,Rheingaustraße 186 +d002098,OÜ Nelijakk,EST,EE,63306,Põlva vald,Võru tn 4 +d002099,Frederiksberg Kommune,DNK,DK01,2000,Frederiksberg,Frederiksberg Rådhus +d002100,Bane NOR Eiendom AS,NOR,NO0,0048,Oslo,Postboks 1800 Sentrum +d002101,Marktgemeinde Gramatneusiedl,AUT,AT12,2440,Gramatneusiedl,Bahnstraße 2 a +d002102,STP Brindisi SpA,ITA,ITF44,72100,Brindisi,SS 613 N.246 Z.I. C.da Piccoli +d002103,AFRY Finland Oy,FIN,FI1B1,,Vantaa, +d002104,Impresa Devi impianti srl,ITA,ITC41,,Busto Arsizio, +d002105,"Italcomma Slovakia, s.r.o.",SVK,SK,010 01,Žilina,Dolné Rudiny 1 +d002106,Elips life ltd,LIE,LI000,,Vaduz, +d002107,axicorp Pharma B. V.,NLD,NL,,Den Haag, +d002108,Hochschule Düsseldorf,DEU,DEA11,40476,Düsseldorf,Münsterstr. 156 +d002109,Pula Herculanea d.o.o. za obavljanje komunalnih djelatnosti,HRV,HR036,52100,Pula,Trg I. istarske brigade 14 +d002110,"Baza de Aprovizionare, Gospodărire și Reparații",ROU,RO322,077120,Jilava,Str. Sabarului nr. 1 +d002111,Tredje Natur ApS,DNK,DK,2200,København N,"Heimdalsgade 35, baghuset 4. sal" +d002112,Zuglói Városgazdálkodási Közszolgáltató Zártkörűen Működő Részvénytársaság,HUN,HU110,1145,Budapest,Pétervárad utca 11–17. +d002113,A. Kyllönen Oy,FIN,FI1D8,,Kuhmo, +d002114,OSAKIDETZA — Servicio Vasco de Salud — Organización Sanitaria Integrada Goierri-Alto Urola,ESP,ES21,,Zumarraga, +d002115,Ajuntament de Cambrils,ESP,ES,43850,Cambrils,"Plaça Ajuntament, 4" +d002116,Rijkswaterstaat,NLD,NL,3526 LA,Utrecht,Griffioenlaan 2 +d002117,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d002118,Peugeot,FRA,FRL05,,Brignoles, +d002119,Srijem d.o.o.,HRV,HR,31000,Osijek,Vilajska 6 +d002120,Eigenbetrieb „Kommunale Objektbewirtschaftung und -entwicklung der Hanse- und Universitätsstadt Rostock“,DEU,DE803,18057,Rostock,Ulmenstr. 44 +d002121,CH de Villefranche-sur-Saône,FRA,FRK26,69655,Villefranche-sur-Saône,BP 80436 +d002122,Siemens Financial Services,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d002123,Matthias Disch Malerfachbetrieb GmbH,DEU,DE132,79238,Ehrenkirchen,Kreuzgartenstr. 15 +d002124,"Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle",DEU,DED41,09111,Chemnitz,Friedensplatz 1 +d002125,Niebuhr Stahlglastechnik GmbH,DEU,DEE04,39638,Gardelegen, +d002126,Stadtverwaltung Schorndorf – Fachbereich Gebäudemanagement,DEU,DE116,73614,Schorndorf,Karlstraße 3 +d002127,SPL Midi-Pyrénées Construction,FRA,FRJ23,31086,Toulouse Cedex 2,"Mandataire agissant au nom et pour le compte de la région Occitanie représentée par la présidente de la région Occitanie Pyrénées Méditerranée, Mme Carole Delga, 11 avenue Parmentier, Central Parc 2, 4e étage, BP 22414" +d002128,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d002129,Comune di Perugia — S.O. contratti e semplificazione — Vicesegretario,ITA,ITI21,06121,Perugia,corso Vannucci 19 +d002130,Medical Ortovit,ROU,RO321,011098,București,"Str. Miron Costin nr. 8, sector 1" +d002131,Somogy Megyei Szeretet Szociális Otthon,HUN,HU232,7516,Berzence,Szabadság tér 1/3. +d002132,"Phoenix lékárenský velkoobchod, s.r.o.",CZE,CZ01,102 00,Praha 10,K pérovně 945/7 +d002133,Gemeente Zoetermeer,NLD,NL,2711 EB,Zoetermeer,Engelandlaan 502 +d002134,Javno podjetje Komunala Brežice d.o.o.,SVN,SI,8250,Brežice,Cesta bratov Milavcev 42 +d002135,Monetăria Statului,ROU,RO321,050183,Bucureşti,Str. Fabrica de Chibrituri nr. 30 +d002136,Perfekta Dienstleistungen und Gebäudereinigung GmbH,DEU,DE929,,Langenhagen, +d002137,Tallinna Linnavaraamet,EST,EE,10146,Tallinn,Vabaduse väljak 10 +d002138,Cenzin Sp. z o.o.,POL,PL,00-957,Warszawa,Czerniakowska 81/83 +d002139,Tinmar Energy S.A.,ROU,RO321,014476,București,Str. Floreasca nr. 246C +d002140,Davy Engineering Ltd,GBR,UK,B90 4NE,West Midlands,"Stirling Road, Shirley" +d002141,Kommunalbetrieb Krefeld AöR,DEU,DEA14,47798,Krefeld,Ostwall 175 +d002142,Meopta Systems s.r.o.,CZE,CZ071,750 02,Přerov,Kabelíkova 268/1 +d002143,"Bidasoa Kultur Zerbitzuak, S. L.",ESP,ES213,,Bertizarana, +d002144,Ageval,FRA,FRE11,59300,Valenciennes,230 bis avenue Desandrouin +d002145,CRIO – 2 S.R.L.,ROU,RO213,700397,Iași,Str. Pădurii nr. 6 +d002146,Designfunktion Mittelrhein GmbH,DEU,DEB11,,Koblenz, +d002147,Deurer,DEU,DEB1B,56337,Simmern,Siebenbornstr. 22 +d002148,Gödde GmbH,DEU,DEA23,,Köln, +d002149,Sontex A/S,DNK,DK011,2740,Skovlunde,Skovlunde Byvej 31 +d002150,Energie froid,FRA,FRE12,62490,Vitry-en-Artois,45 route Nationale +d002151,"Kavyl, spol. s r.o.",CZE,CZ063,675 75,Mohelno,Mohelno 452/1 +d002152,Centrex,FRA,FR106,93160,Noisy-le-Grand,2 rue de la butte verte +d002153,"Staatsbetrieb Sächsisches Immobilien- und Baumanagement, Zentrale, SSC VVM, Außenstelle Dresden 1, Zentrale Vergabestelle",DEU,DED2,01099,Dresden,Königsbrücker Str. 80 +d002154,Societatea Complexul Energetic Oltenia S.A.,ROU,RO412,210227,Târgu Jiu,Str. Alexandru Ioan Cuza nr. 5 +d002155,UAB „Vilniaus vystymo kompanija“,LTU,LT,LT-03219,Vilnius,Algirdo g. 19 +d002156,Sogea Guyane,FRA,FRY30,97354,Remire-Montjoly,"32 rue de l'Industrie, PAE Degrad des Cannes" +d002157,Vimmerby bageri och konditori AB,SWE,SE213,,Vimmerby, +d002158,"ČEZ, a.s.",CZE,CZ,140 00,Praha,Duhová 1444/2 +d002159,"Johnson&Johnson, s.r.o.",CZE,CZ010,158 00,Praha 5,Walterovo nám. 329/1 +d002160,Hospital San Juan de Dios de Córdoba,ESP,ES613,14012,Córdoba,"Avenida del Brillante, 106" +d002161,Turun kaupunki / Hyvinvointitoimiala,FIN,FI1C1,FI-20101,Turku,"PL 630 (käyntiosoite: Linnankatu 31, 2. krs)" +d002162,"Securitas Seguridad España, S. A.",ESP,ES300,,Madrid, +d002163,Enmo Nederland bv,NLD,NL,5531 PZ,Bladel,Lange Trekken 46 +d002164,Proleite,PRT,PT,3720-581,Oliveira de Azeméis,Lugar de Adães +d002165,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d002166,Polymétrie,FRA,FRJ28,82230,Monclar-de-Quercy,22 grand rue du 8 Mai 1945 +d002167,Landwirtschaftskammer Niedersachsen,DEU,DE943,26121,Oldenburg,Mars-la-Tour-Str. 1-13 +d002168,Crayon Deutschland GmbH,DEU,DE21H,,Unterhaching, +d002169,GatewayBaltic Ltd,LVA,LV,LV-1010,Riga,Elizabetes iela 51 +d002170,Azienda ospedaliera «Ospedali riuniti Marche Nord»,ITA,ITI31,61121,Pesaro,piazzale Cinelli 4 +d002171,Consiag servizi comuni srl,ITA,ITI1,59100,Prato,via U. Panziera 16 +d002172,NWS Alarmservice GmbH,DEU,DE254,90409,Nürnberg,Fraunhoferstr. 10 +d002173,Oktal Pharma d.o.o.,HRV,HR050,10020,Zagreb,Utinjska 40 +d002174,Gentofte Kommune,DNK,DK,2920,Charlottenlund,Bernstorffsvej 161 +d002175,AERO-TEC d.o.o,HRV,HR,33000,virovitica,poduzetnička zona II/20 +d002176,Elkraft Sverige AB,SWE,SE,126 26,Hägersten,Telefonvägen 30 +d002177,CH Verdun Saint-Mihiel,FRA,FRF32,55100,Verdun,2 rue d'Anthouard +d002178,"L-MED, trgovina z medicinskimi potrebščinami in materiali, d.o.o.",SVN,SI0,2351,Kamnica,Pod vinogradi 45 +d002179,Geaprodukt trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d002180,Landesbetrieb Bau und Immobilien Hessen Niederlassung Mitte Zentrale Vergabe,DEU,DE7,61231,Bad Nauheim,Dieselstraße 1-7 +d002181,"Tegosa Médica, S. L.",ESP,ES425,45519,Novés,"Carretera Portillo a Novés, km 3" +d002182,GECAL SpA,ITA,ITC4C,20037,Paderno Dugnano, +d002183,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d002184,Strabag a.s.,CZE,CZ01,158 00,Praha,Kačírkova 982/4 +d002185,Vicepresidencia y Conselleria de Igualdad y Políticas Inclusivas,ESP,ES523,46018,Valencia,"C/ de la Democracia, 77, Ciudad Administrativa 9 de Octubre, torre 3, 7.ª planta" +d002186,Leithäusl Gesellschaft m. b. H.,AUT,AT,1030,Wien,Neulinggasse 14 +d002187,"Meditrina, družba za trženje medicinskih pripomočkov in opreme d.o.o.",SVN,SI,1000,Ljubljana,Dunajska cesta 199 +d002188,Edenred France SAS,FRA,FR105,92240,Malakoff,166/180 boulevard Gabriel Péri +d002189,Eesti Kaubandus-Tööstuskoda,EST,EE,10130,Tallinn,Toom-Kooli tn 17 +d002190,"Centro Hospitalar Universitário de Lisboa Norte, E. P. E.",PRT,PT170,1649-035,Lisboa,Lisboa +d002191,Deutsche Rentenversicherung Bund Zentraler Einkauf für Bauleistungen,DEU,DE3,10704,Berlin,Ruhrstr. 2 +d002192,Hays AG,DEU,DE712,60322,Frankfurt am Main,An der Welle 3 +d002193,Fagverktøy AS,NOR,NO074,9514,Alta,Humleveien 3 +d002194,Colas Nord Est — Agence de Côte d'Or,FRA,FRC11,21600,Longvic,10 boulevard Eiffel — BP 58 +d002195,"Promedica Praha Group, a.s.",CZE,CZ010,160 00,Praha 6,Juárezova 1071/17 +d002196,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d002197,"Senatsverwaltung für Umwelt, Verkehr und Klimaschutz, Abteilung Tiefbau",DEU,DE300,13355,Berlin,Brunnenstraße 110d-111 +d002198,DRK Rettungs- und Einsatzdienste Düsseldorf gGmbH,DEU,DEA11,40591,Düsseldorf,Kölner Landstraße 169 +d002199,Donauisar Klinikum Deggendorf-Dingolfing-Landau gKU,DEU,DE224,94469,Deggendorf,Perlasberger Str. 41 +d002200,Département de la Seine-Saint-Denis,FRA,FR106,93000,Bobigny,"Hôtel du Département, 3 esplanade Jean-Moulin" +d002201,Santa Casa da Misericórdia de Lisboa,PRT,PTZZZ,1250-264,Lisboa,"Rua das Taipas, 1" +d002202,Stadt Eberswalde,DEU,DE405,16225,Eberswalde,Breite Straße 41-44 +d002203,Stadt Bocholt,DEU,DEA34,46395,Bocholt,Kaiser-Wilhelm-Straße 52-58 +d002204,Közbeszerzési és Ellátási Főigazgatóság,HUN,HU,1135,Budapest,Szabolcs utca 37–43. +d002205,Wien Holding GmbH,AUT,AT13,1010,Wien,Universitätsstraße 11 +d002206,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002207,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d002208,"Makom Trgovina, d.o.o.",SVN,SI,3320,Velenje,Koroška cesta 64 +d002209,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002210,Architectuurbureau DIRK MARTENS bvba,BEL,BE,9750,Zingem,A. Amelotstraat 36 +d002211,Viromed Medical GmbH,DEU,DEF09,25421,Pinneberg,Flensburger Straße 5 +d002212,EPS Vascular AB,SWE,SE224,263 62,Viken,Hamnplanen 24 +d002213,"Ingiopsa Ingeniería, S. L.",ESP,ES,28035,Madrid,"C/ Vicente Jimeno, 20" +d002214,Hamburg Messe und Congress GmbH,DEU,DE600,20357,Hamburg,Messeplatz 1 +d002215,R4 Korjausurakointi Oy,FIN,FI1B1,FI-00380,Helsinki,Valimotie 21 +d002216,Catarina Duarte Rodrigues Antunes,PRT,PT170,,Lisboa, +d002217,Île-de-France mobilités,FRA,FR,75009,Paris,39 bis — 41 rue de Châteaudun +d002218,Bectro Installatietechniek bv,NLD,NL,3812 RE,Amersfoort,Heliumweg 36 +d002219,VA Vision AB,SWE,SE121,746 31,Bålsta,Strandvägen 24 +d002220,"Optima Facility Services, S. L.",ESP,ES511,08940,Conellá de Llobregart (Barcelona),"C/ Treball, 26, polígono industrial Almeda" +d002221,adelphi consult GmbH,DEU,DE300,10559,Berlin, +d002222,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Straße 8 +d002223,"Stadt Ostfildern, Fachbereich 4, Gebäudemanagement",DEU,DE113,73760,Ostfildern,Otto-Vatter-Str. 12 +d002224,Stadt Wolfsburg,DEU,DE913,38440,Wolfsburg,Porschestraße 49 +d002225,Département des Côtes d'Armor,FRA,FRH01,,Saint-Brieuc,9 place du Général de Gaulle +d002226,"CBK Madeira — Corretores de Seguros, S. A.",PRT,PT300,9000-066,Funchal,"Rua da Sé, 40" +d002227,Vrtec Hansa Christiana Andersena,SVN,SI,1000,Ljubljana,Rašiška ulica 7 +d002228,Service urbain cotraitant,FRA,FRB02,28240,La Loupe,11 bis avenue de Beauce +d002229,GatewayBaltic Ltd,LVA,LV,LV-1010,Riga,Elizabetes iela 51 +d002230,Metall & Stahlbau Schmickler GmbH & Co. KG,DEU,DEB12,53424,Remagen,Konrad-Zuse-Ring 15 +d002231,"Bormia, trgovina in storitve, d.o.o.",SVN,SI,5270,Ajdovščina,Mirce 14 +d002232,Engron GmbH,DEU,DE409,,Bad Freienwalde, +d002233,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d002234,Luxiris,FRA,FR,75019,Paris,157 boulevard Macdonald +d002235,"TUU — Building Design Management, Lda.",PRT,PT,3030-199,Coimbra,Coimbra +d002236,Universitatea din Craiova,ROU,RO411,200585,Craiova,Str. A.I. Cuza nr. 13 +d002237,M3 Bygg AB,SWE,SE110,141 75,Kungens Kurva,Dialoggatan 1 +d002238,Krypton Chemists Ltd,MLT,MT,,Naxxar [In-Naxxar],"Cantrija Complex, Triq It-Targa, Maghtab," +d002239,Sor Libchavy spol. s r.o.,CZE,CZ,561 16,Libchavy,Dolní Libchavy 48 +d002240,Liseberg AB,SWE,SE232,,Göteborg, +d002241,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d002242,Verkehrsgesellschaft Kirchweihtal GmbH,DEU,DE272,,Kaufbeuren, +d002243,Hôpital fondation Rothschild,FRA,FR101,75019,Paris,29 rue Manin +d002244,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d002245,Berg&Dahl arkitektur och projektering AB,SWE,SE224,211 25,Malmö,S.t Gertrudsgatan 3 +d002246,Országos Mentőszolgálat,HUN,HU,1055,Budapest,Markó utca 22. +d002247,Mark Medical trgovina in storitve d.o.o.,SVN,SI,6210,Sežana,Partizanska cesta 109 +d002248,Insight Enterprises Netherlands bv,NLD,NL,1014 BA,Amsterdam,Kabelweg 37 +d002249,"Paul Hartmann Adriatic, družba za medicinske proizvode in storitve na področju preventive, diagnostike, higiene in zdravstvene oskrbe d.o.o.",SVN,SI,1000,Ljubljana,Letališka cesta 3C +d002250,"Calmell, S. A.",ESP,ES511,,Barcelona, +d002251,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002252,"WEMS Consulting, Trading & Service GmbH",AUT,AT,1190,Wien,Billrothstraße 58 +d002253,Viabus,FRA,FR102,77470,Poincy,31/33 avenue de Meaux +d002254,Webbit srl,ITA,ITC4C,,Trezzano s/Naviglio, +d002255,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d002256,Weatherford Atlas GIP S.A.,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2A +d002257,"Timed, s.r.o.",SVK,SK01,821 01,Bratislava,Trnavská cesta 112 +d002258,Inter Koop družba za trgovino in proizvodnjo d.o.o.,SVN,SI,2000,Maribor,Zrkovska cesta 97 +d002259,Fresenius Kabi România,ROU,RO122,,Ghimbav,Str. Henri Coanda nr. 2 +d002260,Università degli studi di Milano — Bicocca,ITA,ITC4C,20126,Milano,piazza dell'Ateneo Nuovo 1 +d002261,"CYMI Seguridad, S. A.",ESP,ES,28050,Madrid,"Avenida Manoteras, 26, 4.ª planta" +d002262,"Medis, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d002263,AB „LTG Cargo“,LTU,LT,LT-02100,Vilnius,Geležinkelio g. 12 +d002264,ENGIE Infra & Mobility bv,NLD,NL,,Dordrecht, +d002265,"Z+M Logistics, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Gorkého 621/26, Moravská Ostrava" +d002266,Sarre et Moselle,FRA,FRF11,57400,Strasbourg,17 avenue Poincaré — CS 80045 +d002267,Medi-Tech GmbH,DEU,DE21B,,Eching, +d002268,Vermögen und Bau Baden-Württemberg Amt Karlsruhe,DEU,DE122,76131,Karlsruhe,Engesserstraße 1 +d002269,Lietuvos kariuomenės Logistikos valdybos Įgulų aptarnavimo tarnyba,LTU,LT,LT-03215,Vilnius,Mindaugo g. 26 +d002270,RATP,FRA,FR101,75599,Paris,LAC B916 — 54 quai de la Râpée +d002271,Alliance Healthcare România,ROU,RO321,060859,București,Str. Amilcar C. Săndulescu nr. 7 +d002272,"Nomago, storitve mobilnosti in potovanj, d.o.o.",SVN,SI,1000,Ljubljana,Vošnjakova ulica 3 +d002273,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d002274,ADX groupe,FRA,FRC14,53200,Chateau-Gontier, +d002275,Olympus Sverige AB,SWE,SE125,171 23,Solna,Box 1816 +d002276,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d002277,Ville de Buc,FRA,FR103,78530,Buc,3 rue des Frères Robin +d002278,"HUM - MED, svetovanje in trgovina, d.o.o.",SVN,SI,1210,Ljubljana - Šentvid,Plemljeva ulica 8 +d002279,Usługi Leśne – Budowlane Krystian Wenta,POL,PL636,84-311,Popowo,Popowo 5A +d002280,Patent- och registreringsverket,SWE,SE,102 42,Stockholm,Box 5055 +d002281,Sontex A/S,DNK,DK011,2740,Skovlunde,Skovlunde Byvej 31 +d002282,Alcaldía del Ayuntamiento de Chipiona,ESP,ES612,11550,Chipiona,"Plaza de Andalucía, s/n" +d002283,Mankkaan Taksi Oy,FIN,FI1B1,,Helsinki, +d002284,Poste italiane,ITA,IT,,Roma, +d002285,Netz16 GmbH,DEU,DE271,86157,Augsburg,Pröllstr. 17 +d002286,"PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d002287,Pigeon TP,FRA,FR,35370,Argentré-du-Plessis, +d002288,Gemeinde Ganderkesee – Die Bürgermeisterin,DEU,DE94D,27777,Ganderkesee,Mühlenstraße 2-4 +d002289,Landkreis Lichtenfels,DEU,DE24C,96215,Lichtenfels,Kronacher Straße 28-30 +d002290,Zakład Usług Leśnych Jodła Jan Doroszkiewicz,POL,PL84,16-315,Lipsk,Krasne 63 +d002291,"Roza Medical, prodaja medicinskih pripomočkov, d.o.o.",SVN,SI,1000,Ljubljana,Ulica bratov Bezlajev 67 +d002292,ratiopharm GmbH,DEU,DE,,Ulm, +d002293,Stadtverwaltung Balingen,DEU,DE143,72336,Balingen,Neue Straße 31 +d002294,Made bv,BEL,BE,2600,Antwerpen,Klokstraat 12A +d002295,Stadt Bad Salzuflen,DEU,DEA45,32105,Bad Salzuflen,Rudolph-Brandes-Allee 19 +d002296,Società regionale per la sanità (SoReSa SpA),ITA,ITF33,80143,Napoli,Centro direzionale Isola F9 +d002297,"Centrale unica di committenza dei Comuni di Comacchio, Codigoro, Fiscaglia, Goro, Jolanda di Savoia, Lagosanto, Mesola, ASP del Delta ferrarese per conto del Comune di Comacchio",ITA,ITH56,44022,Comacchio,piazza Folegatti 15 +d002298,BT Italia SpA,ITA,ITC4C,,Milano (MI), +d002299,Oracle,ITA,IT,,Roma, +d002300,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d002301,Denkmalbau GmbH Ettersburg,DEU,DEG0G,99439,Ettersburg,Im Zweibuchenfelde 6 +d002302,Puolustusvoimien logistiikkalaitos,FIN,FI197,FI-33541,Tampere,Hatanpään valtatie 30 +d002303,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d002304,Fraport AG,DEU,DE712,60547,Frankfurt,"Gebäude 700, Raum 2124/2136" +d002305,Zakład Zamówień Publicznych przy Ministrze Zdrowia,POL,PL,02-326,Warszawa,"Al. Jerozolimskie 155, pok. 115" +d002306,Terridev,FRA,FR105,92200,Neully-sur-Seine,20-22 rue Beffroy +d002307,"Clínica San Francisco, S. L.",ESP,ES413,24004,León,"C/ Marqueses de San Isidro, 11" +d002308,"Torfal, Lda.",PRT,PT16J,,Belmonte, +d002309,WAsval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d002310,Kommunaler Immobilien Service Eigenbetrieb der Landeshauptstadt Potsdam,DEU,DE404,14467,Potsdam,Friedrich-Ebert-Straße 79/81 +d002311,Grönsakshuset i Norden AB,SWE,SE232,541 39,Skövde,Titanvägen 6 +d002312,Vermögen und Bau Baden-Württemberg Amt Ravensburg,DEU,DE148,88214,Ravensburg,Minneggstraße 1 +d002313,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d002314,Mairie de Serris,FRA,FR102,77700,Serris,2 place Antoine-Mauny +d002315,Sander Elektrische Anlagen GmbH,DEU,DE112,71287,Weissach,"Boschstrasse, 4, 4" +d002316,Taxicentrale Witteveen bv,NLD,NL,8531 EG,Lemmer,Nieuwburen 41 -45 +d002317,Consejería de la Presidencia de la Junta de Castilla y León,ESP,ES418,47008,Valladolid,"C/ Santiago Alba, 1" +d002318,Byggnadstekniska Byrån Sverige AB,SWE,SE224,116 45,Stockholm,"Stadsgården 10, 9tr" +d002319,Daimler Truck AG,DEU,DE300,10243,Berlin, +d002320,Gemeinde Pfronten,DEU,DE27B,87459,Pfronten – Ried,Allgäuer Str. 6 +d002321,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d002322,Nordhordland og Gulen Interkommunale Renovasjonsselskap IKS (NGIR),NOR,NO,5956,Hundvin,Lindåsvegen 1260 +d002323,ETS ENST sup. consulaire Grenoble EC MA,FRA,FRK24,38000,Grenoble,12 rue Pierre-Sémard +d002324,Lift AG,CHE,CH0,8105,Regensdorf,Querstraße 37 +d002325,BRIARI'S IND,ROU,RO411,,Carcea,"Strada Calea Bucuresti, Nr. 2" +d002326,UAB „Ignitis“,LTU,LT,,Vilnius, +d002327,Santa Casa da Misericórdia de Lisboa,PRT,PTZZZ,1250-264,Lisboa,"Rua das Taipas, 1" +d002328,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d002329,Dona. Logistică,ROU,RO321,041406,București,Str. Dumitru Minca nr. 2-4 +d002330,Architetto Floriana Grande,ITA,ITF34,,Avellino,c. da Toppole 1 +d002331,Betonbau GmbH & Co. KG,DEU,DE929,31167,Bockenem,Im Nördernfeld +d002332,"J.S. Evro-Medical Company družba za trgovino, proizvodnjo in storitve d.o.o.",SVN,SI,2000,Maribor,Jarnikova ulica 7 +d002333,"Salus, Veletrgovina, družba za promet s farmacevtskimi, medicinskimi in drugimi proizvodi, d.o.o.",SVN,SI,1000,Ljubljana,Litostrojska cesta 46A +d002334,Imprimerie Chauveau,FRA,FRB02,28630,Gellainville, +d002335,Kern GmbH,DEU,DEC05,,Bexbach, +d002336,Deutsche Rentenversicherung Bund Zentraler Einkauf,DEU,DE300,10704,Berlin, +d002337,Staatliches Bau- und Liegenschaftsamt Schwerin,DEU,DE804,19055,Schwerin,Werderstraße 4 +d002338,PinkRoccade Local Government bv,NLD,NL,,'s-Hertogenbosch, +d002339,Fugro France SAS,FRA,FR,92000,Nanterre,"5-6 esplanade Général de Gaulle, Le Carillon" +d002340,Rots Bouw bv,NLD,NL,7122 LC,Aalten,Broekstraat 24 +d002341,FIRM,FRA,FRK25,42000,Saint-Etienne,2 rue Gustave Nadaud +d002342,Dublin Bus/Bus Atha Cliath,IRL,IE061,Dublin,Dublin 7,21 Phibsboro Road +d002343,Lek S.A.,POL,PL9,95-010,Stryków,ul. Podlipie 16 +d002344,Liège Airport Business Park SA,BEL,BE332,4460,Grâce-Hollogne,"Aéroport de Liège, bâtiment 50" +d002345,Bivaria Grup S.R.L.,ROU,RO423,331138,Hunedoara,Str. Eroilor nr. 2D +d002346,Spirale Print,FRA,FR101,75017,Paris,2-4 rue Barye +d002347,"PETROL, Slovenska energetska družba, d.d., Ljubljana",SVN,SI,1000,Ljubljana,Dunajska cesta 50 +d002348,"Lesy Slovenskej republiky, štátny podnik",SVK,SK032,975 66,Banská Bystrica,Námestie SNP 8 +d002349,Strabag s.r.o.,SVK,SK,825 18,Bratislava,Mlynské Nivy 61/A +d002350,Berufsgenossenschaft Holz und Metall,DEU,DEB35,55124,Mainz,Isaac-Fulda-Allee 18 +d002351,Relico Oy,FIN,FI1C1,,Turku, +d002352,"Pharmamed-Mado, družba za trgovino s profesionalno medicinsko opremo in pripomočki, d.o.o.",SVN,SI,1000,Ljubljana,Leskoškova cesta 9E +d002353,CC Pharma GmbH,DEU,DE,,Densborn, +d002354,Halmstads kommun,SWE,SE231,301 05,Halmstad,Box 153 +d002355,Fischer Teamplan Ingenieurbüro GmbH,DEU,DEA27,50374,Erftstadt,Holzdamm 8 +d002356,Geaprodukt trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d002357,Ayuntamiento de Vigo,ESP,ES114,36202,Vigo,"Plaza de «El Rey», 1" +d002358,Bio Technic România S.R.L.,ROU,RO321,060015,București,"Str. Plevnei nr. 196, sector 6" +d002359,Highlander International Recycling,GBR,UKM8,G75 8UZ,Glasgow,"Highlander House, 1 Teign Grove, East Kilbride" +d002360,Municipiul Carei,ROU,RO115,445100,Carei,Str. 1 Decembrie 1918 nr. 40 +d002361,Autobahnen- und Schnellstraßen-Finanzierungs-Aktiengesellschaft,AUT,AT13,1011,Wien,Rotenturmstraße 5-9 +d002362,VA Fälttjänst AB,SWE,SE224,274 36,Skurup,Norra Verkstadsgatan 12 +d002363,Vrtec Vodmat,SVN,SI,1000,Ljubljana,Korytkova ulica 24 +d002364,Philipp GmbH & co. KG,DEU,DEA41,33609,Bielefeld,Schelpmilser Weg 16a +d002365,IBM Deutschland GmbH,DEU,DE112,71139,Ehningen, +d002366,Hentrich GmbH Gebäudereinigung,DEU,DE724,,Stadtallendorf, +d002367,"Pragolab, s.r.o",CZE,CZ010,190 00,Praha,Nad Krocínkou 285/55 +d002368,"BeClean, čiščenje objektov, d.o.o.",SVN,SI,1000,Ljubljana,Popovičeva ulica 8 +d002369,"Hebi Robotics, INC.",USA,,15201,Pittsburgh PA,"91 43rd St, Suite 200, Pittsburgh PA,15201 USA" +d002370,Eranthis,FRA,FRK26,69001,Lyon,Rue Désirée +d002371,Spółdzielnia Socjalna Synergia,POL,PL225,43-316,Bielsko-Biała,al. Armii Krajowej 220 +d002372,GEAPRODUKT trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d002373,MM Surgical družba za trgovino in zastopanje d.o.o.,SVN,SI,1291,Škofljica,Ulica ob hrastih 24 +d002374,Région Auvergne-Rhône-Alpes,FRA,FRK,69269,Lyon,"1 esplanade François Mitterrand, CS 20033" +d002375,Itä-Suomen yliopisto,FIN,FI1D,FI-70210,Kuopio,Yliopistonranta 1 +d002376,Commune de Saint-Denis de La Réunion,FRA,FRY4,97490,Saint-Denis,"Direction De la commande publique, 18 rue Vallon-Hoarau, Sainte-Clotilde" +d002377,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d002378,Métropole de Lyon,FRA,FRK26,69505,Lyon Cedex 3,"20 rue du Lac, CS 33569" +d002379,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d002380,Hexal AG,DEU,DE,,Holzkirchen, +d002381,Spitalul Clinic Judeţean de Urgenţă „Sfântul Apostol Andrei”,ROU,RO223,900591,Constanța,Str. Tomis nr. 145 +d002382,Dutch Theatre Systems & Services bv,NLD,NL,9723 BT,Groningen,Duinkerkenstraat 44 +d002383,"Salus, Veletrgovina, družba za promet s farmacevtskimi, medicinskimi in drugimi proizvodi, d.o.o.",SVN,SI,1000,Ljubljana,Litostrojska cesta 46A +d002384,Cooper Pul scpa,ITA,ITF35,,Salerno, +d002385,Geologian tutkimuskeskus,FIN,FI1,02151,Espoo,Vuorimiehentie 5 +d002386,Grgić obrt za poljodjelstvo i usluge poljoprivrednim i šumskim strojevima vl.Josip Grgić,HRV,HR,32245,Nijemci,Podgrađe Braće Radića 15 +d002387,ATW Brno s.r.o.,CZE,CZ06,621 00,Řečkovice,Kuřimská 1503/42 +d002388,Houdry Selarl,FRA,FRE21,02200,Soissons,55 avenue de Compiègne +d002389,Universitair Ziekenhuis Gent,BEL,BE234,9000,Gent,Corneel Heymanslaan 10 +d002390,"Bundesrepublik Deutschland, vertreten durch das Beschaffungsamt des Bundesministeriums des Innern",DEU,DEA22,53119,Bonn,Brühler Straße 3 +d002391,Trädgårdsteknik i Mellansverige AB,SWE,SE,692 91,Kumla,Frommesta 408 +d002392,"Outsystems — Software em Rede, S. A.",PRT,PTZZZ,2795-242,Linda-a-Velha,"Rua Central Park, edifício 2, 2.º A" +d002393,Dynergie,FRA,FR,69009,Lyon,1 place Verrazzano +d002394,EEAS de Saint-Martin (978),FRA,FRY,97150,Saint-Martin,9 rue Barbuda — Lot 32 — immeuble Kaki Hope Estate +d002395,"Hypokramed, s.r.o.",CZE,CZ010,163 00,Praha,Čistovická 95/13 +d002396,"Javno podjetje Ljubljanski potniški promet, d.o.o.",SVN,SI,1000,Ljubljana,Celovška cesta 160 +d002397,Th. Geyer GmbH & Co. KG Niederlassung Berlin,DEU,DE300,10553,Berlin,Huttenstr. 34-35 +d002398,MeWAdia s.r.o.,CZE,CZ064,603 00,Brno,Hlinky 133/64 +d002399,HEP - Proizvodnja d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 37 +d002400,Producton S.R.L.,ROU,RO321,050527,București,"Str. Dr. Clunet nr. 9, sector 5" +d002401,Deutsche Bundesbank,DEU,DE712,60329,Frankfurt am Main,Taunusanlage 5 +d002402,Pohjolan Turistiauto Oy,FIN,FI1D,,Iisalmi, +d002403,Scan Expert,ROU,RO213,700032,Iași,Str. Sfântul Sava nr. 18 +d002404,Heinrich Schmid GmbH & Co. KG,DEU,DEE08,06618,Wethau, +d002405,Département du Calvados,FRA,FRD11,14000,Caen,9 rue Saint-Laurent +d002406,EDF SA,FRA,FR101,75017,Paris,4 rue Floréal +d002407,"Technische Universität Braunschweig, Geschäftsbereich 3 – Gebäudemanagement",DEU,DE911,38106,Braunschweig,Spielmannstraße 10 +d002408,BIM Berliner Immobilienmanagement GmbH,DEU,DE300,10178,Berlin,Alexanderstraße 3 +d002409,Comando generale della Guardia di finanza — Direzione approvvigionamenti,ITA,ITI43,00162,Roma,viale XXI Aprile 51 +d002410,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d002411,"Landeshauptstadt Dresden GB Stadtentwicklung, Bau, Verkehr und Liegenschaften Amt für Hochbau und Immobilienverwaltung",DEU,DED21,01001,Dresden,Postfach 120020 +d002412,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002413,LHS GmbH & Co.KG,DEU,DEG0H,98724,Neuhaus,Waldweg 10 +d002414,Mølster Installasjon AS,NOR,NO0A2,,Voss, +d002415,Občina Ribnica,SVN,SI,1310,Ribnica,Gorenjska cesta 3 +d002416,"Správa silnic Moravskoslezského kraje, příspěvková organizace",CZE,CZ080,702 23,Ostrava,Úprkova 795/1 +d002417,Stadt Dortmund — Vergabe und Beschaffungszentrum,DEU,DEA52,44135,Dortmund,Viktoriastr. 15 +d002418,"Técnicas y Sistemas de Conservación, S. A.",ESP,ES511,08023,Barcelona,"C/ Solanes, 2, bxs." +d002419,B + R Bildung und Reisen GmbH,DEU,DE600,22081,Hamburg, +d002420,Mark Medical trgovina in storitve d.o.o.,SVN,SI,6210,Sežana,Partizanska cesta 109 +d002421,"Kefo, kemija in farmacija, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 29 +d002422,Bialmed Sp. z o.o.,POL,PL9,02-546,Warszawa,ul. Kazimierzowska 46/48/35 +d002423,Romfarmachim,ROU,RO321,050554,București,"Str. Costache Negri nr. 11, sector 5" +d002424,Huddinge kommun,SWE,SE,141 61,Huddinge,Kommunalvägen 28 +d002425,"Landesbetrieb Straßenbau und Verkehr Schleswig-Holstein (LBV.SH), Standort Rendsburg, vertreten durch die Gebäudemanagement Schleswig-Holstein AöR (GMSH)",DEU,DEF0,24103,Kiel,Gartenstr. 6 +d002426,"Dopravní podnik hl. m. Prahy, akciová společnost",CZE,CZ010,190 22,Praha 9,Sokolovská 217/42 +d002427,Petal,FRA,FRE12,62340,Hames-Boucres,146 route de Guînes +d002428,IFD-Innovatives Fliesen Design GmbH,DEU,DE116,72585,Riederich,Robert-Bosch-Straße 3 +d002429,H & M Gartengestaltung GmbH & Co. KG,DEU,DE263,97222,Rimpar-Maidbronn,Riemenschneiderstraße 26 +d002430,Kmetijska zadruga Selnica ob Dravi z.o.o.,SVN,SI,2352,Selnica ob Dravi,Spodnja Selnica 5 +d002431,Fakultní nemocnice v Motole,CZE,CZ010,150 06,Praha 5,V Úvalu 84 +d002432,3M France,FRA,FR108,95008,Cergy-Pontoise Cedex,1 parvis de l'Innovation — CS 20203 +d002433,Ministarstvo poljoprivrede,HRV,HR,10000,Zagreb,Ulica grada Vukovara 78 +d002434,cBrain A/S,DNK,DK,2100,Kopenhagen,Dampfaergevej 30 +d002435,Občina Dobrna,SVN,SI,3204,Dobrna,Dobrna 19 +d002436,Carps International,FRA,FR,75007,Paryžius,168 rue de Grenelle +d002437,Clear Channel Danmark A/S,DNK,DK011,1408,København K,"Wildersgade 8, 4 sal" +d002438,Enedis,FRA,FR,92079,Paris La Défense,Tour Enedis — 34 place des Corolles +d002439,CSL Behring GmbH,DEU,DE,35041,Marburg,Emil-von-Behring-Straße 76 +d002440,"Sulo Ibérica, S. A.",ESP,ES300,,Madrid, +d002441,Azienda Zero — Passaggio Gaudenzio 1 — Padova,ITA,ITH3,35131,Padova,Passaggio Gaudenzio 1 +d002442,"Malvern Panalytical, B. V., Sucursal en España",ESP,ES30,28703,San Sebastián de los Reyes (Madrid),"C/ Teide, 5, 3.º" +d002443,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d002444,Zentraldienst der Polizei des Landes Brandenburg,DEU,DE40H,15806,Zossen,Am Baruther Tor 20 +d002445,"Skarb Państwa, Państwowe Gospodarstwo Leśne Lasy Państwowe, Nadleśnictwo Augustów",POL,PL843,16-300,Augustów,"ul. Turystyczna 19, 16-300 Augustów" +d002446,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d002447,KSH Soluții Integrate 3D,ROU,RO321,040726,București,"Str. Silvia nr. 85A, sector 2" +d002448,Moser Architekten,DEU,DE139,79539,Lörrach,Georges-Köhler-Str. +d002449,Boston scientific,FRA,FR,78960,Voisins-le-Bretonneux,2 rue René Caudron +d002450,"PRO-GEM svetovanje, marketing, d.o.o. Ljubljana",SVN,SI,1000,Ljubljana,Cesta na Brdo 85 +d002451,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d002452,Cramo Adapteo GmbH,DEU,DE712,60386,Frankfurt,Wächtersbacher Straße 63 +d002453,Plate-forme affrètement et transport,FRA,FR103,78457,Vélizy Cedex,zone aéronautique +d002454,PhDr. Zdeňka Endlicherová,CZE,CZ064,612 00,Brno,Antonína Macka 1/2 +d002455,Centre hospitalier Pierre Oudot,FRA,FRK24,38302,Bourgoin-Jallieu,30 avenue du Médipôle +d002456,Carl Zeiss trgovina optičnih izdelkov in pripomočkov d.o.o.,SVN,SI,1000,Ljubljana,Leskoškova cesta 6 +d002457,MVZ Klinikum Deggendorf GmbH,DEU,DE224,94469,Deggendorf,Perlasberger Str. 41 +d002458,GEAPRODUKT trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d002459,DEKRA Automobil GmbH,DEU,DE111,70469,Stuttgart,Stuttgarter Str. 13 +d002460,Magistrat der Universitätsstadt Gießen – Hochbauamt,DEU,DE72,35390,Gießen,Berliner Platz 1 +d002461,Weatherford Atlas GIP S.A.,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2A +d002462,Gessner & Jacobi GmbH & Co. KG,DEU,DE929,30449,Hannover,Falkenstraße 16-18 +d002463,Dekowand Jobb,DEU,DE224,94469,Deggendorf, +d002464,AMS 2000 Trading Impex,ROU,RO321,030882,București,Str. Turturelelor Nr. 62 +d002465,Karosserie-Melzner GmbH,DEU,DEA18,42859,Remscheid,Burger Str. 55-59 +d002466,Commune d'Ajaccio,FRA,FRM,20304,Ajaccio,2 avenue Antoine Serafini +d002467,"Statutární město Brno, Městská část Brno–Líšeň",CZE,CZ064,628 00,Brno,Jírova 2 +d002468,Medical Ortovit,ROU,RO321,011098,București,"Str. Miron Costin nr. 8, sector 1" +d002469,Raffelsberger & Zagorski OG,AUT,AT,,Wien, +d002470,Gendry Service Location,FRA,FRB05,53400,Craon,"ZA de Villeneue, 1 rue de Hongrie" +d002471,Accord Healthcare Italia,ITA,ITC4C,,Milano, +d002472,BRIARI'S IND,ROU,RO411,,Carcea,"Strada Calea Bucuresti, Nr. 2" +d002473,Abovo Media bv,NLD,NL,1625 NV,Hoorn,Dr. C.J.K. van Aalstweg 8 F 401 +d002474,Eesti Kaubandus-Tööstuskoda,EST,EE,10130,Tallinn,Toom-Kooli tn 17 +d002475,ID2AP,FRA,FRL04,13720,La Bouilladisse,54 chemin des Gorguettes +d002476,"Vantaan kaupunki / Maankäytön, rakentamisen ja ympäristön toimiala",FIN,FI1B,FI-01300,Vantaa,Asematie 7 +d002477,Česká republika – Ministerstvo spravedlnosti,CZE,CZ010,128 10,Praha 2,Vyšehradská 16 +d002478,EnviLoop AB,SWE,SE125,722 11,Västerås,Norra Källgatan 17 +d002479,Pisapia Assicuratori srl Unipolsai Assicurazioni,ITA,ITF31,,Caserta, +d002480,ROMICS,ROU,RO424,300523,Timisoara,"Strada Polona, Nr. 2" +d002481,Centre national du cinéma,FRA,FR10,75675,Paris Cedex 14,291 boulevard Raspail +d002482,Gemeinde Pfronten,DEU,DE27B,87459,Pfronten – Ried,Allgäuer Str. 6 +d002483,Fleck Gerüstbau GmbH & Co.KG,DEU,DEB11,56070,Koblenz,St. Sebastiner Straße 29 +d002484,Občina Šmarje pri Jelšah,SVN,SI,3240,Šmarje pri Jelšah,Aškerčev trg 15 +d002485,Delporte,FRA,FRE11,,Wasquehal,29 avenue de la Marne +d002486,Austro Control Österreichische Gesellschaft für Zivilluftfahrt mit beschränkter Haftung,AUT,AT13,1220,Wien,Wagramer Straße 19 +d002487,Matra S.R.L.,ROU,RO414,235600,Scornicești,Bulevardul Muncii nr. 11 +d002488,Stadibau GmbH – Gesellschaft für den Staatsbediensteten Wohnungsbau in Bayern mbH,DEU,DE212,80804,München,Mottlstr. 1 +d002489,Swereco AB,SWE,SE110,164 40,Kista,"Kistagången 20B, 3tr" +d002490,SPIE Citynetworks,FRA,FR104,91070,Bondoufle,ZI La Marinière +d002491,Powszechny Zakład Ubezpieczeń na Życie Spółka Akcyjna,POL,PL,00-133,Warszawa,"al. Jana Pawła II, nr 24" +d002492,Taksi Jaakko Kuivalainen,FIN,FI1D3,FI-81470,Naarva,Lapinniementie 18 +d002493,"Avalop Servicios XXI, S. L.",ESP,ES114,36500,Lalín,"Avenida de Buenos Aires, 103" +d002494,Viešoji įstaiga Respublikinė Panevėžio ligoninė,LTU,LT,LT-35144,Panevėžys,Smėlynės g. 25 +d002495,Schüßler-Plan Ingenieurgesellschaft mbH,DEU,DE712,60314,Frankfurt am Main,Lindleystraße 11 +d002496,Energie AG Oberösterreich,AUT,AT,4020,Linz,Böhmerwaldstraße 3 +d002497,Reta - prevozi Marko Krže s.p.,SVN,SI,1310,Ribnica,Žlebič 38 +d002498,Servicefirmaet Renell A/S,DNK,DK013,3000,Helsingør, +d002499,"Medica, medicinska zastopstva, trgovina, marketing in posredovanje, d.o.o.",SVN,SI,1236,Trzin,Špruha 44 +d002500,"Landeshauptstadt Saarbrücken, Ordnungsamt",DEU,DEC01,66121,Saarbrücken,Großherzog-Friedrich-Straße 111 +d002501,Gilson international France SA,FRA,FR108,95400,Villiers-le-Bel,19 avenue des Entrepreneurs +d002502,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002503,Tornion Oppilasasuntola Oy,FIN,FI,FI-95401,Tornio, +d002504,Županijska uprava za ceste Primorsko-goranske županije,HRV,HR,51000,Rijeka,Nikole Tesle 9/X +d002505,Miasto Bielsko-Biała Urząd Miejski w Bielsku-Białej,POL,PL225,43-300,Bielsko-Biała,pl. Ratuszowy 9 +d002506,ERG Géotechnique,FRA,FRK26,,Sainte-Foy-les-Lyon, +d002507,"Idex, Ideas y Expansión, S. L.",ESP,ES,03203,Elche,"C/ Jose Cavanilles, 9, PI Torrellano" +d002508,Access Bâtiment,FRA,FRL04,13170,Les Pennes-Mirabeau,Chemin de Velaux +d002509,"GMV Soluciones Globales Internet, S. A. U.",ESP,ES300,28760,Tres Cantos,"C/ Isaac Newton, 11, PTM" +d002510,"Mutua Universal Mugenat, Mutua Colaboradora con la Seguridad Social número 10",ESP,ES511,08022,Barcelona,"Avenida Tibidabo, 17-19" +d002511,Montage- und Trockenbau Mathias Hofmann,DEU,DED44,08525,Plauen-Kauschwitz,Siedlerweg 5 +d002512,Vygon,FRA,FR108,95440,Ecouen,5 rue Adeline +d002513,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d002514,Zöller-Kipper GmbH,DEU,DEB35,55130,Mainz,Hans-Zöller-Str. 50 - 68 +d002515,Leibniz-Institut für Alternsforschung - FLI e.V.,DEU,DEG03,07745,Jena,Beutenbergstraße 11 +d002516,UnipolSai Assicurazioni SpA,ITA,ITF33,40128,Bologna,via Stanlingrado 10 +d002517,"Miejskie Przedsiębiorstwo Wodociągów i Kanalizacji w m.st. Warszawie S.A., zarejestrowane w Krajowym Rejestrze Sądowym w Sądzie Rejonowym dla m.st. Warszawy w Warszawie, XII Wydział Gospodarczy Krajowego Rejestru Sądowego pod numerem KRS 0000146138",POL,PL911,02-015,Warszawa,pl. Starynkiewicza 5 +d002518,VRTEC CICIBAN,SVN,SI,1000,Ljubljana,Šarhova ulica 29 +d002519,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d002520,Dafo Brand Aktiebolag,SWE,SE121,135 70,Stockholm,Vindkraftsvägen 8 +d002521,Freistaat Bayern vertreten durch das Bayerische Staatsministerium für Gesundheit und Pflege,DEU,DE212,81667,München,Haidenauplatz 1 +d002522,"Cardio Medical družba za trgovino in storitve, d.o.o.",SVN,SI,1236,Trzin,Špruha 1 +d002523,RDW,NLD,NL,2711 ER,Zoetermeer,Europaweg 205 +d002524,Tekaben Trade s.r.o.,CZE,CZ063,586 01,Jihlava,Chlumova 5429/1a +d002525,Pygma Conseil,FRA,FRE12,62400,Béthune, +d002526,Securis,FRA,FRD,69220,Belleville-en-Beaujolais,4 rue Joseph Pillard +d002527,Växjö kommun,SWE,SE212,352 12,Växjö,Box 1222 +d002528,CT Trockenbau,DEU,DE936,27726,Worpswede, +d002529,Agence nationale pour la gestion des déchets radioactifs — ANDRA,FRA,FR105,92298,Châtenay-Malabry,1-7 rue Jean Monnet +d002530,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d002531,Osnovna šola Litija,SVN,SI,1270,Litija,Ulica Mire Pregljeve 3 +d002532,UAB „Kelprojektas“,LTU,LT,,Kaunas, +d002533,Science City Skellefteå AB,SWE,SE331,,Skellefteå, +d002534,Municipiul Oradea,ROU,RO111,410100,Oradea,Str. Unirii nr. 1 +d002535,Jawurek GmbH,DEU,DE24,96191,Viereth — Trunstadt,Zum Tänning 1 +d002536,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d002537,Scan Expert,ROU,RO213,700032,Iași,Str. Sfântul Sava nr. 18 +d002538,Cancom GmbH,DEU,DEA1C,,Langenfeld, +d002539,Wohn- und Pflegeheim Zell am Ziller – Kaiser Franz Josef Stiftung,AUT,AT335,6280,Zell am Ziller,Gerlosstraße 5 +d002540,Substance,FRA,FRI21,19100,Brive,8 rue Marie L. et Jul Viallatoux +d002541,Srijem d.o.o.,HRV,HR,31000,Osijek,Vilajska 6 +d002542,Dar-Nic Iri Conf,ROU,RO311,110241,Pitești,Str. Craiovei nr. 128 +d002543,"LandesEnergieAgentur Hessen GmbH, Zentrale Beschaffung",DEU,DE714,65189,Wiesbaden,Mainzer Straße 118 +d002544,"Kastor - Medical Dental podjetje za veleprodajo, zastopanje, inženiring in zunanjo trgovino, Ljubljana, Vošnjakova 6",SVN,SI,1000,Ljubljana,Vošnjakova ulica 6 +d002545,SAS la Plurielle du Bâtiment,FRA,FR106,93320,Les Pavillons-sous-Bois,"ZI la Poudrette, 18 allée de Luxembourg" +d002546,Asociación Centro Trama,ESP,ES300,28031,Madrid,"C/ Puerto de Idiazábal, 3" +d002547,"Národný ústav srdcových a cievnych chorôb, a.s.",SVK,SK01,833 48,Bratislava-mestská časť Nové Mesto,Pod Krásnou hôrkou 1 +d002548,Agenția Națională de Îmbunătățiri Funciare,ROU,RO321,041293,Bucureşti,"Str. Olteniței nr. 35-37, sector: -, județ București" +d002549,CSL Behring AG,CHE,CH,CH-3014,Bern,Wankdorfstrasse 10 +d002550,Volvo Danmark A/S,DNK,DK0,2630,Taastrup,Højager 7 +d002551,AB Sciex Austria GmbH,AUT,AT13,1170,Wien,Hernalser Hauptstraße 219 +d002552,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d002553,COWI A/S,DNK,DK,2800,Kongens Lyngby,Parallelvej 2 +d002554,Idex Énergies,FRA,FR105,92513,Boulogne-Billancourt,72 avenue Jean Baptiste Cement +d002555,Assurances MALJ / Pilliot,FRA,FRH,62921,Aire-sur-la Lys,rue Witternesse +d002556,Spitalul Județean de Urgență Tulcea,ROU,RO225,820195,Tulcea,Str. 1848 nr. 32 +d002557,"ATS Chemnitz Asphalt-, Tief- und Straßenbau GmbH",DEU,DED41,09116,Chemnitz,Weideweg 31 +d002558,Holzfällung Hausbacher,AUT,AT32,5600,St. Johann im Pongau,Hallmoos 22 +d002559,KIZ PROWINA pro Wirtschaft und neue Arbeit GmbH,DEU,DE,63065,Offenbach am Main,Hermann-Steinhäuser-Straße 43-47 +d002560,CNRS délégation Aquitaine,FRA,FRI12,33402,Talence Cedex,esplanade des Arts et Métiers — BP 105 +d002561,SOGEA Nord Ouest Travaux publics,FRA,FRD2,27930,Gravigny,"La Censurière, CS 40156" +d002562,documentus Deutschland GmbH,DEU,DE600,,Hamburg, +d002563,"Cortijo Cuevas, S. L.",ESP,ES,18327,Láchar,"Avenida Presidente Felipe González, 5" +d002564,Ana María Bradineras Silvoso,ESP,ES511,,Barcelona, +d002565,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d002566,Občina Podčetrtek,SVN,SI,3254,Podčetrtek,Trška cesta 59 +d002567,Sace BT tramite Bucchioni’s Studio di Bucchioni Franco e C. sas,ITA,ITC34,,La Spezia, +d002568,"Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.",SVN,SI,2000,Maribor,Zagrebška cesta 22 +d002569,UAB „Ekstrameda“,LTU,LT,,Kaunas, +d002570,"Inetum España, S. A.",ESP,ES,,Madrid, +d002571,Občina Kozje,SVN,SI,3260,Kozje,Kozje 37 +d002572,Philips GmbH Market DACH,DEU,DE600,22335,Hamburg, +d002573,Sement Overheid bv,NLD,NL,,Gouda, +d002574,Lernen fördern e. V.,DEU,DEA37,49477,Ibbenbüren, +d002575,Sipic trgovina in proizvodnja d.o.o.,SVN,SI,1000,Ljubljana,Koprska ulica 94 +d002576,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d002577,Mavili srl,ITA,ITI43,,Roma, +d002578,Urtica Sp. z o.o.,POL,PL51,54-613,Wrocław,ul. Krzemieniecka 120 +d002579,UAB „Lurida“,LTU,LT023,LT,Petkeliškės k.,"Jungties g. 10, Petkeliškės k., Prienų r. sav." +d002580,Società di committenza Regione Piemonte SpA — SCR — Piemonte SpA,ITA,ITC1,10125,Torino,corso Marconi 10 +d002581,Cherbourg-en-Cotentin,FRA,FRD12,50108,Cherbourg-en-Cotentin,10 place Napoléon +d002582,Vodárna Plzeň a.s.,CZE,CZ032,326 00,Plzeň,Malostranská 143/2 +d002583,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d002584,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d002585,TZMO România,ROU,RO322,077060,Clinceni,Sat Olteni nr. 3E +d002586,Egis Villes et Transport,FRA,FRG01,44379,Nantes,"7 rue Rainière, parc du Perray, TSA 27922" +d002587,B&W Bautenschutz,DEU,DEA37,48431,Rheine,Windhorststr. 2B +d002588,Entreprise Limouzin,FRA,FRI12,33170,Gradignan, +d002589,"Interexport mednarodna trgovina, d.o.o.",SVN,SI,1218,Komenda,Potok pri Komendi 12 +d002590,Region Hovedstaden,DNK,DK011,2100,København Ø,Blegdamsvej 9 +d002591,Kauniaisten kaupunki,FIN,FI1B1,FI-00270,Kauniainen,Kauniaistentie 10 +d002592,"Área de Gobierno de Portavoz, Seguridad y Emergencias",ESP,ES300,28002,Madrid,"C/ Príncipe de Vergara, 140" +d002593,GIS Consult GmbH,DEU,DEA36,45721,Halteren am See,Schultenbusch 3 +d002594,SANPRODMED S.R.L.,ROU,RO321,013594,Bucuresti,"Strada Aeroportului, Nr. 2, Sector: 1" +d002595,Spitalul Municipal Toplița,ROU,RO124,535700,Toplița,Str. Victor Babeș nr. 3 +d002596,"Johnson & Johnson, prodaja medicinskih in farmacevtskih izdelkov, d.o.o.",SVN,SI,1000,Ljubljana,Šmartinska cesta 53 +d002597,Nemzeti Színház Közhasznú Nonprofit Zártkörűen Működő Részvénytársaság,HUN,HU120,1095,Budapest,Bajor Gizi park 1. +d002598,"Bundesagentur für Arbeit (BA), vertreten durch den Vorstand, hier vertreten durch die Leiterin des Geschäftsbereiches Einkauf im BA-Service-Haus",DEU,DE,90478,Nürnberg,Regensburger Str. 104 +d002599,CISS TDI GmbH,DEU,DEB12,53489,Sinzig,Barbarossastr. 36 +d002600,"Presidencia de la Agencia Estatal Consejo Superior de Investigaciones Científicas, M. P.",ESP,ES300,28006,Madrid,"C/ Serrano, 117" +d002601,La Banque Postale Leasing & Factoring,FRA,FR,75275,Paris Cedex 06,"115 rue de Sèvres, CPX 804" +d002602,Oy Helsingin Asuntohankinta ab,FIN,FI1B,FI-00240,Helsinki,Eevankatu 2 +d002603,WSP Sverige AB,SWE,SE110,121 88,Stockholm-Globen, +d002604,Dupeyron Alexandre,FRA,FRI12,33700,Mérignac,4 rue Jules Michelet +d002605,"Harald Bruhns GmbH, Vertriebscenter Berlin",DEU,DE405,13407,Berlin,Montanstraße 6 +d002606,Fundación Meniños,ESP,ES111,15008,A Coruña,"Avenida de Cádiz, 5, 2.º izquierda" +d002607,Hrvatska Lutrija d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 72 +d002608,ARGE Kutter HTS Bauunternehmung GmbH/Ludwig Pfeiffer Hoch- und Tiefbau GmbH & Co. KG,DEU,DEE0A,06311,Helbra, +d002609,Silnice Morava s.r.o.,CZE,CZ080,794 01,Krnov,Revoluční 904/30 +d002610,LOS Elektro AS,NOR,NO0A2,5430,Bremnes,Hollundsdalen 3 +d002611,Siemens Financial Services,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d002612,Tampereen Sähkölaitos Oy,FIN,FI197,FI-33100,Tampere,Voimakatu 17 +d002613,"Grupo EITB, Departamento de Recursos Generales de EITB",ESP,ES21,,Bilbao,"C/ Capuchinos de Basurto, 2, 48008 Bilbao (Bizkaia)" +d002614,"Marijanović, obrt za proizvodnju i usluge",HRV,HR,32245,Podgrađe,Kralja Tomislava 4 +d002615,Maintenance technique optimisée,FRA,FRL04,13320,Bouc-Bel-Air,990 chemin de la Sauvecanne +d002616,Papeteries la Victoire,FRA,FRE11,59200,Tourcoing,rue Racine +d002617,Stadtverwaltung Kaiserslautern – Stabstelle IV.1) Zentrale Vergabestelle,DEU,DEB32,67657,Kaiserslautern,Lauterstraße 2 +d002618,Ferrovienord SpA,ITA,ITC4C,20123,Milano,piazzale Cadorna 14 +d002619,"Stadt Frankfurt am Main, Stadtkämmerei Zentraleinkauf",DEU,DE712,60311,Frankfurt am Main,Paulsplatz 9 +d002620,Inéo Normandie,FRA,FRD12,50110,Tourlaville,260 rue des Noisetiers +d002621,Conseil départemental de Côte-d'Or,FRA,FRC11,21035,Dijon Cedex,"1 rue Joseph-Tissot, CS 13501" +d002622,Teleos Suisse,CHE,CH,2883,Montmelon,Les Rangiers 11e +d002623,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002624,"S&T Slovenija, informacijske rešitve in storitve, d.d.",SVN,SI,1000,Ljubljana,Leskoškova cesta 6 +d002625,Comisión Ciudadana Anti-sida de Bizkaia,ESP,ES211,,Vitoria-Gasteiz, +d002626,Euromed trgovina in storitve d.o.o.,SVN,SI,1351,Brezovica pri Ljubljani,Podpeška cesta 14 +d002627,Comune di Milano — Area gare beni e servizi,ITA,ITC4C,20121,Milano,galleria Ciro Fontana 3 +d002628,Landkreis Aschaffenburg,DEU,DE264,63739,Aschaffenburg,Bayernstr. 18 +d002629,IT gouvernance,FRA,FRG02,49300,Cholet,6 rue du Président Wilson +d002630,Vodovod d.o.o. Zadar,HRV,HR,23000,Zadar,Špire Brusine 17 +d002631,"Fraunhofer-Gesellschaft, Einkauf und Gerätewirtschaft C2",DEU,DE212,80686,München,Hansastraße 27 c +d002632,Direcția Generală de Asistență Socială și Protecția Copilului Brașov,ROU,RO122,500091,Brașov,Str. Iuliu Maniu nr. 6 +d002633,BDX Företagen AB,SWE,SE,975 95,Luleå,Kallaxvägen 190 Kallaxheden +d002634,Fakultní nemocnice Olomouc,CZE,CZ071,779 00,Olomouc,I. P. Pavlova 185/6 +d002635,Pörner Anlagenbau GmbH.,AUT,AT,,Wien, +d002636,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d002637,Werfen Polska sp. z o.o.,POL,PL911,03-699,Warszawa,ul. Wolińska 4 +d002638,Econocom,FRA,FRK24,92110,Clichy,"42,46 rue Médéric" +d002639,Müllverwertung Borsigstraße GmbH,DEU,DE6,22113,Hamburg,Borsigstraße 6 +d002640,Lunemapa SARL,FRA,FR108,95500,Bonneuil-en-France,29 rue de Dugny +d002641,"Emetel Sistemas, S. L.",ESP,ES111,15172,Oleiros, +d002642,Pentti J Toivanen,FIN,FI1D3,FI-83700,Polvijärvi,Niskaniementie 22 k +d002643,Mittetulundusühing Valga Arvutikeskus,EST,EE,68204,Valga vald,Vabaduse tn 22-7 +d002644,Københavns Kommune - Økonomiforvaltningen,DNK,DK011,,København, +d002645,Grand port maritime de Marseille,FRA,FRL04,13226,Marseille,"23 place de la Joliette, CS 81965" +d002646,Gottlob Brodbeck GmbH & Co. KG,DEU,DE141,72555,Metzingen,Maienwaldstraße 25 +d002647,Dirección General de Tráfico,ESP,ES300,28071,Madrid,"C/ Josefa Valcárcel, 28" +d002648,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002649,Gebäudereinigung Flohr e.K,DEU,DE938,29693,Hodenhagen,Bahnhofstraße 51 +d002650,Klinički bolnički centar Sestre milosrdnice,HRV,HR,10000,Zagreb,Vinogradska cesta 29 +d002651,Rosenbauer Deutschland GmbH,DEU,DE40H,14943,Luckenwalde,Rudolf-Breitscheid-Straße 79 +d002652,Computacenter AG & Co. oHG,DEU,DE,12099,Berlin,Mariendorfer Damm 1 +d002653,Tisseo,FRA,FRJ23,31081,Toulouse,4 impasse Paul Mesplé +d002654,Land Oberösterreich – Krisenstab,AUT,AT31,4021,Linz,Landhausplatz 1 +d002655,Municipiul Vaslui,ROU,RO216,730139,Vaslui,Str. Spiru Haret nr. 2 +d002656,"PRO-GEM svetovanje, marketing, d.o.o. Ljubljana",SVN,SI,1000,Ljubljana,Cesta na Brdo 85 +d002657,Hlavní město Praha,CZE,CZ010,110 00,Praha,Mariánské náměstí 2 +d002658,Vrtec Ciciban,SVN,SI,1000,Ljubljana,Šarhova ulica 29 +d002659,"Poniente Formación e Innovación, S. L., Escuela Taller Juyma, S. L. y Lauma RC, U. T. E., Ley 18/1982",ESP,ES614,,Granada, +d002660,"České vysoké učení technické v Praze, Fakulta elektrotechnická",CZE,CZ01,160 00,Praha 6 - Dejvice,Jugoslávských partyzánů 1580/3 +d002661,MicroPort CRM AB,SWE,SE110,103 25,Stockholm,Box 16285 +d002662,Gemeente Westland,NLD,NL,,Naaldwijk, +d002663,Feuerwehr Oftringen Zürichstraße 30 4665 Oftringen,CHE,CH0,4665,Oftringen,Zürichstraße 30 +d002664,Roche farmacevtska družba d.o.o.,SVN,SI,1000,Ljubljana,Stegne 13G +d002665,TREBOR DRUM CONSTRUCT SRL,ROU,RO111,410265,Oradea,"Strada Erofte Grigore, Nr. 1B" +d002666,Telecom Italia SpA,ITA,IT,,Milano (MI), +d002667,B.A.D Gesundheitsvorsorge und Sicherheitstechnik GmbH,DEU,DEA22,53225,Bonn,Herbert-Rabius-Straße 1 +d002668,Vrtec Mojca,SVN,SI,1000,Ljubljana,Levičnikova ulica 11 +d002669,Servier Polska Services Sp. z o.o.,POL,PL9,01-248,Warszawa, +d002670,Stadt Mülheim-Kärlich,DEU,DEB17,56218,Mülheim-Kärlich,Rathaus Kapellenplatz +d002671,O2 Czech Republic a.s.,CZE,CZ,140 22,Praha 4–Michle,Za Brumlovkou 266/2 +d002672,"EKO PLUS podjetje za izvajanje nalog na področju ekologije, organizacije, trgovine in poslovnih storitev d.o.o",SVN,SI,3220,Štore,Vrtna ulica 14 +d002673,Neue Schauspielhaus GmbH,DEU,DE600,20099,Hamburg,Kirchenallee 39 +d002674,LADAPT2607,FRA,FRK23,26800,Portes-lès-Valence,380 avenue de Président Allende +d002675,Dura Vermeer Hengelo bv,NLD,NL,7550 AW,Hengelo,Postbus 877 +d002676,Tallinna Tehnikaülikool,EST,EE,19086,Tallinn,Ehitajate tee 5 +d002677,otelio,FRA,FR104,68000,Colmar,52 rue du Prunier +d002678,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d002679,Maelstrom Studios,FRA,FR10,33130,Bègles,406 boulevard Jean-Jacques-Bosc +d002680,Walter Ermler GmbH,DEU,DE243,96450,Coburg,Glender Straße 24 +d002681,Gemeente Westvoorne,NLD,NL,,Rockanje, +d002682,"Servicio Gallego de Salud, Área Sanitaria de Santiago y Barbanza",ESP,ES111,15706,Santiago de Compostela,"Rúa Choupana, s/n" +d002683,Comune di Genova — Stazione unica appaltante,ITA,ITC33,16124,Genova,via Garibaldi 9 +d002684,Deluxe Cards,ROU,RO321,030615,București,"Str. Călăraşi nr. 167, sector 3" +d002685,"Ditcom, s.r.o.",CZE,CZ010,,Praha 4,Antala Staška 510/38 +d002686,"Stadt Witten, Zentrales Vergabeamt",DEU,DEA56,58453,Witten,Annenstr. 111 b +d002687,"Tecnocontrol Servicios, S. A.",ESP,ES30,28760,Tres Cantos,"Ronda de Poniente, 11" +d002688,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d002689,Ministry for the Agriculture Fisheries and Animal Rights — MPU,MLT,MT,SVR 1301,Santa Venera,"Permanent Secretariat Offices, 6 Qormi Road" +d002690,Aktsiaselts Tallinna Linnatransport,EST,EE,12618,Tallinn,Kadaka tee 62a +d002691,"Stadt Plauen, Vergabestelle",DEU,DED44,08523,Plauen,Unterer Graben 1 +d002692,Scania Danmark A/S,DNK,DK0,2635,Ishøj,Industribuen 19 +d002693,Metsähallitus,FIN,FI1,FI-01301,Vantaa,PL 94 +d002694,Lietuvos nuolatinė atstovybė Europos Sąjungoje,BEL,BE,1040,Briuselis,Rue Belliard 41-43 +d002695,ERG,FRA,FRL05,83500,La Seyne-sur-Mer,243 avenue de Bruxelles +d002696,Pro3 Baumanagement GmbH Messendorfberg 46 8042 Graz,AUT,AT,8042,Graz, +d002697,Stercontrol Marek Grdeń,POL,PL,53-238,Wrocław,Ostrowskiego 9 +d002698,Markt Berchtesgaden,DEU,DE215,83471,Berchtesgaden,Rathausplatz 1 +d002699,Municipiul Cluj-Napoca,ROU,RO113,400001,Cluj-Napoca,Str. Moților nr. 1-3 +d002700,"Uniqa pojišťovna, a.s.",CZE,CZ010,160 00,Praha,Evropská 810/136 +d002701,Felső-Szabolcsi Kórház,HUN,HU,4600,Kisvárda,Árpád utca 26. +d002702,Semsamar (973),FRA,FRY30,97351,Matoury,ZA Terca Centre commercial Family Plaza +d002703,Balas,FRA,FR106,93583,Saint-Ouen,PA Rives de Seine 10/12 rue Pierre Nicolau +d002704,Auto-Brasse Tim Brasse GmbH,DEU,DE944,49084,Osnabrück,Karmannstr. 11 +d002705,AMD Global Construct S.R.L.,ROU,RO322,,Voluntari,Str. Crinului nr. 14-16 +d002706,"FUNDATIA ""KIWI CASA BUCURIEI""",ROU,RO125,540074,Targu Mures,"Strada Papiu Ilarian Alexandru, Nr. 7" +d002707,město Orlová,CZE,CZ080,735 14,Orlová–Lutyně,Osvobození 796 +d002708,Bouygues énergies et services,FRA,FR103,78280,Guyancourt,1 avenue E. Freyssinet +d002709,Ostravská univerzita,CZE,CZ080,701 03,Ostrava,Dvořákova 7 +d002710,"Futura Soft, s.r.o.",CZE,CZ064,612 00,Brno,Příkop 843/4 +d002711,Macofil,ROU,RO412,210001,Târgu Jiu,Str. Bârsești nr. 217 +d002712,Eiffage Infrastructure Guyane,FRA,FRY30,97343,Cayenne Cedex,"1050 route de Degrad des Cannes, ZI Terca, BP 1026" +d002713,"Grupo Control Empresa de Seguridad, S. A.",ESP,ES611,04004,Almería,"C/ Soldado Español, 12" +d002714,Architekten BHP,DEU,DEB11,56077,Koblenz,Kapuzinerplatz 135 +d002715,B. Braun Medical,ROU,RO424,,Sânandrei,Str. Bernd Braun nr. 1 +d002716,a2bau GmbH,DEU,DE111,70182,Stuttgart,Katharinenplatz 3 +d002717,Zöller-Kipper GmbH,DEU,DEB35,55130,Mainz,Hans-Zöller-Str. 50-68 +d002718,Roger Martin,FRA,FRC11,21850,Saint-Apollinaire, +d002719,Synergon a.s.,SVK,SK032,974 01,Banská Bystrica,Partizánska cesta 5564/77 +d002720,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d002721,Ziekenhuisnetwerk Antwerpen,BEL,BE211,2000,Antwerpen,Lange Beeldekensstraat 267 +d002722,Bundesagentur für Arbeit Regionales Einkaufszentrum Nord,DEU,DE,30147,Hannover,Postfach +d002723,Region Stockholm,SWE,SE11,104 22,Stockholm,Box 22550 +d002724,Farmacol Logistyka Sp. z o.o.,POL,PL22,40-431,Katowice,ul. Szopieniecka 77 +d002725,Maxigel S.R.L.,ROU,RO316,100070,Ploiești,Str. Laboratorului nr. 29B +d002726,Juli Architekten,DEU,DE24B,95326,Kulmbach,Obere Stadt 14 +d002727,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d002728,Bock GmbH,DEU,DEG0F,,Ilmenau, +d002729,HKF Haustechnik GmbH,DEU,DE,23992,Krassow,Kastanienallee 56 +d002730,"Association ""Entreprise d' insertion"" PAIE 2002",FRA,FRY10,97122,Baie-Mahault,allée des Télecommunications Cité Sicaf Destrellan Sud +d002731,SPL Euralille,FRA,FRE11,59777,Euralille,"Tour de Lille, 18° étage BD de Turin" +d002732,Maxeiner GmbH,DEU,DEB1A,56355,Nastätten,Rheinstr. 30 +d002733,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d002734,NTT MAGYARORSZÁG Kft.,HUN,HU11,1117,Budapest,Budafoki út 60. +d002735,Am Trust Internationl Underwriters DAC such. In Italia,ITA,ITC4C,,Milano, +d002736,ATOSS Software Ges.m.b.H.,AUT,AT13,1030,Wien,Ungargasse 64-66/3/503 +d002737,Tinmar Energy S.A.,ROU,RO321,014476,București,"Calea Floreasca nr. 246C, sector 1, București, Clădirea Sky Tower, et. 17" +d002738,Instalserwis Wojciech Gawarkiewicz,POL,PL922,07-410,Ostrołęka,Tęczowa 7 +d002739,CAF Cergy,FRA,FR108,95000,Cergy-Pontoise,CAF du Val-d'Oise +d002740,Lausitzer Grün GmbH,DEU,DE402,03050,Cottbus,Strasse der Jugend 33 +d002741,Janssen-Cilag GmbH,DEU,DEA,41470,Neuss,Johnson&Johnson Platz 1 +d002742,Commune de Tremblay-en-France,FRA,FR106,93290,Tremblay-en-France,18 boulevard de l'Hôtel de Ville +d002743,rexx systems GmbH,DEU,DE600,20097,Hamburg,Süderstraße 75-79 +d002744,"O2 Czech Republic, a.s.",CZE,CZ,140 22,Praha 4 - Michle,Za Brumlovkou 266/2 +d002745,"Interpart trgovina na debelo in drobno, posredništvo, d.o.o.",SVN,SI,1000,Ljubljana,Cesta na Brdo 85 +d002746,Frontsound Veranstaltungstechnik GmbH,DEU,DED51,04347,Leipzig,Stöhrerstraße 3e +d002747,Keskkonnaministeeriumi Infotehnoloogiakeskus,EST,EE,12618,Tallinn,Teaduspargi tn 8 +d002748,Mestna občina Ljubljana,SVN,SI,1000,Ljubljana,Mestni trg 1 +d002749,"Pavasal Empresa Constructora, S. A.",ESP,ES52,46014,Valencia,"C/ Tres Forques, 149 AC" +d002750,"Maxto Sp. z o.o., s.k.a.",POL,PL,32-085,Modlniczka,ul. Willowa 87 +d002751,"A care, a.s.",CZE,CZ010,143 00,Praha 4,Nikoly Vapcarova 3274/2 +d002752,Ingenieurbüro Schötz,DEU,DE27E,87463,Dietmannsried,Baumeisterstraße 8 +d002753,Autorità di sistema portuale del mar Tirreno Centrale,ITA,ITF33,80133,Napoli,p.le Carlo Pisacane — interno Porto +d002754,Medgal sp. z o.o.,POL,PL84,16-001,Księżyno,ul. Niewodnicka 26a +d002755,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002756,Poste italiane SpA,ITA,IT,,Roma, +d002757,Società regionale per la sanità (SO.RE.SA. SpA),ITA,ITF33,80143,Napoli,Centro direzionale Isola f9 +d002758,Universitätsstadt Siegen,DEU,DEA5A,57078,Siegen,Lindenplatz 7 +d002759,"Staatsbetrieb Sächsisches Immobilien- und Baumanagement, Zentrale, SSC VVM, Außenstelle Dresden 1, Zentrale Vergabestelle",DEU,DED2,01099,Dresden,Königsbrücker Str. 80 +d002760,"ČEZ Distribuce, a.s.",CZE,CZ04,405 02,Děčín - Podmokly,Teplická 874/8 +d002761,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d002762,Lidköpings kommun,SWE,SE232,531 88,Lidköping,Skaragatan 8 +d002763,Geaprodukt trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d002764,Societatea Națională Nuclearelectrica S.A.,ROU,RO321,010494,Bucureşti,Str. Polonă nr. 65 +d002765,Gemeinde Hallwang,AUT,AT323,5300,Hallwang,Dorfstraße 45 +d002766,Arthrex Adria d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 269 G +d002767,Dansk Privat Sikring ApS,DNK,DK031,5380,Dalby,Hersnapvej 97 +d002768,Usługi Leśne Matyka Marek,POL,PL84,16-320,Bargłów Kościelny,Tajno Stare 74 +d002769,UAB „Osteca“,LTU,LT,LT-92108,Klaipėda,Danės g. 47 +d002770,Alingsås kommun,SWE,SE232,441 81,Alingsås,Stora torget 1 +d002771,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d002772,Stadtverwaltung Waldshut-Tiengen,DEU,DE13A,79761,Waldshut-Tiengen,Hauptstraße 34 +d002773,Medical Corp S.R.L.,ROU,RO126,550165,Sibiu,"Strada Lazăr Gheorghe, Nr. 8" +d002774,Ville de Vannes,FRA,FRH04,56019,Vannes,"Place Maurice-Marchais, BP 509" +d002775,Hydrogeotechnique,FRA,FR,71150,Fontaines,RNO — ZA Les Ormeaux D — 3 rue Parado +d002776,"Anetta, poslovne in druge storitve d.o.o. Ljubljana",SVN,SI,1000,Ljubljana,Tržaška cesta 135 +d002777,Distelkam Dienstleistungsgruppe,DEU,DE,,Chemnitz, +d002778,Humancare Polska,POL,PL,55-040,Żerniki Małe,ul. Jesionowa 6 +d002779,Arthrex Adria d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 269 G +d002780,Škoda Electric a.s.,CZE,CZ032,301 00,Plzeň,Tylova 1 57 +d002781,Weatherford Atlas GIP S.A.,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2A +d002782,Splošna bolnišnica Izola Ospedale Generale Isola,SVN,SI,6310,Izola - Isola,Polje 40 +d002783,Mermaid Medical A/S,DNK,DK0,3660,Stenløse,Frydensbergvej 25 +d002784,Ville d'Orvault,FRA,FRG01,44700,Orvault,9 rue Marcel Deniau +d002785,ADI — Azuréenne d'Incendie,FRA,FRL05,83140,Six-Fours-les-Plages,1282 chemin des Negadoux +d002786,Pleno del Ayuntamiento de Azuqueca de Henares,ESP,ES424,19200,Azuqueca de Henares,"Plaza de la Constitución, 1" +d002787,"Novum CZech, s.r.o.",CZE,CZ,252 02,Jíloviště,Na Močidlech 242 +d002788,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 - Haus 6 +d002789,Kareta s.r.o.,CZE,CZ080,792 01,Bruntál,Krnovská 1877/51 +d002790,Dolex Com,ROU,RO415,240275,Râmnicu Vâlcea,Str. Timiș nr. 24 +d002791,Integrerings- og mangfoldsdirektoratet (IMDi),NOR,NO,0152,Oslo,Tollbugata 20 +d002792,"Futura Soft, s.r.o.",CZE,CZ064,602 00,Brno,Příkop 843/4 +d002793,Medine Plus trženje farmacevtskih in drugih izdelkov d.o.o.,SVN,SI,3000,Celje,Erjavčeva ulica 30 +d002794,Wiener Tourismusverband,AUT,AT13,1030,Wien,Invalidenstraße 6 +d002795,Services et Santé,FRA,FR105,92032,Paris La Défense,9-11 allée de l'Arche +d002796,Primăria Armeniș (Consiliul Local Armeniș),ROU,RO422,327005,Armeniș,Str. Principală nr. 368 +d002797,Szpital Powiatowy w Zawierciu,POL,PL22B,42-400,Zawiercie,ul. Miodowa 14 +d002798,Puolustuskiinteistöt,FIN,FI1C4,FI-49400,Hamina,Isoympyräkatu 10 +d002799,"Smero, spol. s r.o.",CZE,CZ064,664 61,Rajhrad,Odbojářů 695 +d002800,Stadtverwaltung Meßstetten,DEU,DE143,72469,Meßstetten,Hauptstraße 9 +d002801,Orifarm GmbH,DEU,DE,,Leverkusen, +d002802,Ferrovie della Calabria srl,ITA,ITF6,88100,Catanzaro,via Milano 28 +d002803,KONE GmbH,DEU,DE212,82110,München,Industriestr. 15 +d002804,Bundesagentur für Arbeit Regionales Einkaufszentrum Südwest,DEU,DE,60528,Frankfurt am Main,Saonestr. 2-4 +d002805,BWI GmbH,DEU,DE30,12489,Berlin,Rudower Chaussee 13 +d002806,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002807,R.D.R. SpA,ITA,IT,,Torre del Greco (NA), +d002808,Universitetet i Oslo,NOR,NO081,0372,Oslo,Klaus Torgårds vei 3 Sogn Arena 4. etasje +d002809,REMONDIS Olpe GmbH,DEU,DEA59,57462,Olpe,Raiffeisenstraße 39 +d002810,Destia Oy,FIN,FI1B1,FI-01300,Vantaa,Neilikkatie 17 +d002811,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d002812,Gadola Fassaden AG,CHE,CH0,8618,Oetwil am See,Willikon +d002813,Servicio Madrileño de Salud.Hospital Universitario Ramon y Cajal,ESP,ES30,28034,Madrid,"Carretera de Colmenar, kilómetro 9,100" +d002814,Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos,LTU,LT,LT-50161,Kaunas,Eivenių g. 2 +d002815,Miemczok Elektroanlagenbau GmbH,DEU,DE9,30827,Garbsen,Dieselstraße 42 +d002816,Off the Wall Communication AB,SWE,SE,113 56,Stockholm,Birger Jarlsgatan 61 +d002817,UAB „Lokmis“,LTU,LT,LT-08300,Vilnius,Visorių g. 2 +d002818,Geometricus d.o.o.,HRV,HR,34340,Kutjevo,Ferovac 32 +d002819,jobcenter Kreis Steinfurt AöR,DEU,DEA37,48565,Steinfurt,Tecklenburger Str. 10 +d002820,GatewayBaltic Ltd,LVA,LV,LV-1010,Riga,Elizabetes iela 51 +d002821,Skånemejerier Storhushåll AB,SWE,SE232,213 76,Malmö,"Boplatsgatan 6, 5 vån" +d002822,"MEDIC-UM STORE, prodaja medicinske opreme, d.o.o.",SVN,SI,3320,Velenje,Vinska Gora 44 +d002823,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d002824,"Infraestruturas de Portugal, S. A.",PRT,PT170,2809-013,Almada,"Praça da Portagem, Almada" +d002825,Delta service srl,ITA,IT,,Piacenza, +d002826,"Generalna Dyrekcja Dróg Krajowych i Autostrad, Oddział w Gdańsku",POL,PL63,80-354,Gdańsk,ul. Subisława 5 +d002827,MM Surgical družba za trgovino in zastopanje d.o.o.,SVN,SI,1291,Škofljica,Ulica ob hrastih 24 +d002828,Hippy Hippy Shake Oy,FIN,FI1D3,FI-81820,Kylänlahti,Tikanniementie 20 +d002829,IMServ Europe Ltd,GBR,UKG,,Telford, +d002830,Občina Žalec,SVN,SI,3310,Žalec,Ulica Savinjske čete 5 +d002831,"Eulen Servicios Sociosanitarios, S. A.",ESP,ES111,15008,A Coruña,"Carretera de Arteixo, 21" +d002832,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002833,Bigbang,FRA,FRK26,69007,Lyon,114 Grande rue de la Guillotière +d002834,Ville d'Aubervilliers,FRA,FR106,,Aubervilliers, +d002835,bioMerieux,POL,PL911,01-518,Warszawa,ul. generała Józefa Zajączka 9 +d002836,CHU de Nantes,FRA,FRG01,44093,Nantes Cedex,5 allée de l'Île-Gloriette +d002837,Fisher et Paykel Healthcare,FRA,FR,91946,Courtabœuf,"10 avenue du Québec, bâtiment F5, Silic 512 Villebon-sur-Yvette" +d002838,White & Case LLP,GBR,UKI,000000,Londres,"5 Old Broad St, Ec2n 1dw" +d002839,Landesbetrieb Forst Brandenburg Landeswaldoberförsterei Borgsdorf,DEU,DE40A,16556,Hohen Neuendorf OT Borgsdorf,Bahnhofstr. 17 +d002840,"SANTIM, čiščenje, d. o. o.",SVN,SI,2370,Dravograd,Koroška cesta 47 +d002841,"AdwyData, s.r.o.",CZE,CZ010,103 00,Praha 10,Za potokem 46/4 +d002842,Lääkintäväline Oy,FIN,FI1D2,,Kuopio, +d002843,"J.S. Evro-medical Company družba za trgovino, proizvodnjo in storitve d.o.o.",SVN,SI,2000,Maribor,Jarnikova ulica 7 +d002844,Vwr international srl,ITA,ITC4C,20153,Milano,via San Giusto 85 +d002845,Sander Elektrische Anlagen GmbH,DEU,DE112,71287,Weissach,"Boschstrasse, 4, 4" +d002846,"Skarb Państwa – Generalny Dyrektor Dróg Krajowych i Autostrad, prowadzący postępowanie: Generalna Dyrekcja Dróg Krajowych i Autostrad, Oddział w Krakowie",POL,PL,31-542,Kraków,ul. Mogilska 25 +d002847,"Javno podjetje Ljubljanska parkirišča in tržnice, d.o.o.",SVN,SI,1000,Ljubljana,Kopitarjeva ulica 2 +d002848,Internationaler Bund e.V. Verbund Hessen,DEU,DE711,64289,Darmstadt,Marburger Str. 2 +d002849,"Arno Kindler, EDV-Sytemhaus",DEU,DEA38,48231,Warendorf,Waterstroate 32 +d002850,Osnovna šola Muta,SVN,SI,2366,Muta,Šolska ulica 6 +d002851,„Eko Dolina” Sp. z o.o.,POL,PL633,84-207,Koleczkowo,"Łężyce, al. Parku Krajobrazowego 99" +d002852,"Simbio, družba za ravnanje z odpadki d.o.o.",SVN,SI,3000,Celje,Teharska cesta 49 +d002853,Consorci del Museu Nacional d'Art de Catalunya,ESP,ES511,08038,Barcelona,"Palau Nacional, Parc de Montjuïc" +d002854,Ruokolahden Vuokratalot Oy,FIN,FI,,Ruokolahti, +d002855,Espoon Asunnot Oy,FIN,FI1B1,FI-02230,Espoo,Suomenlahdentie 1 +d002856,"Águas e Resíduos da Madeira (ARM), S. A.",PRT,PT300,9000-082,Funchal,"Rua dos Ferreiros, 148-150" +d002857,Oracle,ITA,IT,,Roma, +d002858,studio2architekten,DEU,DED41,09120,Chemnitz,Altchemnitzer Straße 27 +d002859,Raumgestaltung Plauen GmbH,DEU,DED44,08527,Plauen,Oberer Graben 1 +d002860,Associació per a la Reconstrucció i Posta en Servei de Material Ferroviari Històric,ESP,ES513,,Lleida, +d002861,"Landkreis Börde, Zentrale Vergabestelle",DEU,DEE07,39387,Oschersleben (Bode),Triftstr. 9-10 +d002862,"Novo Nordisk trženje farmacevtskih izdelkov, d.o.o.",SVN,SI,1000,Ljubljana,Šmartinska cesta 140 +d002863,Flughafen München GmbH,DEU,DE21A,85326,München,Postfach 23 17 55 +d002864,Bright Finland Oy,FIN,FI1B1,,Vantaa, +d002865,Nordic Last Og Buss AS,NOR,NO074,8305,Svolvær,Vorsetøyveien 20 +d002866,Corex S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Breslelor nr. 15 +d002867,SFR,FRA,FR101,75015,Paris,16 rue du Général-Alain-de-Boissieu +d002868,Cheops Technology,FRA,FRI12,33610,Canéjan,37 rue Thomas Edison +d002869,Håbo kommun,SWE,SE121,746 32,Bålsta,Håbo kommun Centrumleden 1 +d002870,"Ecologia Italiana srl, avente P. IVA 03694411210 e con sede in Acerra (NA) alla via delle Industrie 159, con un ribasso offerto del 26,725 % e un importo di aggiudicazione di 1 164 909,24 EUR, oltre IVA",ITA,ITF33,,Acerra (NA),via delle Industrie 159 +d002871,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d002872,"Simps's podjetje za svetovanje, inženiring, marketing, prodajo in servis, d.o.o.",SVN,SI,1236,Trzin,Motnica 3 +d002873,AHK Service OÜ,EST,EE,10133,Tallinn,Suurtüki tn 4b +d002874,Euforia AB,SWE,SE110,115 30,Stockholm,Artillerigatan 89 bv +d002875,Srijem d.o.o.,HRV,HR,31000,Osijek,Vilajska 6 +d002876,Spitalul Clinic Judeţean Mureş,ROU,RO125,540072,Târgu Mureș,Str. Bernady György nr. 6 +d002877,Norrköping Norrevo Fastigheter AB,SWE,SE,601 81,Norrköping,Norra Promenaden 100 +d002878,"Stadt Halle (Saale), Fachbereich Recht, Team Vergabe Bauleistungen/Bauplanungen",DEU,DEE02,06108,Halle (Saale),Marktplatz 1 +d002879,Svanen ApS,DNK,DK011,2300 Kbh. S,København,Azaleagangen 38 +d002880,Oslo kommune v/Helseetaten,NOR,NO081,0182,Oslo,Storgata 51 +d002881,Bode Böden e.K.,DEU,DED,71691,Freiberg, +d002882,Posluh za sluh d.o.o.,SVN,SI,6320,Portorož - Portorose,Sončna pot 14A +d002883,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d002884,SPL aéroportuaire régionale,FRA,FRJ,34064,Montpellier,hôtel de région 201 avenue de la Pompignane +d002885,Aformac,FRA,FRK14,63000,Clermont-Ferrand,6 rue de Gravenoire +d002886,Communauté d'agglomération de Pau Pyrenées,FRA,FRI15,64000,Pau Cedex,"hôtel de France, 2 B place Royale, CS 90547" +d002887,Qualiconsult immobilier,FRA,FRC14,25480,École-Valentin, +d002888,Amt Miltzow,DEU,DE80L,18519,Sundhagen,"OT Miltzow, Bahnhofsallee 8a" +d002889,Aqua-Mesure,FRA,FR104,91090,Lisses,6-8 rue de la Closerie +d002890,Albert Ziegler GmbH,DEU,DE11C,89537,Giengen,Albert-Ziegler-Straße 1 +d002891,"Správa železnic, státní organizace",CZE,CZ010,110 00,Praha 1,Dlážděná 1003/7 +d002892,HELD + GABELMANN Beratende Ingenieure PartGmbB,DEU,DE132,,Müllheim, +d002893,"Elkarkide, S. L.",ESP,ES220,,Noáin, +d002894,Stadt Wien — Wiener Wohnen,AUT,AT130,1030,Wien,Rosa-Fischer-Gasse 2 +d002895,Accessible échafaudages,FRA,FRI12,33190,La Réole, +d002896,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d002897,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d002898,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d002899,Becoming Group,FRA,FR,59800,Lille, +d002900,"Servicios de la Comarca de Pamplona, S. A.",ESP,ES220,,Pamplona,31002 +d002901,Procurator Sverige AB,SWE,SE232,431 26,Mölndal,Box 1004 +d002902,BELURBA bvba,BEL,BE,3930,Hamont-Achel,Heikant 5 +d002903,Stad Vilvoorde,BEL,BE241,1800,Vilvoorde,Stadhuis - Grote Markt +d002904,Planungsgruppe VA GmbH,DEU,DE929,30539,Hannover, +d002905,Fußbodentechnik Ing. Maikl GMBH,AUT,AT32,5020,Salzburg,Altgasse 11 +d002906,KPMG AS,NOR,NO,0306,Oslo,Postboks 7000 Majorstua +d002907,Kontiolahden kunta,FIN,FI1D3,,Kontiolahti, +d002908,CardiRad Sweden AB,SWE,SE11,126 31,Hägersten,Karusellplan 8 +d002909,Wahl Abbruch GmbH,DEU,DEB12,53424,Remagen,Dornierstr. 2 +d002910,social mobility,DEU,DE27B,,Oberostendorf, +d002911,Dell SAS,FRA,FRJ13,34938,Montpellier Cedex 9,1 rond-point Benjamin-Franklin +d002912,Landkreis Neunkirchen,DEU,DEC03,66564,Ottweiler,Wilhelm-Heinrich-Straße 36 +d002913,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002914,"HEP Energija, trgovanje in prodaja električne energije, d.o.o.",SVN,SI,1000,Ljubljana,Dunajska cesta 151 +d002915,Parimage,FRA,FR101,75015,Paris,22 rue Chauvelot +d002916,Gemeente Rotterdam,NLD,NL,3002 AN,Rotterdam,Wilhelminakade 179 +d002917,Novaintermed S.R.L.,ROU,RO322,,Pipera (Voluntari),Drumul Potcoavei nr. 5A +d002918,Farid Industrie SpA,ITA,ITC11,10048,Vinovo (TO),via Moncalieri 109 +d002919,Braumann + Schmidt GmbH,DEU,DE300,12357,Berlin, +d002920,Electrabel NV,BEL,BE100,1000,Bruxelles,Boulevard Simon Bolivar 34 +d002921,Engie,FRA,FRK26,69246,Lyon,127 avenue Barthélémy Buyer +d002922,Projexia,FRA,FRK25,42800,Rive-de-Gier,40 boulevard des Provinces +d002923,kreuger wilkins architekten GbR,DEU,DE111,70176,Stuttgart,Rosenbergstrasse 52 a +d002924,Département de la Vendée,FRA,FRG05,85923,La Roche-sur-Yon,40 rue du Maréchal Foch +d002925,ÖBB Infrstruktur AG,AUT,AT130,1020,Wien,Praterstern 3 +d002926,Rectorado de la Universidad de Sevilla,ESP,ES618,41004,Sevilla,"C/ San Fernando, 4" +d002927,Signify Italia SpA,ITA,ITC4C,,Milano,viale Sarca 235 +d002928,Svenska Lantmännen ek för,SWE,SE110,104 25,Stockholm,Box 30192 +d002929,RWD Schlatter AG,CHE,CH0,9325,Roggwil TG,St. Gallerstraße 21 +d002930,Datec Netzwerke & Druckerlösungen GmbH,DEU,DED44,08468,Heinsdorfergrund,Kaltes Feld 23 +d002931,Česká republika - Ministerstvo spravedlnosti,CZE,CZ010,128 10,Praha 2,Vyšehradská 16 +d002932,Eiffage énergie système,FRA,FRI11,24100,Bergerac, +d002933,Tallinna Kesklinna Valitsus,EST,EE,15058,Tallinn,Nunne tn 18 +d002934,O2 Czech Republic a.s.,CZE,CZ,140 22,Praha 4–Michle,Za Brumlovkou 266/2 +d002935,Villamosipari Acélszerkezetgyártó Kft.,HUN,HU,8360,Keszthely,Georgikon u. 22 +d002936,Junta de Gobierno de la Diputación Provincial de Almería,ESP,ES611,04001,Almería,"C/ Navarro Rodrigo, 17" +d002937,Concejalía Delegada de Contratación del Ayuntamiento de Puerto del Rosario,ESP,ES70,35600,Puerto del Rosario,"C/ Fernández Castañeyra, 2" +d002938,Verstappen Van Amelsvoort bv,NLD,NL,5391 LH,Nuland,Rijksweg 17 +d002939,Region Hannover,DEU,DE929,30169,Hannover,Hildesheimer Str. 20 +d002940,"Consejo de Administración de Aigues i Sanejament d'Elx, S. A.",ESP,ES521,03202,Elche,Plaza de la Lonja +d002941,Gemeinde Pfronten,DEU,DE27B,87459,Pfronten – Ried,Allgäuer Str. 6 +d002942,DTS Przyjemne Przeprowadzki Sp. z o.o.,POL,PL91,04-866,Warszawa,ul. Wał Miedzeszyński 251 +d002943,RUMPF architekten + ingenieure,DEU,DEB17,56626,Andernach,Rennweg 97 +d002944,UAB „B. Braun Medical“,LTU,LT,,Vilnius, +d002945,Reta - prevozi Marko Krže s.p.,SVN,SI,1310,Ribnica,Žlebič 38 +d002946,OÜ ADM Interactive,EST,EE,10415,Tallinn,Põhja pst 27a +d002947,Groupement Bouygues travaux publics régions France/Pro-Fond SAS,FRA,FRD22,76000,Rouen,4 rue Saint-Eloi +d002948,"STRABAG AG, Direktion Niedersachsen/Sachsen-Anhalt, Gruppe Halberstadt",DEU,DEE09,38820,Halberstadt,Kruggang 1 +d002949,Commune de la Ciotat,FRA,FRL04,13600,La Ciotat,hôtel de ville — rond-point des Messageries Maritimes +d002950,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d002951,EWIBO GmbH,DEU,DEA34,46399,Bocholt,Adenauerallee 59 +d002952,ANAS SpA,ITA,ITC11,00185,Roma,via Monzambano 10 +d002953,"Maquinter, S. A.",ESP,ES30,28850,Torrejón de Ardoz,"PIaza Las Monjas, c/ Las Estaciones, 3" +d002954,Université de Nantes,FRA,FRG01,44035,Nantes Cedex 1,1 quai de Tourville — BP 13522 +d002955,SAS TPB,FRA,FR,35500,Vitré, +d002956,Česká republika - Generální ředitelství cel,CZE,CZ010,140 96,Praha 4,Budějovická 7 +d002957,Bezirk Oberbayern,DEU,DE212,80538,München,Prinzregentenstr. 14 +d002958,ALOS GmbH,DEU,DE,50859,Köln,Dieselstraße 17 +d002959,S.C. Fragra Design S.R.L.,ROU,RO114,430013,Baia Mare,"Str. Bucureşti nr. 118, sector, județ Maramureș, localitate Baia Mare, cod poștal 430013" +d002960,ETS Georges Vilatte,FRA,FR105,92320,Châtillon,57 avenue de la République +d002961,"Pharmos, a.s.",CZE,CZ,716 00,Ostrava,Těšínská 1349 296 +d002962,Polizeipräsidium Wuppertal,DEU,DEA1A,42285,Wuppertal,Müngstener Straße 35 +d002963,Director de Gestión Económica de la Jefatura de Apoyo Logístico de la Armada,ESP,ES300,28036,Madrid,"Avenida Pío XII, 83" +d002964,Rambøll Danmark A/S,DNK,DK,2300,København S,Hannemanns Allè 53 +d002965,Ministero dell'interno — Dipartimento della pubblica sicurezza — Direzione centrale dei servizi tecnico logistici e della gestione patrimoniale — Ufficio attività contrattuali per il vestiario l'equipaggiamento e l'armamento della polizia di stato,ITA,ITI,00185,Roma,via del Castro Pretorio 5 +d002966,"Accenture — Consultores de Gestão, S. A.",PRT,PTZZZ,1070-101,Lisboa,"Avenida Engenheiro Duarte Pacheco, Amoreiras, torre 1, 16.º piso" +d002967,Fels+Hüsges GmbH,DEU,DEA15,41066,Mönchengladbach,Boettgerstr. 6 +d002968,Sailer Stepan und Partner GmbH Beratende Ingenieure für Bauwesen VBI,DEU,DE212,,München,Ingolstädter Straße 20 +d002969,DUBRAU GmbH Niederlassung Dresden,DEU,DED21,01159,Dresden,Freiberger Str. 67 +d002970,"Bundesamt für Infrastruktur, Umweltschutz und Dienstleistungen der Bundeswehr",DEU,DEA22,53123,Bonn,Fontainengraben 200 +d002971,Dachtech GmbH,CHE,CH0,8302,Kloten,Oberfeldstrasse 10 +d002972,Acte 2 Paysage,FRA,FRF11,67210,Obernai,24 rue des Érables +d002973,Hochtief CZ a.s.,CZE,CZ010,150 00,Praha 5,Plzeňská 16/3217 +d002974,SMACL,FRA,FRH,73031,Niort,141 avenue Salvador Allende +d002975,Euro Défense — service Labrenne Propreté,FRA,FR105,92230,Gennevilliers,5 avenue Henri Colin +d002976,Osaühing Roverto,EST,EE,80010,Pärnu linn,Lao tn 17 +d002977,Jetmail bv,NLD,NL,,Hillegom, +d002978,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002979,SUTURA Képviseleti és Kereskedelmi Korlátolt Felelősségű Társaság,HUN,HU,1097,Budapest,Gubacsi út 47. +d002980,MOE A/S,DNK,DK,2860,Søborg,Buddingevej 272 +d002981,AMJ Turku Audio Oy,FIN,FI1C1,,Lieto, +d002982,Citémétrie SAS,FRA,FR101,75014,Paris,23 rue de la Tombe-Issoire +d002983,InExchange Factorum AB,SWE,SE232,541 23,Skövde,Box 133 +d002984,"ENA Portugal — Sistemas de Telecomunicações, S. A.",PRT,PT17,2740-257,Oeiras,"Edifício Tecnologia III, 66, Taguspark, Porto Salvo" +d002985,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d002986,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d002987,"Maquinaria Trabadelo Santana, S. L.",ESP,ES704,35600,Puerto del Rosario,"C/ Alfareras, esquina c/ Alcaldes Mayores, 7" +d002988,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d002989,"České Radiokomunikace, a.s.",CZE,CZ010,169 00,Praha 6,Skokanská 1 +d002990,Euroimmun Polska sp. z o.o.,POL,PL514,50-543,Wrocław,ul. Widna 2a +d002991,"Značky Morava, a.s.",CZE,CZ080,793 93,Brantice,Brantice 430 +d002992,"Medcom Tech, trgovina in storitve d.o.o.",SVN,SI,3000,Celje,Stegenškova ulica 6 +d002993,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d002994,Gmina Miasta Gdyni,POL,PL633,81-382,Gdynia,al. marszałka Piłsudskiego 52/54 +d002995,Spitalul Clinic Judeţean de Urgenţă Arad,ROU,RO421,310037,Arad,Str. Andreny Karoly nr. 2-4 +d002996,Antignum GmbH & Co.KG,DEU,DEG0G,99439,Ballstedt,Im Dorfe 6d +d002997,Ryfylke Bygg,NOR,NO0A1,,Sauda, +d002998,KLC Désamiantage,FRA,FR108,95200,Sarcelles,2 rue de la Fosse-Guerin +d002999,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003000,Komenda Główna Policji,POL,PL,02-624,Warszawa,ul. Puławska 148/150 +d003001,Gmina Czerniewice,POL,PL713,97-216,Czerniewice,"ul. Mazowiecka 42, 97-26 Czerniewice" +d003002,Geaprodukt trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d003003,Service urbain Cotraitant,FRA,FRB02,28240,La Loupe,11 bis avenue de Beauce +d003004,Kuf environnement,FRA,FRY10,,Gourbeyre,ZAC de Grande Savane — 3 allée des Jonquilles +d003005,FBS GmbH,DEU,DEC04,66763,Dillingen,Odilienplatz 6 +d003006,Rolf Schmidt GmbH - Garten + Landschaft + Sportplatzbau,DEU,DE237,92718,Schirmitz,Falkenweg 11 +d003007,Dienstleistungen für Bestatter Bernd Pfannkuchen e.K.,DEU,DE7,63165,Mühlheim,Waldstraße 15 +d003008,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003009,Spółdzielnia Socjalna Synergia,POL,PL225,43-316,Bielsko-Biała,al. Armii Krajowej 220 +d003010,Wilhelm Barth GmbH &. Co.KG,DEU,DE116,70736,Fellbach,Steinbeisstr. 14 +d003011,"Liegenschaftsfonds Berlin GmbH & Co.KG, vertreten durch die Berliner Immobilienmanagement GmbH",DEU,DE300,10178,Berlin,Alexanderstraße 3 +d003012,Eesti Töötukassa,EST,EE,11412,Tallinn,Lasnamäe tn 2 +d003013,Klinikum Fürth,DEU,DE253,90766,Fürth,Jakob-Henle-Str. 1 +d003014,Costacos Com,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d003015,"Calmell, S. A.",ESP,ES511,,Barcelona, +d003016,Försvarsmakten,SWE,SE,371 41,Karlskrona,Minervavägen Campus Gräsvik +d003017,AS Trev-2 Grupp,EST,EE,10916,Tallinn,Teemeistri tn 2 +d003018,Centrex,FRA,FR106,93160,Noisy-le-Grand,2 rue de la Butte Verte +d003019,Société publique locale Deux-Rives,FRA,FRF11,67016,Strasbourg Cedex,1 rue de la Coopérative +d003020,Spie Facilities,FRA,FR106,93287,Saint-Denis,1/3 place de la Berline +d003021,Farmaceutica Remedia Distribution & Logistics S.R.L.,ROU,RO423,330040,Deva,Str. Dorobanților nr. 43 +d003022,WEMO-tec GmbH,DEU,DE732,36124,Eichenzell,Bürgermeister-Ebert-Straße 17 +d003023,Schüßler-Plan Ingenieurgesellschaft mbH,DEU,DE712,60314,Frankfurt am Main,Lindleystraße 11 +d003024,Junta General del Patronato Municipal de la Vivienda de Alicante,ESP,ES521,03002,Alicante,"Plaza Santa Faz, 5" +d003025,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d003026,Eesti Kaubandus-Tööstuskoda,EST,EE,10130,Tallinn,Toom-Kooli tn 17 +d003027,Opća bolnica Bjelovar,HRV,HR0,43000,Bjelovar,Mihanovićeva 8 +d003028,"MEO — Serviços de Comunicações e Multimédia, S. A.",PRT,PT170,1050-119,Lisboa,"Avenida Fontes Pereira de Melo, 40" +d003029,"Gilead Sciences, S. L.",ESP,ES300,28033,Madrid,"Via de los Poblados, 3, Parque Empresarial Cristalia, edificio 7/8, 6.ª planta" +d003030,"Baxter, S. L.",ESP,ES523,46005,Valencia,"Gran Vía Marqués del Turia, 57" +d003031,"Ambiente e Sistemas de Informação Geográfica (AMBISIG), S. A.",PRT,PT,2510-216,Óbidos,"Rua da Criatividade, sala 1.74, Parque Tecnológico de Óbidos, edifícios Centrais" +d003032,Luan Vision,ROU,RO111,417166,Oradea,Str. Margaretelor nr. 18 +d003033,Technická univerzita v Liberci,CZE,CZ051,461 17,Liberec,Studentská 1402/2 +d003034,Alliance Healthcare România,ROU,RO321,060859,București,Str. Amilcar C. Săndulescu nr. 7 +d003035,"Rial Engenharia, Lda.",PRT,PT17,1600-160,Lisboa,"Estrada da Luz, 90, 8.º andar" +d003036,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d003037,Haltmeyer GmbH,AUT,AT,1130,Wien, +d003038,Colas Projets,FRA,FRF31,54186,Heillecourt Cedex,3 avenue des Erables — CS 80139 +d003039,Josef Lentner GmbH,DEU,DE218,85664,Hohenlinden,Josef-Neumeier-Str. 3 +d003040,Qiagen srl,ITA,ITC4C,,Milano, +d003041,Enel Italia SpA on behalf of e-distribuzione SpA,ITA,ITI43,00198,Roma (RM),Viale Regina Margherita 125 +d003042,GatewayBaltic Ltd,LVA,LV,LV-1010,Riga,Elizabetes iela 51 +d003043,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003044,Mairie de Coupvray,FRA,FR102,77700,Coupvray,Place de la Mairie +d003045,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d003046,Fucina Italia srl (mandante),ITA,ITI16,,Piombino, +d003047,Haemato Pharm GmbH,DEU,DE,,Schönefeld, +d003048,"Kostak, komunalno in gradbeno podjetje, d.d.",SVN,SI,8270,Krško,Leskovška cesta 2A +d003049,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d003050,Vermögen und Bau Baden-Württemberg Amt Tübingen,DEU,DE142,72076,Tübingen,Schnarrenbergstraße 1 +d003051,Schreibwaren Wegmann,DEU,DE229,94227,Zwiesel, +d003052,"Centro Hospitalar Universitário de Lisboa Norte, E. P. E.",PRT,PT170,1649-035,Lisboa,Avenida Professor Egas Moniz +d003053,GHT — Le CHU de Clermont-Ferrand,FRA,FRK14,63003,Clermont-Ferrand,58 rue Montalembert +d003054,Ministerstvo spravedlnosti České republiky,CZE,CZ010,128 00,Praha 2,Vyšehradská 16 +d003055,"Axiom Tech, računalniško svetovanje in programiranje, d.o.o.",SVN,SI,1210,Ljubljana - Šentvid,Ulica Jožeta Jame 14 +d003056,Stichting Scala College,NLD,NL,2406LK,Alphen aan den Rijn,Kees Mustersstraat 6 -8 +d003057,Eesti Kaubandus-Tööstuskoda,EST,EE,10130,Tallinn,Toom-Kooli tn 17 +d003058,Pardubický kraj,CZE,CZ053,532 11,Pardubice,Komenského náměstí 125 +d003059,"Soclabreport — Análises Laboratoriais, Lda.",PRT,PT,2040-511,Rio Maior,"Estrada Nacional 114, s/n, ribeira de São João" +d003060,"IDEXX Laboratorios, S. L.",ESP,ES511,08038,Barcelona,"C/ Plomo, 2, piso 3.º" +d003061,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4b +d003062,VOIS - Vestfold Offentlige Innkjøpssamarbeid,NOR,NO,3160,Stokke,Nygaards allé 1 +d003063,Stadt Bocholt,DEU,DEA34,46395,Bocholt,Kaiser-Wilhelm-Straße 52-58 +d003064,"Dirección General de la Mutual Midat Cyclops, Mutua Colaboradora con la Seguridad Social número 1",ESP,ES511,08029,Barcelona,"Avenida Josep Tarradellas, 14-18" +d003065,Splošna bolnišnica Izola Ospedale Generale Isola,SVN,SI,6310,Izola - Isola,Polje 40 +d003066,Insprie Technologies GmbH und MID GmbH,DEU,DE9,,St. Georgen, +d003067,SAS Setec Hydratec — Agence de Vitrolles,FRA,FRL01,13127,Vitrolles,5 chemin des Gorges de Cabriès +d003068,"Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.",SVN,SI,2000,Maribor,Zagrebška cesta 22 +d003069,"Bláha ús, s.r.o.",CZE,CZ020,273 73,Vraný,119 +d003070,Brandner Unterallgäu KG,DEU,DE27C,,Babenhausen, +d003071,Now Boarding AB,SWE,SE331,931 31,Skellefteå,"Peter Karlsten, Trädgårdsgatan 8" +d003072,Hydrotec Ingenieurgesellschaft für Wasser und Umwelt mbH,DEU,DEA2D,,Aachen, +d003073,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d003074,TCR bv,NLD,NL,8102 HW,Raalte,Spitsstraat 14 +d003075,Landesbetrieb Bau und Immobilien Hessen Niederlassung Mitte Zentrale Vergabe,DEU,DE7,61231,Bad Nauheim,Dieselstraße 1-7 +d003076,UAB „Sorimpeksas“,LTU,LT,LT-44353,Kaunas,Šiaulių g. 16A +d003077,Marmorveredelung Foerg & Weisheit GmbH,DEU,DED42,09366,Stollberg /Erzgeb,"An der Buche, 22" +d003078,"Interpart trgovina na debelo in drobno, posredništvo, d.o.o.",SVN,SI,1000,Ljubljana,Cesta na Brdo 85 +d003079,"Multiservicios Telyma Grupo de Empresas, S. L.",ESP,ES617,29009,Málaga,"Avenida Doctor Gálvez Ginachero, 27, 1.º B" +d003080,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d003081,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003082,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d003083,Ned Com,ROU,RO223,905700,Constanța,Str. Vârfu cu Dor nr. 26 +d003084,wibbeke denkmalpflege GmbH,DEU,DEA,59590,Geseke,Meteorstr. 6 +d003085,UAB „Ignitis“,LTU,LT,,Vilnius, +d003086,Mittetulundusühing Valga Arvutikeskus,EST,EE,68204,Valga vald,Vabaduse tn 22-7 +d003087,"Futura Soft, s.r.o.",CZE,CZ064,602 00,Brno,Příkop 843/4 +d003088,Association Compostri,FRA,FRG01,,Nantes, +d003089,Relico Oy,FIN,FI1C1,,Turku, +d003090,"T M G, a.s.",SVK,SK,971 01,Prievidza,Priemyselná 9A +d003091,GSI Helmholtzzentrum für Schwerionenforschung GmbH,DEU,DE711,64291,Darmstadt,Planckstraße 1 +d003092,Uppsala kommun,SWE,SE121,753 75,Uppsala,Uppsala kommun Kommunledningskontoret +d003093,ETG - Obrt,HRV,HR,51250,Novi Vinodolski,Prisika 12 +d003094,Karl Gemünden GmbH & Co. KG,DEU,DEB3J,55218,Ingelheim am Rhein,Rheinstraße 194 B +d003095,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d003096,Axes Computers s.r.o.,CZE,CZ032,301 00,Plzeň,Kollárova 2116/1 +d003097,Alpha Brio Medical S.R.L.,ROU,RO321,031184,București,Str. Foișorului nr. 146 +d003098,Matka-Kyllönen Oy,FIN,FI1D8,FI-88900,Kuhmo,Kainuuntie 84 +d003099,"Economic Commerce trgovsko, proizvodno in storitveno podjetje d.o.o.",SVN,SI,2000,Maribor,Zagrebška cesta 40A +d003100,2299022-8,FIN,FI1B,,Helsinki, +d003101,"Dopravný podnik mesta Prešov, akciová spoločnosť",SVK,SK041,080 06,Ľubotice,Bardejovská 7 +d003102,Agenzia del demanio Direzione servizi al patrimonio,ITA,ITI43,00187,Roma,via Barberini 38 +d003103,Stölting GmbH Reinigung und Service,DEU,DEA32,45891,Gelsenkirchen,Willy-Brandt-Allee 314 +d003104,Port Douglas Contractors Ltd,IRL,IE,,Athlone, +d003105,Agro-vir d.o.o.,HRV,HR0,10000,Zagreb,Slavonska avenija 7 +d003106,Maxman,ROU,RO115,440210,Satu Mare,"Strada -, Nr. -" +d003107,OPCO Atlas,FRA,FR101,75013,Paris,25 quai Panhard-et-Levassor +d003108,Progexial,FRA,FR104,91160,Longjumeau,12 rue Narcisse Gallien — BP 40335 +d003109,Gemeente Delft,NLD,NL,,Delft, +d003110,Macon,ROU,RO423,,Cristur,Șoseaua Hunedoarei nr. 1-3 +d003111,Bez + Kock Architekten Generalplaner GmbH,DEU,DE111,,Stuttgart, +d003112,"Universitätsmedizin Göttingen (UMG), Georg-August-Universität, Stiftung Öffentlichen Rechts",DEU,DE91C,37075,Göttingen,Robert-Koch-Str. 40 +d003113,Bayer. Landeskriminalamt,DEU,DE212,80636,München,Maillingerstrasse 15 +d003114,ThyssenKrupp Aufzüge GmbH,AUT,AT13,1230,Wien,Zetschegasse 11 +d003115,Fingrid Oyj,FIN,FI,FI-00620,Helsinki,Läkkisepäntie 21 +d003116,Agenția Națională de Administrare a Bunurilor Indisponibilizate,ROU,RO321,050741,Bucureşti,Str. Regina Elisabeta nr. 3 +d003117,Albaida Infraestructuras,ESP,ES,04006,Almería,"C/ el Alcázar, 7, 1.º B" +d003118,Leyrer + Graf Baugesellschaft m.b.H.,AUT,AT124,3950,Gmünd,Conrathstraße 6 +d003119,Wasserstraßen- und Schifffahrtsamt Lauenburg,DEU,DEF06,21481,Lauenburg,Dornhorster Weg 52 +d003120,Mahlknecht Herrle Architektur,DEU,DE212,,München, +d003121,Fakultní nemocnice Bulovka,CZE,CZ010,180 81,Praha,Budínova 67/2 +d003122,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d003123,Forstliche DL M. Agthe,DEU,DE408,,Ketzin, +d003124,SBH | Schulbau Hamburg,DEU,DE600,20355,Hamburg,An der Stadthausbrücke 1 +d003125,"Metal Timanfaya, S. L.",ESP,ES708,35500,Arrecife,"C/ Doctor Gómez Ulla, 24" +d003126,Vestra Industry S.R.L.,ROU,RO212,,Cătămărești-Deal,Str. Mihai Eminescu nr. 85 +d003127,CPP-Budapest Kft.,HUN,HU1,1145,Budapest,Amerikai út 33. +d003128,"MDS — Corretor de Seguros, S. A.",PRT,PT11,4100-130,Porto,"Avenida da Boavista, 1277/81, 2.º" +d003129,Nimar,ROU,RO125,545300,Reghin,Str. Gării nr. 78/A +d003130,Johann Huter u. Söhne KG,AUT,AT,,Innsbruck, +d003131,Konditori Fiesta,SWE,SE213,,Kalmar, +d003132,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d003133,Spitalul Orășenesc Rupea,ROU,RO122,505500,Rupea,Str. Republicii nr. 128 +d003134,Ferrocarrils de la Generalitat de Catalunya,ESP,ES,08017,Barcelona,"C/ dels Vergós, 44" +d003135,"Mutua Universal Mugenat, Mutua Colaboradora con la Seguridad Social número 10",ESP,ES511,08022,Barcelona,"Avenida Tibidabo, 17-19" +d003136,Medeq OÜ,EST,EE,10135,Tallinn,Veerenni tn 24 +d003137,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d003138,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d003139,Gavanier SARL,FRA,FRI23,87250,Bessines-sur-Gartempe,ZA de l'Occitanie +d003140,"Francisco Lucas, S. L.",ESP,ES618,,Sevilla, +d003141,Hasenkox Ingenieurgesellschaft mbH,DEU,DEA11,,Düsseldorf, +d003142,Kreera samhällsbyggnad,SWE,SE224,211 43,Malmö,Södra Förstadsgatan 4 +d003143,Gladsaxe Kommune,DNK,DK,2860,Søborg,Rådhus Allé 7 +d003144,Śląskie Centrum Chorób Serca w Zabrzu,POL,PL,41-800,Zabrze,ul. M. Curie-Skłodowskiej 9 +d003145,Holzfällung Hausbacher,AUT,AT32,5600,St. Johann im Pongau,Hallmoos 22 +d003146,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d003147,CLINI-LAB,ROU,RO125,540342,Târgu Mureș,Str. Rodnei nr. 15 +d003148,Id Verde Agence de Lille,FRA,FRE11,59874,Wambrechies Cedex,"1re rue du Port Fluvial, CS 80065" +d003149,BWI GmbH,DEU,DE212,80637,München,Dachauer Straße 128 +d003150,Skanska Industrial Solutions AB,SWE,SE232,112 74,Stockholm,Warfvinges Väg 25 +d003151,Haigo,FRA,FR101,75010,Paris,7 rue du Paradis +d003152,OF Bygg AB,SWE,SE,903 04,Umeå,Box 3133 +d003153,Agropartner land u forstechnik GmbH,DEU,DE80J,17192,Schloen-Dratow,Tiergartenweg 3 +d003154,Ziemann Sicherheit GmbH,DEU,DE131,79227,Schallstadt,Gewerbestr. 19 -23 +d003155,FEI – Beschaffung Infrastruktur,DEU,DE30,10115,Berlin,Caroline-Michaelis-Straße 5-11 +d003156,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003157,Telecom Italia SpA,ITA,IT,,Milano (MI), +d003158,Deutsche Gesetzliche Unfallversicherung e. V. (DGUV),DEU,DE300,10117,Berlin,Glinkastr. 40 +d003159,"Labena trgovina, svetovanje in proizvodnja laboratorijske opreme d.o.o.",SVN,SI,1000,Ljubljana,Verovškova ulica 64 +d003160,IKK classic,DEU,DE,01099,Dresden, +d003161,Nantes Métropole,FRA,FRG01,44923,Nantes Cedex 9,2 cours du Champ de Mars +d003162,"Futura Soft, s.r.o.",CZE,CZ064,602 00,Brno,Příkop 843/4 +d003163,Mediplus Exim,ROU,RO322,077135,Mogoşoaia,Str. Ciobanului nr. 133 +d003164,REA Rosignano energia ambiente SpA,ITA,ITI16,57016,Rosignano Marittimo,località Le Morelline Due snc +d003165,Département de la Haute-Savoie,FRA,FRK28,74041,Annecy,23 rue de la Paix +d003166,Staatsbetrieb Sächsische Informatik Dienste,DEU,DED2,01445,Radebeul,Dresdner Straße 78 A +d003167,Southern Water Services Ltd,GBR,UKJ,,Worthing, +d003168,Stanglmeier Reisebüro-Bustouristik GmbH & Co. KG,DEU,DE226,84048,Mainburg,Industriestr. 14 +d003169,"Dirección General de Desarrollo Rural, Agricultura y Ganadería",ESP,ES220,31005,Pamplona,"C/ González Tablas, 9" +d003170,Direcţia Generală de Asistenţă Socială şi Protecţia Copilului Mureș,ROU,RO125,540081,Târgu Mureș,Str. Trebely nr. 7 +d003171,Compania Națională de Administrare a Infrastructurii Rutiere S.A.,ROU,RO113,400205,Cluj-Napoca,"Prin DRDP Cluj, Str. Decebal nr. 128" +d003172,Norconsult AB,SWE,SE232,402 76,Göteborg,Box 8774 +d003173,Vervoerservice van Driel bv,NLD,NL,5349 AT,Oss,Galliersweg 15 +d003174,Ville de Lorient,FRA,FRH04,56315,Lorient Cedex,2 boulevard Leclerc — CS 30010 +d003175,Bizmed,ROU,RO111,410297,Sântandrei,Str. Livezilor nr. 5 +d003176,Badke Baustoffe GmbH,DEU,DE408,14728,Rhinow,Neustädter Str. 1 +d003177,Viški vrtci,SVN,SI,1000,Ljubljana,Jamova cesta 23 +d003178,bbp geomatik ag,CHE,CH0,3097,Liebefeld BE,Könizstraße 161 +d003179,Netia Spółka Akcyjna,POL,PL91,02-822 Warszawa,Warszawa,ul. Poleczki 13 +d003180,Université Toulouse II — Jean Jaurès,FRA,FRJ23,,Toulouse, +d003181,Via Plus Assurances,FRA,FRY10,97139,Les Abymes,résidence Les Jardins d'Alexandre — 50/52 Vieux Bourg +d003182,"Ingeniería, Estudios y Proyectos Europeos, S. L.",ESP,ES30,28944,Fuenlabrada,"Cº de Castilla, 10" +d003183,"Amt für Arbeitslosenversicherung AVA, Arbeitsvermittlung LAM Office de l'assurance-chômage, Service de l'emploi LMMT",CHE,CH0,3018,Berne,Lagerhausweg 10 +d003184,Občina Tabor,SVN,SI,3304,Tabor,Tabor 21 +d003185,Ville de Pontault-Combault,FRA,FR102,77347,Pontault-Combault Cedex,107 avenue de la République +d003186,Sandviken Energi AB,SWE,SE313,,Sandviken, +d003187,Göteborgs Stad Inköp och upphandling,SWE,SE232,405 23,Göteborg,Box 1111 +d003188,Umeå Energi Aktiebolag,SWE,SE,901 05,Umeå,Umeå Energi Box 224 +d003189,Fundatia Pro Sovata,ROU,RO125,545500,Sovata,"Strada Lungă, Nr. 46D" +d003190,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d003191,SC FRASINUL SRL,ROU,RO112,427131,Maieru,"Strada Principala, Sat Anies, Nr. 59" +d003192,Department of Contracts,MLT,MT,FRN-1600,Floriana,Notre Dame Ravelin +d003193,Baldes Gerüstbau GmbH,DEU,DEB14,55595,Roxheim,"Hauptstr., 91" +d003194,Merazet Spółka Akcyjna,POL,PL,60-203,Poznań,ul. Krauthofera 36 +d003195,Wiener Linien GmbH & Co. KG,AUT,AT130,1030,Wien,Erdbergstraße 202 +d003196,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d003197,Hartmann Paul laboratoires,FRA,FRF11,67730,Chatenois,9 route de Sélestat +d003198,S.C. Stofe Buhuși S.A.,ROU,RO211,605100,Buhuși,Str. Libertății nr. 36 +d003199,GrassMark Oy,FIN,FI1C1,,Lieto, +d003200,Hexal AG,DEU,DE,,Holzkirchen, +d003201,MEII Mesures expertises instrumentation informatique,FRA,FR,78370,Plaisir,50 rue Pierre Curie +d003202,Imprimerie Chauveau,FRA,FRB02,28630,Gellainville, +d003203,Macon,ROU,RO423,,Cristur,Șoseaua Hunedoarei nr. 1-3 +d003204,CEZ Vânzare S.A.,ROU,RO411,200581,Craiova,"Calea Severinului nr. 97, et. 1" +d003205,Bundesagentur für Arbeit Regionales Einkaufszentrum Nord,DEU,DE,30147,Hannover,Postfach +d003206,Maggioli SpA,ITA,ITH59,47822,Santarcangelo di Romagna (RN),via del Carpino 8 +d003207,Uppsala K Skolfastigheter AB,SWE,SE121,753 30,Uppsala,Uppsala Kommun Skolfastigheter AB Salagatan 18 +d003208,Eurovia Bourgogne,FRA,FRC11,21600,Longvic, +d003209,Stichting Jeugdinterventies,NLD,NL,,JD Oegstgeest,Oude Vaartweg 2 2343 +d003210,bioMérieux AB,SWE,SE,436 33,Askim,Hantverksvägen 15 +d003211,"Kemomed, d.o.o., svetovanje, trgovina in trženje",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 31 +d003212,Consejería de Salud y Consumo,ESP,ES53,07002,Palma,"Plaça Espanya, 9" +d003213,Ruokolahden kunta,FIN,FI,FI-56100,Ruokolahti,Virastotie +d003214,Vermögen und Bau Baden-Württemberg Amt Freiburg,DEU,DE13,79104,Freiburg,Mozartstraße 58 +d003215,Optimisa,FRA,FR1,,Magny-le-Hongre, +d003216,Soliha Mayenne,FRA,FRG03,53000,Laval,21 rue de l'Ancien Évêché +d003217,HEP-Operator distribucijskog sustava d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 37 +d003218,EndoPro Implants d.o.o.,HRV,HR050,10000,Zagreb,Lašćinska 48 +d003219,S.C. Maxigel S.R.L.,ROU,RO,100070,Ploiești,"Str. Laboratorului nr. 29B, sector, județ Prahova, localitate Ploiești, cod poștal 100070" +d003220,SchoolSoft AB,SWE,SE110,114 51,Stockholm,Artillerigatan 6 +d003221,"Llop Gestió Esportiva, S. L.",ESP,ES511,08960,Sant Just Desvern, +d003222,Prognos AG,DEU,DE300,,Berlin, +d003223,Autocont a.s.,CZE,CZ080,702 00,Ostrava–Moravská Ostrava,Hornopolní 3322/34 +d003224,Expedit Finland Oy,FIN,FI1B1,,Vantaa, +d003225,Idelum,FRA,FRH04,,Gavres, +d003226,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d003227,Dom upokojencev Domžale,SVN,SI,1230,Domžale,Karantanska cesta 5 +d003228,OPTeam S.A.,POL,PL823,36-002,Jasionka,Tajęcina 113 +d003229,Északdunántúli Vízmű Zártkörűen Működő Részvénytársaság,HUN,HU212,2800,Tatabánya,Sárberek Egyéb 100 +d003230,Merianto Install Oy,FIN,FI1B,,Helsinki, +d003231,ENGIE INEO,FRA,FR103,78130,Les Mureaux,165 rue Jean Jaurès +d003232,Evident Verian,ROU,RO214,610201,Piatra Neamț,Str. General Dăscălescu nr. 365 +d003233,Direcția Județeana de Administrare a Drumurilor și Podurilor Iași,ROU,RO213,6600,Iași,Str. Ștefan cel Mare și Sfânt nr. 13 +d003234,UAB „Indastrus“,LTU,LT,,Panevėžys,Trakiškio g. 1 +d003235,Jens Looke Forst- und Gartenservice,DEU,DE405,16348,Wandlitz,Am Töppersberg 27 +d003236,Município de Oeiras,PRT,PT17,2784-501,Oeiras,Largo Marquês de Pombal +d003237,„Ekologika Sp. z o.o.”,POL,PL811,21-560 Międzyrzec Po,Rzeczyca,ul. Polna 6 +d003238,Gemeente Rotterdam,NLD,NL,3002 AN,Rotterdam,Wilhelminakade 179 +d003239,Siemens SAS,FRA,FRF33,57084,Metz,6 rue Marie de Coëtlosquet +d003240,Gemeinde Hallwang,AUT,AT,5300,Hallwang,Dorfstraße 45 +d003241,"Muralla de Rehabilitaciones, S. L.",ESP,ES112,27001,Lugo,"Rúa San Froilán, 26, P02I" +d003242,Tecnoarmit S.R.L.,ROU,RO321,061334,București,Bulevardul Timișoara nr. 210-230 +d003243,SARL Vauquier,FRA,FRD2,76330,Port-Jérôme-sur-Seine,1339 rue Maryse Bastie/ND de Gravenchon +d003244,NEOS-SDI,FRA,FRK26,69006,Lyon,34 quai Charles de Gaulle +d003245,"Tentours turistična agencija, d.o.o., Ljubljanska 85, Domžale",SVN,SI,1230,Domžale,Ljubljanska cesta 85 +d003246,Rossing Åkeri & Logistik AB,SWE,SE,302 30,Halmstad,Handelsvägen 13 +d003247,Cetin a.s.,CZE,CZ010,,Praha 9, +d003248,Väylävirasto,FIN,FI,FI-00521,Helsinki,PL 33 (Opastinsilta 12 A) +d003249,Haviland - Cel Gemeentelijke Bouwwerken,BEL,BE241,1731,Zellik,Brusselsesteenweg 617 +d003250,Infonet Projekt S.A.,POL,PL225,43-300,Bielsko-Biała,ul. Towarowa 2 +d003251,Daser,ITA,IT,,Treviso, +d003252,Somair Gervat Hydralians,FRA,FRL06,84800,Isle-sur-la-Sorgue,ZI de la Grande Marine +d003253,Fresenius Kabi nv/sa,BEL,BE,2627,Schelle,Brandekensweg 9 +d003254,ANAS SpA,ITA,ITC11,00185,Roma,via Monzambano 10 +d003255,Centre communal d'action sociale de la Ville de Lorient,FRA,FRH04,,Lorient,50 cours de Chazelles +d003256,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d003257,VRTEC HANSA CHRISTIANA ANDERSENA,SVN,SI,1000,Ljubljana,Rašiška ulica 7 +d003258,Roche diagnostics France,FRA,FRK24,38242,Meylan Cedex,2 avenue du Vercors — CS 60059 +d003259,"IRIS, Mednarodna trgovina, d.o.o.",SVN,SI,1000,Ljubljana,Cesta v Gorice 8 +d003260,"Mantenimiento y Servicios Tecman, S. L.",ESP,ES111,15570,Narón,"Estrada de Cedeira, 209" +d003261,"DOM SISTEMI družba za upravljanje, inženiring in poslovno svetovanje, d.o.o.",SVN,SI,4000,Kranj,Ulica Lojzeta Hrovata 3A +d003262,"Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.",SVN,SI,2000,Maribor,Zagrebška cesta 22 +d003263,"Johnson & Johnson, Lda.",PRT,PT170,2740-262,Porto Salvo,"Lagoas Park, edifício 9" +d003264,Naturstyrelsen,DNK,DK04,7183,Randbøl,Førstballevej 2 +d003265,Husitské muzeum v Táboře,CZE,CZ031,390 01,Tábor,nám. Mikuláše z Husi 44 +d003266,Asclepios S.A.,POL,PL,50-502,Wrocław,ul. Hubska 44 +d003267,Landwirtschaftliche Rentenbank,DEU,DE712,60486,Frankfurt am Main,Theodor-Heuss-Allee 80 +d003268,Etelä-Pohjanmaan sairaanhoitopiirin kuntayhtymä,FIN,FI194,,Seinäjoki, +d003269,Costacos Com,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d003270,Oktal Pharma d.o.o.,HRV,HR050,10020,Zagreb,Utinjska 40 +d003271,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003272,Ista Deutschland GmbH,DEU,DEA,45131,Essen,Luxemburger Str. 1 +d003273,Azienda Zero,ITA,ITH3,35131,Padova,passaggio Gaudenzio 1 +d003274,Schindler,FRA,FR103,78141,Vélizy-VIllacoublay,5 rue Dewotine +d003275,NOVA TECH MED,ROU,RO321,021997,Bucuresti,"Strada Zagoritz Alexandru, arh., Nr. 19, Sector: 2" +d003276,Fakultní nemocnice Olomouc,CZE,CZ071,779 00,Olomouc,I. P. Pavlova 185/6 +d003277,Région Guadeloupe,FRA,FRY10,97100,Basse-Terre,avenue Paul Lacave +d003278,"Landkreis Börde, Zentrale Vergabestelle",DEU,DEE07,39387,Oschersleben (Bode),Triftstr. 9-10 +d003279,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d003280,"Radiotelevizija Slovenija javni zavod, Ljubljana",SVN,SI,1000,Ljubljana,Kolodvorska ulica 2 +d003281,Societatea Română de Televiziune,ROU,RO321,010565,Bucureşti,Str. Dorobanţi nr. 191 +d003282,Gemeente Nissewaard,NLD,NL,,Spijkenisse, +d003283,Centre hospitalier universitaire,FRA,FRD11,14033,Caen,DRMA — cellule marchés publics — avenue Georges Clemenceau +d003284,Sihtasutus Pärnu Haigla,EST,EE,80010,Pärnu linn,Ristiku tn 1 +d003285,Ville de Solliès-Pont,FRA,FRL05,83210,Solliès-Pont,1 rue de la République +d003286,Metall-&Stahlbau Kurts,DEU,DEE07,39218,Schönebeck,Glinder Straße 3 +d003287,Aktsiaselts Nõo Lihatööstus,EST,EE,61601,Nõo vald,Voika tn 18 +d003288,Municipia SpA,ITA,ITH20,38122,Trento,via Adriano Olivetti 7 +d003289,RATP,FRA,FR10,75599,Paris Cedex 12,"Lac B916, 54 quai de la Rapée" +d003290,SOS Security S.R.L.,ROU,RO214,610109,Piatra Neamț,Str. Mărășești nr. 50 +d003291,Landesforst Mecklenburg-Vorpommern AöR,DEU,DE80J,17139,Malchin,Fritz-Reuter-Platz 9 +d003292,Siemens Healthcare SAS,FRA,FR,93527,Saint-Denis,40 avenue des Fruitiers +d003293,Gällivare Kommun,SWE,SE332,982 81,Gällivare,Tingshusgatan 8-10 +d003294,Rex-rotary,FRA,FR1,93631,La Plaine-Saint-Denis,03 rue Jess Owens +d003295,Techtex,ROU,RO321,013685,București,Str. Bucureşti-Ploieşti nr. 42-44 +d003296,Caverion Industria Oy,FIN,FI1B1,,Vantaa, +d003297,Action Logement Services,FRA,FR101,75013,Paris,19/21 quai d'Austerlitz +d003298,Wex Fleet France SAS,FRA,FR101,75008,Paris,102 avenue des Champs-Elysées +d003299,EurimPharm Arzneimittel GmbH,DEU,DE,,Saaldorf-Surheim, +d003300,VšĮ „Versli Lietuva“,LTU,LT,LT-01112,Vilnius,Goštauto g. 40A +d003301,AMJ Turku Audio Oy,FIN,FI1C1,,Lieto, +d003302,OÜ Võlukaloss,EST,EE,74305,Anija vald,Tuleviku tn 5 +d003303,Beschuttende Werkplaats Pajottenland vzw,BEL,BE,1750,Lennik,Luitenant Jacopsstraat 11 +d003304,"Chemass d.o.o., merilni sistemi",SVN,SI,1000,Ljubljana,Baznikova ulica 2 +d003305,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d003306,Ajuntament de Viladecavalls,ESP,ES51,08232,Viladecavalls,"C/ Antoni Soler Hospital, 7-9" +d003307,Scan Expert,ROU,RO213,700032,Iași,Str. Sfântul Sava nr. 18 +d003308,Elektro-Energetyka Aleksander Jakub Zduńczyk,POL,PL922,,Regimin, +d003309,"Inforet Medio Ambiente, S. L.",ESP,ES418,,Valladolid, +d003310,Geaprodukt trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d003311,K&S Gebäudetechnik mbH,DEU,DEA17,46149,Oberhausen,Im Erlengrund 17a +d003312,Office national des forêts — agence Vosges-Ouest,FRA,FRF34,88000,Épinal,4 rue André-Vitu +d003313,Grupa Azoty Zakłady Azotowe Kędzierzyn S.A.,POL,PL52,47-220,Kędzierzyn-kOźle,ul. Mostowa 30A +d003314,Česká republika - Ministerstvo spravedlnosti,CZE,CZ010,128 10,Praha 2,Vyšehradská 16 +d003315,"Universität Tübingen, Dezernat VII-Finanzen, Abteilung Einkauf",DEU,DE142,72074,Tübingen,Geschwister-Scholl-Platz +d003316,"Thomy F.E., medicinska zastopstva, trgovina, marketing in posredovanje, d.o.o.",SVN,SI,1236,Trzin,Brodišče 24 +d003317,"Oracle Ibérica, S. R. L.",ESP,ES300,28046,Madrid,"Paseo de la Castellana, 81" +d003318,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d003319,"Lavado de Textiles, S. L.",ESP,ES521,03190,Pilar de la Horadada,"C/ Pintores, 2" +d003320,edilon sedra GmbH,DEU,DE,65201,Wiesbaden,Schossbergstraße 19 +d003321,EWN Entsorgungswerk für Nuklearanlagen GmbH,DEU,DE80N,17509,Rubenow,Latzower Straße 1 +d003322,Plurima SpA,ITA,ITC4C,20122,Milano,piazza Santo Stefano 6 +d003323,GOODZO bv,NLD,NL,,Rotterdam, +d003324,VWR International GmbH,DEU,DED21,01127,Dresden,Großenhainer Straße 99 +d003325,Swerock Aktiebolag,SWE,SE232,262 24,Ängelholm,Box 1281 +d003326,Frontline Services bv,NLD,NL,4131 NJ,Vianen,Lange Dreef 15a +d003327,Commune de Noisy-le-Roi,FRA,FR103,78590,Noisy-le-Roi,37 rue André Le Bourblanc +d003328,Stadt Versmold,DEU,DEA42,33775,Versmold,Münsterstraße 16 +d003329,Les Abeilles,FRA,FRD22,76058,Le Havre Cedex,"6 rue Dupleix, BP 546" +d003330,"Foment del Reciclatge, S. A.",ESP,ES511,,Sabadell, +d003331,Rogaland Fylkeskommune,NOR,NO0A1,4010,Stavanger,Arkitekt Eckhoffsgate 1 +d003332,Jönköpings kommun,SWE,SE211,551 89,Jönköping,Stadskontoret +d003333,"Sanolabor, podjetje za prodajo medicinskih, laboratorijskih in farmacevtskih proizvodov, d.d.",SVN,SI,1000,Ljubljana,Leskoškova cesta 4 +d003334,Colas Nord-Est,FRA,FRC11,21600,Longvic, +d003335,Groupe Pierre le Goff,FRA,FRG01,44480,Saint-Aignan-de-Grand-Lieu, +d003336,Blitz Blank Peterhoff GmbH,DEU,DE300,,Berlin, +d003337,Agence Presence,FRA,FRE11,59110,La Madeleine,31 rue du Général-de-Gaulle +d003338,ZCCS,FRA,FR101,75010,Paris,47 rue de Paradis +d003339,"Slovak Telekom, a.s.",SVK,SK010,817 62,Bratislava,Bajkalská 28 +d003340,KGP Events GmbH,AUT,AT,1180,Wien,Schindlergasse 17/2 +d003341,"SITEL, spol. s r.o.",CZE,CZ01,140 00,Praha,Baarova 957/15 +d003342,Presidencia de la Confederación Hidrográfica del Ebro,ESP,ES243,50071,Zaragoza,"Paseo Sagasta, 24-28" +d003343,"Anastácio Saldanha, Unipessoal, Lda.",PRT,PTZZZ,1685-253,Famões,"Rua Major João Luís de Moura, armazém J, Famões Park" +d003344,Association Arc en Ciel,FRA,FRE11,59460,Jeumont,3 résidence les Marroniers +d003345,Bau- und Liegenschaftsbetrieb NRW Duisburg,DEU,DEA12,47051,Duisburg,Friedrich-Wilhelm-Str. 12 +d003346,Staatsbosbeheer,NLD,NL,3811 MG,Amersfoort,Smallepad 5 +d003347,Centre interdépartemental de gestion de la Grande Couronne,FRA,FR103,78008,Versailles,15 rue Boileau +d003348,Busse-Aufzüge GmbH,DEU,DEA5A,57074,Siegen,Martinshardt 1 +d003349,Berlin Partner für Wirtschaft und Technologie GmbH,DEU,DE300,10623,Berlin,Fasanenstr. 85 +d003350,Biotronik AB,SWE,SE11,103 25,Stockholm,P.O. Box 162 85 +d003351,Fichot Hygiène,FRA,FR103,28300,Mainvilliers,26 rue Jean-Perrin +d003352,Euromed trgovina in storitve d.o.o.,SVN,SI,1351,Brezovica pri Ljubljani,Podpeška cesta 14 +d003353,"Želva podjetje za usposabljanje in zaposlovanje invalidov, d.o.o. Ljubljana",SVN,SI,1000,Ljubljana,Ulica Alme Sodnik 6 +d003354,Kiinteistö Oy Auroranlinna,FIN,FI1B,FI-00240,Helsinki,Eevankatu 2 +d003355,Zurli & Waly srl,ITA,ITF22,,Castelmauro (CB),via Calvario 1 +d003356,UAB „TELE2“,LTU,LT,,Vilnius, +d003357,Ostravská univerzita,CZE,CZ080,701 03,Ostrava,Dvořákova 7 +d003358,Castrén Engine Osakeyhtiö,FIN,FI1B1,,Helsinki, +d003359,MSS Security GmbH,DEU,DEA18,42853,Remscheid, +d003360,RWE Generation SE,DEU,DEA13,45141,Essen,RWE Platz 3 +d003361,Recover AS,NOR,NO08,,Oslo, +d003362,Gemeente Schiedam,NLD,NL,,Schiedam, +d003363,Maria Manuela da Costa Pereira,PRT,PT170,,Lisboa, +d003364,Festo Didactic SE,DEU,DE113,,Denkendorf, +d003365,"Heinrich Schmid GmbH & Co. KG, Geschäftsbereich Akustik + Schall",DEU,DED2F,01734,Rabenau, +d003366,Stadt Neumarkt i.d.OPf.,DEU,DE236,92318,Neumarkt in der Oberpfalz,Rathausplatz 1 +d003367,Eurovia,FRA,FRH01,22440,Ploufragan,"La Côte Boto, BP 39" +d003368,Agropartner land u forstechnik GmbH,DEU,DE80J,17192,Schloen-Dratow,Tiergartenweg 3 +d003369,Sogeti ingénierie airports,FRA,FRJ,33600,Pessac,31 avenue Gustave Eiffel +d003370,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d003371,"AV Media, a.s.",CZE,CZ010,102 00,Praha 10,"Pražská 1335/63, Hostivař" +d003372,IKK Engineering GmbH,AUT,AT,8020,Graz,Reininghausstraße 78 +d003373,Generalzolldirektion Zentrale Beschaffungsstelle der Bundesfinanzverwaltung,DEU,DE713,63069,Offenbach a. M.,Friedrichsring 35 +d003374,Svartemadens Potatis AB,SWE,SE232,534 94,Vara,Tumleberg Svartemad 1 +d003375,Arffman Finland Oy,FIN,FI,FI-87250,Kajaani,Ahontie 1 +d003376,Stadt Hamminkeln,DEU,DEA1F,46499,Hamminkeln,Brüner Str. 9 +d003377,m 4 Ingenieure GmbH,DEU,DE212,80333,München,Augustenstr. 10 +d003378,"Landeshauptstadt München, IT-Referat, it@M, Geschäftsleitung",DEU,DE212,80992,München,Agnes-Pockels-Bogen 21 +d003379,Veidekke Industri AS,NOR,NO,0278,Oslo,Skabos vei 4 PB 508 Skøyen +d003380,"Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle",DEU,DED41,09111,Chemnitz,Friedensplatz 1 +d003381,Miejskie Przedsiębiorstwo Gospodarki Komunalnej Sp. z o.o.,POL,PL,38-200,Jasło,ul. P. Skargi 86 A +d003382,ASB Region Düsseldorf e.V.,DEU,DEA11,40217,Düsseldorf,Kronprinzenstr.123 +d003383,Junta de Gobierno del Ayuntamiento de Novelda,ESP,ES521,03660,Novelda,"Plaza de España, 1" +d003384,Javni lekarniški zavod Gorenjske lekarne,SVN,SI,4000,Kranj,Gosposvetska ulica 12 +d003385,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d003386,Klinika za dječje bolesti Zagreb,HRV,HR050,10000,Zagreb,Vjekoslava Klaića 16 +d003387,mevis.tv GmbH,DEU,DE11,70182,Stuttgart,Blumenstraße 42 +d003388,Métropole de Lyon,FRA,FRK26,69505,Lyon,"20 rue du Lac, CS 33569, 20 rue du Lac, CS 33569" +d003389,Languedoc Toitures,FRA,FR,34670,Baillargues,Ancienne gare route de la Gare +d003390,"Xanadu, a.s.",CZE,CZ01,106 00,Praha,Žirovnická 2389/1a +d003391,Conseil général du Var,FRA,FRL05,83076,Toulon,"Direction des infrastructures et de la mobilité, 390 avenue des Lices, CS 41303" +d003392,Bundesanstalt für Immobillienaufgaben,DEU,DE300,10623,Berlin,Fasanenstraße 87 +d003393,Instalaciones y Mantenimientos Imafer,ESP,ES111,15570,Narón,Rúa Vidrieiros +d003394,SA Vendee cyclisme,FRA,FRG05,85140,Essarts-en-Bocage,19 rue Arsène Mignen +d003395,Marron TP,FRA,FRD2,02000,Laon,65 rue de Manoise +d003396,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d003397,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003398,David Synák,CZE,CZ064,612 00,Brno,Poděbradova 129 +d003399,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d003400,Genesis Pharma Cyprus Ltd.,CYP,CY,2025 Στρόβολος,Λευκωσία,"Αμφιπόλεως 2, 1ος όροφος" +d003401,Stadt Sankt Augustin,DEU,DEA2C,53757,Sankt Augustin,Markt 1 +d003402,Maxman,ROU,RO115,440210,Satu Mare,"Strada -, Nr. -" +d003403,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d003404,SMACL,FRA,FRH,79031,Niort,141 avenue Salvador Allende +d003405,Tudor Print and Signs,GBR,UKG21,,Acle,Unit 11 Damgate Lane +d003406,MTDA,FRA,FRL04,13770,Venelles,47 avenue des Ribas +d003407,CHUBB France,FRA,FRF31,54320,Maxéville,6 rue Alfred Kastler +d003408,ESTM/EPA/ENSTA Bretagne,FRA,FRH02,29200,Brest,2 rue François-Verny +d003409,Sogn Elektro AS,NOR,NO0A2,6856,Sogndal,Mannhellervegen 100 +d003410,Abfallwirtschaft Dithmarschen GmbH,DEU,DEF05,25746,Heide,Rungholtstraße 9 +d003411,Stadapharm GmbH,DEU,DE,,Bad Vilbel, +d003412,"Omega svetovanje, inženiring, razvoj in raziskovanje, d.o.o.",SVN,SI,1000,Ljubljana,Dolinškova ulica 8 +d003413,Commune de Cannes,FRA,FRL03,06406,Cannes,"place Cornut Gentille, CS 30140" +d003414,Viešoji įstaiga Vilniaus universiteto ligoninės Žalgirio klinika,LTU,LT,LT-08217,Vilnius,Žalgirio g. 117 +d003415,Valtex & Co. trgovina in zastopstva d.o.o.,SVN,SI,1000,Ljubljana,Koprska ulica 62A +d003416,Mittetulundusühing Valga Arvutikeskus,EST,EE,68204,Valga vald,Vabaduse tn 22-7 +d003417,Blum & Schultze Architekten PartG mbB,DEU,DED2,01324,Dresden,Plattleite 43 +d003418,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d003419,ARE 33,FRA,FRI12,33000,Bordeaux, +d003420,Investing CZ spol. s.r.o.,CZE,CZ051,460 01,Liberec,Štefánikovo nám. 780 +d003421,Lidköpings kommun,SWE,SE232,531 88,Lidköping,Skaragatan 8 +d003422,Trollhättans kommun,SWE,SE232,461 83,Trollhättan,Gärdhemsvägen 9 +d003423,Città metropolitana di Torino,ITA,ITC11,10138,Torino, +d003424,Octapharma AG,CHE,CH,8853,Lachen,Seidenstrasse 2 +d003425,Department of Contracts,MLT,MT,FRN-1600,Floriana,Notre Dame Ravelin +d003426,Bayerisches Landesamt für Umwelt,DEU,DE271,86179,Augsburg,Bürgermeister-Ulrich Str. 160 +d003427,Mark Medical trgovina in storitve d.o.o.,SVN,SI,6210,Sežana,Partizanska cesta 109 +d003428,Tempo-Team Uitzenden bv,NLD,NL,,Diemen, +d003429,VCE Vienna Consulting Engineers ZT GmbH,AUT,AT,1030,Wien,Untere Viaduktgasse 2 +d003430,VĮ Lietuvos automobilių kelių direkcija,LTU,LT,LT-03109,Vilnius,J. Basanavičiaus g. 36 +d003431,Hett Tech AB,SWE,SE110,192 72,Sollentuna,Sjöängsvägen 15 +d003432,verde GaLaBau GmbH,DEU,DEE0B,,Steigra, +d003433,Solcom GmbH,DEU,DE141,72766,Reutlingen,Schuckertstraße 1 +d003434,Centre social protestant Berne-Jura,CHE,CH0,2720,Tramelan,Rue de la Promenade 14 +d003435,"Angiomedic, trgovina in storitve, d.o.o.",SVN,SI,1000,Ljubljana,Zemljemerska ulica 12 +d003436,"Braintec podjetje za sodobne tehnologije, d.o.o.",SVN,SI,1000,Ljubljana,Cesta Andreja Bitenca 68 +d003437,"PETROL, Slovenska energetska družba, d.d., Ljubljana",SVN,SI,1000,Ljubljana,Dunajska cesta 50 +d003438,"TME Trade, s.r.o.",CZE,CZ01,100 00,Praha 10,Petrovická 155/9 +d003439,Karosseriebau Scharff,DEU,DEA1A,42277,Wuppertal,Rosenau 1A +d003440,Staatliches Bauamt Bamberg,DEU,DE241,96049,Bamberg,Kasernstraße 4 +d003441,REMONDIS GmbH & Co. KG,DEU,DEA51,44805,Bochum,Dieselstraße 3 +d003442,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d003443,Pleno del Ayuntamiento de El Cuervo de Sevilla,ESP,ES618,41749,El Cuervo de Sevilla,"Plaza de la Constitución, 2" +d003444,Computacenter AG & Co. oHG,DEU,DE,12099,Berlin,Mariendorfer Damm 1 +d003445,Département de la Charente-Maritime,FRA,FRI32,17000,La Rochelle, +d003446,AOK Baden-Württemberg,DEU,DE1,70191,Stuttgart,Presselstraße 19 +d003447,"Medis, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d003448,Abbott Rapid Diagnostics AB,SWE,SE110,164 22,Kista,Box 1147 +d003449,Telecom Italia SpA,ITA,IT,,Milano (MI), +d003450,AOK PLUS — Die Gesundheitskasse für Sachsen und Thüringen,DEU,DEG,99084,Erfurt,Augustinerstraße 38 +d003451,Okręgowe Przedsiębiorstwo Energetyki Cieplnej Sp. z o.o.,POL,PL633,81-213,Gdynia,Opata Hackiego 14 +d003452,Schneider Bauunternehmung GmbH & Co. KG,DEU,DE143,72401,Haigerloch,Hanfland 1 +d003453,AM 22 srl,ITA,ITI43,,Palombara Sabina, +d003454,Deutsche Post InHaus Services GmbH,DEU,DEA22,,53121 Bonn, +d003455,TBF + Partner AG,CHE,CH0,8042,Zürich,Beckenhofstraße 35 +d003456,Strate Ingénierie,FRA,FRE11,59650,Villeneuve-d'Ascq,14 rue Haddock +d003457,Degen GmbH & Co. KG,DEU,DE254,,Nürnberg, +d003458,Poste italiane SpA,ITA,IT,,Roma, +d003459,Minerva - Graphica d.o.o.,HRV,HR,10292,Gornji Laduč,Zagrebačka cesta 89 +d003460,Epsilon Cities,BEL,BE,3960,Bree,Industrieterrein Kanaal Noord 1159 +d003461,"PRO-GEM svetovanje, marketing, d.o.o. Ljubljana",SVN,SI,1000,Ljubljana,Cesta na Brdo 85 +d003462,MDO cotraitant,FRA,FRB02,28240,La Loupe,11 bis avenue de Beauce — 28240 La Loupe +d003463,Intesa Sanpaolo RBM Salute SpA,ITA,ITH35,,Venezia Mestre, +d003464,Artsanity srl,ITA,IT,,Treviso, +d003465,"Z+M Logistics, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Gorkého 621/26, Moravská Ostrava" +d003466,Parc national de Port-Cros,FRA,FRL05,83400,Hyères,181 allée du Castel-Sainte-Claire +d003467,CERRA — Marietton Pro,FRA,FRK26,69670,Vaugneray,RD 30 — circuit Marietton +d003468,CUC Area vasta — sede territoriale di Valle Trompia,ITA,ITC47,25063,Brescia,via Matteotti 327 — 25063 Gardone VT +d003469,VetAgro Sup,FRA,FRK26,69280,Marcy-l'Étoile,1 avenue Bourgelat +d003470,Nantes Métropole,FRA,FRG01,44923,Nantes Cedex 9,2 cours du Champ de Mars +d003471,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d003472,Vrtec Pod gradom,SVN,SI,1000,Ljubljana,Praprotnikova ulica 2 +d003473,AB Ängelholmshem,SWE,SE224,262 22,Ängelholm,Box 1111 +d003474,W. Rokitzky AG,CHE,CH0,8057,Zürich,Winterthurerstraßse 284 +d003475,Staatliches Bauamt München 1,DEU,DE212,81547,München,Peter-Auzinger-Straße 10 +d003476,OÜ Nelijakk,EST,EE,63306,Põlva vald,Võru tn 4 +d003477,Kemmlit Bauelemente GmbH,DEU,DE142,72144,Dusslingen, +d003478,Samhall Aktiebolag,SWE,SE1,111 64,Stockholm,"Klarabergsviadukten 90, Hus C Box 27705" +d003479,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d003480,HKF Haustechnik GmbH,DEU,DE,23992,Krassow,Kastanienallee 56 +d003481,BOMI-LAB d.o.o.,HRV,HR050,10000,Zagreb,Gajeva 35 +d003482,Proklima GmbH,DEU,DE712,90411,Nürnberg,Nordostpark 76 +d003483,Securitas Sverige Aktiebolag,SWE,SE212,102 29,Stockholm,Box 12516 +d003484,TMH Tourismus Management Hessen UG (haftungsbeschränkt),DEU,DE714,65189,Wiesbaden,Frankfurter Str. 2 +d003485,"Mylan Healthcare GmbH (A Viatris company), Zweigniederlassung Bad Homburg",DEU,DE71,61352,Bad Homburg,Benzstraße 1 +d003486,"Labohem trgovina, zastopstvo, posredništvo, d.o.o.",SVN,SI,1230,Domžale,Kettejeva ulica 16 +d003487,Mairie de Montry,FRA,FR102,77450,Montry,25 avenue de la Mairie +d003488,Autostrade per l'Italia SpA,ITA,ITI43,00159,Roma,via A. Bergamini 50 +d003489,Baltrade Oy,FIN,FI,FI-01120,Västerskog,Sipoonranta 10 B LT 1 +d003490,New Gorbals Housing Association c/o Bruce Stevenson Insurance Brokers,GBR,UKM82,G4 9JT,Glasgow,144 West George Street +d003491,SoftwareOne Deutschland GmbH,DEU,DEA11,81829,München,Konrad-Zuse-Platz 2 +d003492,Siemens Healthcare SAS,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d003493,Aviva Italia SpA,ITA,ITC4C,,Milano, +d003494,Serviciul Județean de Dezinsecție și Ecologizare Mediu Ilfov,ROU,RO322,077135,Mogoșoaia,"Str. Colentina nr. 1, localitatea Mogoșoaia, județul Ilfov" +d003495,Eurofins Labtium Oy,FIN,FI1B,,Espoo, +d003496,Trifyl,FRA,FRJ27,81300,Labessière-Candeil,3316 route de Sieurac +d003497,Cowi A/S,DNK,DK012,2800,Kongens Lyngby,Parallelvej 2 +d003498,"PD Medical, razvoj, proizvodnja in trženje medicinskih proizvodov d.o.o.",SVN,SI,4208,Šenčur,Poslovna cona A 10 +d003499,Île-de-France mobilités,FRA,FR1,75009,Paris,39 bis-41 rue de Châteaudun +d003500,Hiscox / Sarre et Moselle,FRA,FRH,57400,Sarrebourg,17 avenue Poincare +d003501,Žilinský samosprávny kraj,SVK,SK031,011 09,Žilina,Komenského 48 +d003502,Przedsiębiorstwo Handlowo-Usługowe Anmar Sp. z o.o. Sp. k.,POL,PL22,43-100,Tychy,ul. Strefowa 22 +d003503,Direzione di intendenza della Marina militare — Roma,ITA,ITI43,00135,Roma,via Taormina 4 +d003504,AG Complex Sp. z o.o.,POL,PL911,,Warszawa, +d003505,Luleå kommun,SWE,SE332,971 85,Luleå,Luleå kommun Luleå kommun +d003506,Lusk Motor Factors Ltd T/A Swords Motor Factors,IRL,IE,Co. Dublin,Dublin,"Forest Rd, Swords" +d003507,Dynergie,FRA,FR,69009,Lyon,1 place Verrazzano +d003508,ENEDIS,FRA,FR,92079,Paris La Défense,Tour ENEDIS 34 place des Corolles Courbevoie +d003509,Gironde Habitat,FRA,FRI12,33074,Bordeaux,"40 rue d'Armagnac, CS 71232" +d003510,Dirección General de Patrimonio y Contratación Centralizada,ESP,ES431,06800,Mérida,"Paseo de Roma, s/n, módulo A, 2.ª planta" +d003511,Vrtec Ciciban,SVN,SI,1000,Ljubljana,Šarhova ulica 29 +d003512,SDIS de la Loire,FRA,FRK25,42007,Saint-Etienne Cedex 1,BAJM 8 rue du Chanoine Ploton — CS 50541 +d003513,Conseil général du Val d'Oise,FRA,FR108,95032,Cergy-Pontoise Cedex,"2 avenue du Parc, CS 20201 Cergy" +d003514,Viški vrtci,SVN,SI,1000,Ljubljana,Jamova cesta 23 +d003515,Polkka – Pohjois-Karjalan tukipalvelut oy,FIN,FI1D3,,Joensuu, +d003516,Koblenzer Bäder GmbH,DEU,DEB11,56068,Koblenz,Peter-Altmeier-Ufer 50 +d003517,Södersjukhuset Aktiebolag,SWE,SE11,118 83,Stockholm,x +d003518,"Vermican Soluciones de Compostaje, S. L.",ESP,ES220,,Cordovilla, +d003519,EVO 01,FRA,FRK21,01000,Bourg-en-Bresse, +d003520,Loial Impex,ROU,RO215,727525,Scheia,Str. Oborului nr. 75A +d003521,N.E.A. srl,ITA,IT,,Piovera (AL), +d003522,BOMA nv,BEL,BE,2030,Antwerpen 3,Noorderlaan 131 +d003523,Artelia SAS,FRA,FR,69760,Limonest,135 allée des Noisetiers — bât A +d003524,Scan Water,NOR,NO,1415,Oppegård,Haukeliveien 48 +d003525,GEAPRODUKT trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d003526,Groupe Pierre le Goff,FRA,FRG01,44480,Saint-Aignan-de-Grand-Lieu, +d003527,"Základní škola Svitavy, Riegrova 4",CZE,CZ053,568 02,Svitavy,Riegrova 600/4 +d003528,Brenntag,ROU,RO322,077040,Chiajna,Str. Gării nr. 1 +d003529,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003530,Atlas Medical,ROU,RO125,540252,Târgu Mureș,Str. Voinicenilor nr. 62 +d003531,Dom starejših občanov Tezno,SVN,SI,2000,Maribor,Panonska ulica 41 +d003532,IHB Brandenburg GmbH,DEU,DE404,14482,Potsdam, +d003533,Systeema Oy,FIN,FI1D3,FI-80100,Joensuu,Aspitie 2 +d003534,CAR s.c.p.a.,ITA,ITI43,00012,Guidonia Montecelio (RM),via Tenuta del Cavaliere 1 +d003535,Heiko Bölling Dachdeckermeister GmbH,DEU,DE929,,Laatzen, +d003536,EARL les Vetivers,FRA,FRY10,97129,Lamentin,Castel +d003537,Stadt Mitterteich,DEU,DE23A,95666,Mitterteich,Kirchplatz 12 +d003538,Medgal sp. z o.o.,POL,PL84,16-001,Księżyno,ul. Niewodnicka 26a +d003539,Creaspace,FRA,FR104,91940,Les Ulis,"19 avenue des Indes, parc de Courtabœuf" +d003540,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d003541,"Feiraco Lácteos, S. L.",ESP,ES111,15864,Ames (A Coruña),"Lugar Arufe, s/n, Agrón" +d003542,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d003543,Outokummun kaupunki,FIN,FI1D3,,Outokumpu, +d003544,Silvacultura S.R.L.,ROU,RO125,545500,Sovata,"Str. Minei nr. 4, Sovata, Mureș" +d003545,Stadt Neubukow,DEU,DE80K,18233,Neubukow,Am Markt 1 +d003546,"Instituto Catalán de la Salut, Centro Corporativo (ICS)",ESP,ES51,08007,Barcelona,"Gran Vía de les Corts Catalanes, 587, Geréncia de Compras y Política de Distribución" +d003547,Terre d'Opale Habitat — Office public de l'habitat,FRA,FRE12,62103,Calais,"16 quai de la Gendarmerie, CS 50128" +d003548,"Kemofarmacija, veletrgovina za oskrbo zdravstva, d.d.",SVN,SI,1000,Ljubljana,Cesta na Brdo 100 +d003549,"Biomedica ČS, s.r.o.",CZE,CZ010,158 00,Praha 5,Radlická 740/113d +d003550,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d003551,SUPTel a.s.,CZE,CZ03,312 00,Plzeň,Hřbitovní 1322/15 +d003552,Junta de Gobierno del Ayuntamiento de Lugo,ESP,ES112,27002,Lugo,"Ronda da Muralla, 197 (Centro Servizos Municipais)" +d003553,Roche Diagnostics Deutschland GmbH,DEU,DE126,,Mannheim, +d003554,Ribal TP,FRA,FRY30,97333,Cayenne,"ZI Collery, 4-01 rue des Morphos, BP 548" +d003555,Bundesamt für Straßen ASTRA Filiale Zofingen,CHE,CH0,4800,Zofingue,Brühlstrasse 3 +d003556,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003557,UAB „B. Braun medical“,LTU,LT,LT-05132,Vilnius,Viršuliškių skg. 34-1 +d003558,Spitalul Clinic Județean Mureș,ROU,RO125,540072,Târgu Mureș,"Str. Bernady Gyorgy nr. 6, sector: -, județ Mureș" +d003559,"Siemens Healthcare, s.r.o.",CZE,CZ010,140 00,Praha,Budějovická 779/3b +d003560,"Arribas Center, S. L.",ESP,ES511,08349,Cabrera de Mar, +d003561,Aktsiaselts Nõo Lihatööstus,EST,EE,61601,Nõo vald,Voika tn 18 +d003562,Nixu Oyj,FIN,FI1B,,Espoo, +d003563,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d003564,VR-Yhtymä Oy,FIN,FI,FI-00101,Helsinki,PL 488 +d003565,European Commission,BEL,BE100,1049,Brussels,B232 5/P047 +d003566,ARGE Nürtingen-Metzingen-Reutlingen c/o Schweerbau GmbH & Co. KG,DEU,DE928,31655,Stadthagen, +d003567,Nocker Metallbau GmbH,AUT,AT33,6145,Navis,Außerweg 62b +d003568,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003569,Kontiolahden seurakunta,FIN,FI1D3,,Kontiolahti, +d003570,Région Guadeloupe,FRA,FRY10,97100,Basse-Terre,avenue Paul Lacave — Petit Paris +d003571,Ville de Bourg-de-Péage,FRA,FRK23,26301,Bourg-de-Péage,rue du Docteur Eynard +d003572,Medtronic Aktiebolag,SWE,SE11,164 21,Kista,Box 1034 +d003573,Scania Danmark A/S,DNK,DK0,2635,Ishøj,Industribuen 19 +d003574,Universitatea „Alexandru Ioan Cuza” Iași,ROU,RO213,700506,Iași,Str. Carol I nr. 11 +d003575,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d003576,Fundación de Gestión Sanitaria del Hospital de la Santa Creu i Sant Pau,ESP,ES511,08025,Barcelona,"C/ Sant Antoni Maria Claret, 167, planta baja, pabellón Sant Antoni" +d003577,"Nomago, storitve mobilnosti in potovanj, d.o.o.",SVN,SI,1000,Ljubljana,Vošnjakova ulica 3 +d003578,Amstein + Walthert,FRA,FRK26,69003,Lyon,57 boulevard Marius Vivier Merle +d003579,EMRAmed Arzneimittel GmbH,DEU,DE,,Trittau, +d003580,MVZ Landau a. d. I. GmbH,DEU,DE22C,94405,Landau a. d. I.,Bayerwaldring 17 +d003581,Contrôle environnement qualité,FRA,FRH04,,Brech, +d003582,Commune de Bastia,FRA,FRM,20410,Bastia,avenue Pierre Giudicelli +d003583,Spirale Print,FRA,FR101,75017,Paris,2-4 rue Barye +d003584,Wald und Holz NRW,DEU,DEA33,48147,Münster,Albrecht-Thaer-Straße 34 +d003585,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d003586,Ziekenhuisnetwerk Antwerpen,BEL,BE211,2000,Antwerpen,Lange Beeldekensstraat 267 +d003587,Monetăria Statului,ROU,RO321,050183,Bucureşti,Str. Fabrica de Chibrituri nr. 30 +d003588,Consejo Rector del Instituto de Empleo y Desarrollo Socioeconómico y Tecnológico de la Diputación Provincial de Cádiz,ESP,ES612,11007,Cádiz,"C/ Tamarindo, 12 bajo" +d003589,Svanen ApS,DNK,DK011,2300,København,Azaleagangen 38 +d003590,Guérin Logistique SAS,FRA,FRK25,42160,Andrézieux-Bouthéon,ZAC les Vollons +d003591,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d003592,"Slovenský vodohospodársky podnik, štátny podnik",SVK,SK,969 55,Banská Štiavnica,Radničné námestie 8 +d003593,Klinikum Fürth,DEU,DE253,90766,Fürth,Jakob-Henle-Straße 1 +d003594,Comune di Pistoia — Stazione unica appaltante,ITA,ITI13,51100,Pistoia,piazza Duomo 1 +d003595,Département du Tarn,FRA,FRJ27,81013,Albi,Lices Georges-Pompidou +d003596,Ista Deutschland GmbH,DEU,DEA,45131,Essen,Luxemburger Str. 1 +d003597,AKQA srl,ITA,IT,,Roncade (TV), +d003598,Alcaldía del Ayuntamiento de Llanes,ESP,ES120,33500,Llanes,Nemesio Sobrino +d003599,"JEV Instruments Technologies, S. L.",ESP,ES300,28660,Boadilla del Monte (Madrid),"C/ Valle del Tormes, 2, L55" +d003600,Fastlegeportalen AS,NOR,NO082,,Sarpsborg, +d003601,MÜLLER Umwelttechnik GmbH & Co. KG,DEU,DE406,32816,Schieder-Schwalenberg,Julius-Müller-Str. 3 +d003602,Klüh Cleaning,DEU,DEA11,40211,Düsseldorf,Am Wehrhahn 70 +d003603,Adacel Inc.,CAN,,,Montreal,"895 De La Gauchetiere O., Suite 300, P.O. Box 48" +d003604,Medgal sp. z o.o.,POL,PL84,16-001,Księżyno,ul. Niewodnicka 26a +d003605,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003606,Amt der Burgenländischen Landesregierung,AUT,AT11,7000,Eisenstadt,Europaplatz 1 +d003607,MAN Truck- & Bus Deutschland GmbH,DEU,DE142,72138,Kirchtellinsfurt,Madenstr. 1 +d003608,Keski-Suomen ELY-keskus,FIN,FI,,Jyväskylä, +d003609,Bergkvarabuss Aktiebolag,SWE,SE122,391 28,Kalmar,Box 853 +d003610,Spitalul Clinic Colentina,ROU,RO321,020125,Bucureşti,Str. Ştefan cel Mare nr. 19-21 +d003611,Centrum Informatyki Resortu Finansów,POL,PL921,26-601,Radom,ul. Samorządowa 1 +d003612,"Mikro+Polo, družba za inženiring, proizvodnjo in trgovino, d.o.o.",SVN,SI,2000,Maribor,Zagrebška cesta 22 +d003613,Firma Schürzeberg Gerüstbau GmbH,DEU,DEA1E,41751,Viersen, +d003614,Land Berlin vertr. durch BA Mitte v. Berlin,DEU,DE3,10551,Berlin,Mathilde-Jacob-Platz 1 +d003615,Département de l'Ain,FRA,FRK21,01003,Bourg-en-Bresse Cedex,"45 avenue Alsace-Lorraine, BP 10114" +d003616,Suomen Terveystalo Oy,FIN,FI1B1,FI-00100,Helsinki,"Jaakonkatu 3, 3. krs" +d003617,Sciensano,BEL,BE100,1050,Bruxelles,Rue Juliette Wytsman 14 +d003618,"Enedis, Paris La Défense, Tour Enedis 34 place des Corolles 92079 Courbevoie",FRA,FR105,92079,Paris La Défense Cedex,Tour Enedis — 34 place des Corolles 92079 Courbevoie +d003619,Município de Braga,PRT,PT112,4700-435,Braga,Praça Municipal +d003620,OCEA Smart Building,FRA,FRF11,,Schiltigheim, +d003621,"Johnson & Johnson, prodaja medicinskih in farmacevtskih izdelkov, d.o.o.",SVN,SI,1000,Ljubljana,Šmartinska cesta 53 +d003622,janßen bär partnerschaft mbB Architekten und Ingenieure,DEU,DE946,,Bad Zwischenahn, +d003623,SNTFC „CFR Călători” S.A.,ROU,RO321,010873,Bucureşti,"Str. Dinicu Golescu nr. 38, sector 1" +d003624,Balme conseil,FRA,FR101,75004,Paris,33 boulevard Henri IV +d003625,"Landeshauptstadt München, Direktorium, Vergabestelle 1 Abt. 2",DEU,DE212,80636,München,Birkerstraße 18 +d003626,Carps International,FRA,FR,75007,Paryžius,168 rue de Grenelle +d003627,Občina Vojnik,SVN,SI,3212,Vojnik,Keršova ulica 8 +d003628,"Ústav chemických procesů AV ČR, v.v.i.",CZE,CZ010,165 02,Praha 6,Rozvojová 135 +d003629,"Velkoobchod ŠAS, s.r.o",CZE,CZ010,257 68,Kralovice,Severní 184 +d003630,Cancom GmbH,DEU,DE254,,Nürnberg, +d003631,Axians Cloud Builder,FRA,FR105,92213,Saint-Cloud,"1 rue Royale, 165 Bureaux de la Colline" +d003632,Carbini srl,ITA,ITI3,,Ancona, +d003633,JJW Arkitekter A/S,DNK,DK,2000,Frederiksberg,Finsensvej 78 +d003634,Octapharma AG,CHE,CH,8853,Lachen,Seidenstrasse 2 +d003635,Bestattungsdienst Felden,DEU,DE142,72072,Tübingen,Aixer Str. 12 +d003636,Konsorcjum firm:(Lider) Baxter Polska Sp. z o.o.,POL,PL,00-380,Warszawa,ul. Kruczkowskiego 8 +d003637,"Medis, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d003638,"Vantaan kaupunki / Maankäytön, rakentamisen ja ympäristön toimiala",FIN,FI1B1,FI-01300,Vantaa,Asematie 7 +d003639,Geb. Neumann GmbH & Co. KG,DEU,DE942,26723,Emden,Schwabenstraße 42 +d003640,"Kemofarmacija, veletrgovina za oskrbo zdravstva, d.d.",SVN,SI,1000,Ljubljana,Cesta na Brdo 100 +d003641,CHU de Toulouse,FRA,FRJ23,31059,Toulouse Cedex 9,hôtel-dieu Saint-Jacques 2 rue Viguerie — TSA 80035 +d003642,EWIBO GmbH,DEU,DEA34,46399,Bocholt,Adenauerallee 59 +d003643,Provincia autonoma di Trento — Agenzia provinciale per gli appalti e contratti — Servizio appalti – Ufficio gare servizi e forniture,ITA,ITH20,38122,Trento,via Dogana 8 +d003644,Landesbaudirektion Bayern,DEU,DE267,96106,Ebern,Marktplatz 30 +d003645,ANAS SpA,ITA,ITC11,00185,Roma,via Monzambano 10 +d003646,Grupa Azoty Zakłady Azotowe Kędzierzyn S.A.,POL,PL52,47-220,Kędzierzyn-Koźle,ul. Mostowa 30A +d003647,UAB „Labochema LT“,LTU,LT,LT-03151,Vilnius,Vilkpėdės g. 22 +d003648,"Salus, Veletrgovina, družba za promet s farmacevtskimi, medicinskimi in drugimi proizvodi, d.o.o.",SVN,SI,1000,Ljubljana,Litostrojska cesta 46A +d003649,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003650,Dansk Dekommissionering,DNK,DK02,4000,Roskilde,Frederiksborgvej 399 +d003651,Pohjois-Karjalan hankintatoimi,FIN,FI1D3,FI-80110,Joensuu,Linnunlahdentie 2 +d003652,Scoreman — RH Partners,FRA,FRL04,13100,Aix-en-Provence,"970 rue René-Descartes, horizon Sainte-Victoire, bât A" +d003653,CFDP Assurances,FRA,FRF11,67000,Strasbourg,1 rue de l'Autre +d003654,Logikview Analytics private Ltd,IND,,452010,Indore,"121, Shanti Niketan" +d003655,Garda de Coastă,ROU,RO223,900433,Constanța,Str. Zmeurei nr. 3 +d003656,Rheinberg-Buch e.K. Inh. Andreas Meier,DEU,DEA2B,51469,Bergisch-Gladbach, +d003657,PwC,DEU,DE712,60327,Frankfurt am Main,Friedrich-Ebert-Anlage 35-37 +d003658,Esbjerg Kommune,DNK,DK032,6700,Esbjerg,Torvegade 74 +d003659,Ilomantsin kunta,FIN,FI1D3,,Ilomantsi, +d003660,Rennbahn Hoppegarten GmbH & Co. KG,DEU,DE409,15336,Dahlwitz-Hoppegarten,Goetheallee 1 +d003661,DIMEX-2000 COMPANY S.R.L.,ROU,RO112,427240,Rebra,"Strada Principala, Nr. 315" +d003662,UAB „Dts solutions“,LTU,LT,,Vilnius, +d003663,Hlavní město Praha,CZE,CZ010,110 00,Praha,Mariánské náměstí 2 +d003664,"Mediline Mešana trgovska družba, d.o.o.",SVN,SI,1241,Kamnik,Perovo 30 +d003665,Lloyd’s Insurance Company S.A.,ITA,ITC4C,,Milano, +d003666,Braumann + Schmidt GmbH,DEU,DE300,12357,Berlin, +d003667,Lessard TP,FRA,FRH01,22510,Brehand,Le Pont de Pierre +d003668,SUTURA Képviseleti és Kereskedelmi Korlátolt Felelősségű Társaság,HUN,HU,1097,Budapest,Gubacsi út 47. +d003669,Lektus Sweden AB,SWE,SE312,781 22,Borlänge,Box 134 +d003670,Bundesanstalt für Gewässerkunde,DEU,DEB11,56068,Koblenz,Am Mainzer Tor 1 +d003671,Infraneo structure et réhabilitation,FRA,FR106,93170,Bagnolet,140 avenue Jean Lolive +d003672,I/S Vestforbrænding og datterselskaber,DNK,DK,2600,Glostrup,Ejby Mosevej 219 +d003673,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d003674,Stadt Neumarkt i. d. OPf.,DEU,DE236,92318,Neumarkt i. d. OPf.,Rathausplatz 1 +d003675,"SDV Karsten Schröder, Tangerhütte",DEU,DEE04,39517,Tangerhütte,Breitscheidstraße 50 +d003676,Geolys,FRA,FRE12,59426,Armentières,9 avenue de l'Europe +d003677,Comune di Ercolano,ITA,ITF33,80056,Comune di Ercolano (NA),corso Resina 39 +d003678,Sous les fraises,FRA,FR101,75020,Paris,17 rue de Retrait +d003679,UAB „B. Braun Avitum“,LTU,LT,,Vilnius, +d003680,Institut Català de la Salut — Hospital Universitari Vall d'Hebron,ESP,ES511,08035,Barcelona,"Passeig Vall d'Hebron, 119-129" +d003681,Kliniczny Szpital Wojewódzki nr 2 im. św. Jadwigi Królowej w Rzeszowie,POL,PL823,35-301,Rzeszów,ul. Lwowska 60 +d003682,Vzw AZ Sint-Lucas & Volkskliniek,BEL,BE234,9000,Gent,Groenebriel 1 +d003683,Comune di Comacchio,ITA,ITH56,44022,Comacchio,piazza Folegatti 15 +d003684,"UTE Telefónica de España, S. A. U. — Telefónica Móviles España, S. A. U.",ESP,ES30,28013,Madrid,"Gran Vía, 28" +d003685,Gmina Kołaczyce,POL,PL821,38-213,Kołaczyce,ul. Rynek 1 +d003686,Z+K Verwaltung GmbH,DEU,DE2,85630,GRASBRUNN,Am Hochacker 2 +d003687,"Vilt Ibérica, S. L. U.",ESP,ES300,,Madrid, +d003688,Botanica Sport,FRA,FR10,92000,Nanterre,5 rue des Courrières +d003689,Nvburo,FRA,FR102,77550,Moissy-Cramayel,601 avenue Blaise Pascal +d003690,Arpiem Aviation,ROU,RO322,075100,Otopeni,Calea Bucureștilor nr. 224E +d003691,Örebro kommun,SWE,SE124,701 35,Örebro,Box 30000 +d003692,ZÜBLIN Timber GmbH,DEU,DE275,86551,Aichach, +d003693,PEAKCON AB,SWE,SE313,,Gävle, +d003694,Rambøll Danmark A/S,DNK,DK,2300,København S,Hannemanns Allè 53 +d003695,Service départemental d'incendie et de secours,FRA,FRK27,73230,Saint-Alban-Leysse,226 rue de la Perrodière +d003696,Gemeente Den Haag,NLD,NL,2511 BT,Den Haag,Spui 70 +d003697,CA Saumur Val de Loire,FRA,FRG02,49408,Saumur Cedex,CS 54030 +d003698,NewPlacement Academy GmbH,CHE,CH0,8048,Zürich,Flurstrasse 50 +d003699,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d003700,SYSback GmbH,DEU,DE600,22083,Hamburg,Humboldtstraße 58 - 62 +d003701,DB Netz AG (Bukr 16),DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 11-13 +d003702,"Pinturas Isaval, S. L.",ESP,ES52,46190,Valencia,"C/ Velluyers, parcela 2-14, en Ribra" +d003703,Métropole de Lyon,FRA,FRK26,69505,Lyon,"20 rue du Lac, CS 33569" +d003704,Region Västmanland,SWE,SE125,721 89,Västerås,Regionhuset +d003705,eHealth.Business GmbH,DEU,DE300,12489,Berlin,Am Studio 2a +d003706,Gemeente Ridderkerk,NLD,NL,,Ridderkerk, +d003707,Mairie de Saint-Estève,FRA,FRJ15,66240,Saint-Estève,5 rue de la République +d003708,"FCC Equal CEE Comunidad Valenciana, S. L.",ESP,ES,28016,Valencia,"C/ Federico Salmón, 13" +d003709,"Gerencia de Emaya, Empresa Municipal d'Aigües i Clavegueram, S. A.",ESP,ES532,07010,Palma,"Camino de los Reyes 400, edificio Central de Son Pacs" +d003710,Consellería de Política Social,ESP,ES111,15781,Santiago de Compostela,"Edificio administrativo San Caetano, s/n" +d003711,BWI GmbH,DEU,DE30,12489,Berlin,Rudower Chaussee 13 +d003712,OMV Petrom Marketing,ROU,RO321,013329,București,"Str. Coralilor nr. 22, sector 1" +d003713,Kaefer GmbH,DEU,DE253,90768,Fürth, +d003714,F. & M. Lautenschläger GmbH & Co. KG,DEU,DEA23,50996,Köln,Zum Engelshof 1 +d003715,"Bormia, trgovina in storitve, d.o.o.",SVN,SI,5270,Ajdovščina,Mirce 14 +d003716,Poste italiane,ITA,IT,,Roma, +d003717,Rosenbauer Schweiz AG,CHE,CH0,8154,Oberglatt,Eichweg 4 +d003718,Stadtwerke Münster GmbH,DEU,DEA33,48155,Münster,Hafenplatz 1 +d003719,Pfizer Pharma PFE GmbH,DEU,DE30,10785,Berlin,Linkstr. 10 +d003720,"100MED, trgovina, zastopstvo, posredništvo, d.o.o.",SVN,SI,1230,Domžale,Sejmiška ulica 9 +d003721,Naturschutzgroßprojekt Thüringer Kuppenrhön gGmbH,DEU,DEG0B,,Kaltennordheim OT Kaltensundheim, +d003722,Västra Mälardalens Energi och Miljö AB,SWE,SE125,731 21,Köping,Box 34 +d003723,Zwaluwe Bouw,NLD,NL,4927 PC,Hooge Zwaluwe,Thijssenweg 12 +d003724,Moravskoslezský kraj,CZE,CZ080,702 18,Ostrava–Moravská Ostrava,28. října 117 +d003725,HKF Haustechnik GmbH,DEU,DE,23992,Krassow,Kastanienallee 56 +d003726,UAB „Limeta“,LTU,LT,,Vilnius, +d003727,OÜ Võlukaloss,EST,EE,74305,Anija vald,Tuleviku tn 5 +d003728,Département de la Vendée,FRA,FRG05,85923,La Roche-sur-Yon,40 rue du Maréchal Foch +d003729,Vrtec Ledina,SVN,SI,1000,Ljubljana,Čufarjeva ulica 14 +d003730,Autoklass Center,ROU,RO321,040042,București,"Str. Unirii nr. 166, sector 4" +d003731,Konsorcjum Szczotka: Przedsiębiorstwo Leśne Wojciech Szczotka (lider),POL,PL411,64-930,Szydłowo,Krępsko 69A +d003732,Stiftung Humboldt Forum im Berliner Schloss,DEU,DE300,10117,Berlin,Unter den Linden 3 +d003733,"AXA Seguros Generales, S. A. de Seguros y Reaseguros",ESP,ES,07014,Palma de Mallorca,"C/ Monseñor Palmer, 1" +d003734,Koninklijke Kentalis,NLD,NL,5270 BA,Sint-Michielsgestel,Postbus 7 +d003735,CHUBB France,FRA,FRF31,54320,Maxéville,6 rue Alfred Kastler +d003736,Mestna občina Ljubljana,SVN,SI,1000,Ljubljana,Mestni trg 1 +d003737,Comune Petruro Irpino,ITA,ITF34,,Petruro Irpino, +d003738,Valle Umbra Servizi SpA,ITA,ITI21,06049,Spoleto,via A. Busetti 38/40 +d003739,EurimPharm Arzneimittel GmbH,DEU,DE,,Saaldorf-Surheim, +d003740,Espoon kaupunki,FIN,FI1B1,FI-02070,Espoo,PL 640 +d003741,Lidköpings kommun,SWE,SE232,531 88,Lidköping,Skaragatan 8 +d003742,ADZO,FRA,FRK21,01700,Neyron,3 rue du Grand Lyon +d003743,"Angiomedic, trgovina in storitve, d.o.o.",SVN,SI,1000,Ljubljana,Zemljemerska ulica 12 +d003744,Spacing,FRA,FRE12,62840,Fleurbaix,5004F rue Louis Bouquet +d003745,Nord Tour S.R.L.,ROU,RO213,700124,Iași,Str. 14 Decembrie 1989 nr. 1 +d003746,Velamed GmbH,DEU,DEA23,50825,Köln,Helmholtzstr. 50 +d003747,Liperin seurakunta,FIN,FI1D3,,Liperi, +d003748,Castrén Engine Osakeyhtiö,FIN,FI1B1,,Helsinki, +d003749,Kreis Viersen — 38 Bevölkerungsschutz,DEU,DEA1E,41747,Viersen,Rathausmarkt 3 +d003750,Provincia autonoma di Trento — Agenzia provinciale per gli appalti e contratti — Servizio appalti — Ufficio gare,ITA,ITH20,38122,Trento,via Dogana 8 +d003751,Alcaldía del Ayuntamiento de Llíria,ESP,ES523,46160,Llíria,"Plaza Mayor, 1" +d003752,"Dopravní podnik hl. m. Prahy, akciová společnost",CZE,CZ010,190 00,Praha 9,Sokolovská 42/217 +d003753,Deutsche Post InHaus Services GmbH,DEU,DEA22,53121,Bonn, +d003754,Forstbetrieb Hipp,DEU,DE,87448,Waltenhofen, +d003755,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 - Haus 6 +d003756,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d003757,Stadt Kaufbeuren,DEU,DE272,87600,Kaufbeuren,Kaiser-Max-Straße 1 +d003758,"Dahme-Nuthe Wasser-, Abwasserbetriebsgesellschaft mbH",DEU,DE406,15711,Königs Wusterhausen,Köpenicker Str. 25 +d003759,Silvacultura S.R.L.,ROU,RO125,545500,Sovata,"Str. Minei nr. 4, Sovata, Mureș" +d003760,"Cores, informacijski sistemi, d.o.o., Kranj",SVN,SI,4000,Kranj,Ulica Mirka Vadnova 6 +d003761,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d003762,Landesbetrieb Bau und Immobilien Hessen Niederlassung Mitte Zentrale Vergabe,DEU,DE7,61231,Bad Nauheim,Dieselstraße 1-7 +d003763,Corlet Roto,FRA,FRG03,53300,Ambrières-les-Vallées, +d003764,DB Netz AG (Bukr 16),DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 11-13 +d003765,Dämmtech Swiss AG,CHE,CH0,5053,Staffelbach,Kirchleerauerstraße 1 +d003766,Tornion vuokra-asunnot Oy,FIN,FI,FI-95401,Tornio, +d003767,Engie,FRA,FRK26,69246,Lyon,127 avenue Barthélémy Buyer +d003768,Pisapia Assicuratori srl Unipolsai Assicurazioni,ITA,ITF31,,Caserta, +d003769,Uppsala kommun,SWE,SE,753 75,Uppsala,Uppsala kommun Kommunledningskontoret +d003770,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d003771,Commune de Montagny-en-Vexin,FRA,FRE22,60240,Montagny-en-Vexin,3 place de la Mairie +d003772,Cegelec Guyane,FRA,FRY30,97351,Matoury,carrefour du Larivot +d003773,Brandner Unterallgäu KG,DEU,DE27C,,Babenhausen, +d003774,Norrort Konditori Aktiebolag,SWE,SE,191 47,Sollentuna,Sollentunavägen 163-165 +d003775,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d003776,Goetze Bühnentechnik,DEU,DEA18,42859,Remscheid,Sonnenstr. +d003777,Helsingborgs stad,SWE,SE2,252 21,Helsingborg,Helsingborgs stad Drottninggatan 2 +d003778,Stölting GmbH Reinigung und Service,DEU,DEA32,45891,Gelsenkirchen,Willy-Brandt-Allee 314 +d003779,Krüger + Schröder GmbH,DEU,DEA45,32657,Lemgo,Am Bauhof 27 +d003780,Wind Tre SpA,ITA,ITC4C,,Rho (MI), +d003781,Municipiul Roman,ROU,RO214,611022,Roman,Piața Roman Vodă nr. 1 +d003782,S.C. Vega Chemicals S.R.L.,ROU,RO,031164,București,"Str. Anastase Panu nr. 6, sector 3, județ București, localitate București, cod poștal 031164" +d003783,Laireiter Forstbetrieb GmbH,AUT,AT32,5611,Grossarl,Ellmau 8 +d003784,"Varia, s.r.o. - inženýrská činnost a provádění staveb",CZE,CZ042,400 01,Ústí nad Labem,Rooseveltova 1804/2 +d003785,Asclepios S.A.,POL,PL514,50-502,Wrocław,ul. Hubska 44 +d003786,NIE Networks Ltd,GBR,UKN,BT9 5HT,Belfast,120 Malone Road +d003787,Producton S.R.L.,ROU,RO321,050527,București,"Str. Dr. Clunet nr. 9, sector 5" +d003788,Siemens SAS,FRA,FRF33,57084,Metz,6 rue Marie de Coëtlosquet +d003789,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d003790,SMACL assurances,FRA,FR,79031,Niort Cedex 9,141 avenue Salvador Allende +d003791,Provincia di Vicenza,ITA,ITH32,36100,Vicenza,contra' Gazzolle 1 +d003792,Greensoft S.R.L.,ROU,RO213,700349,Iași,Str. Han Tătar nr. 4 +d003793,Finanzministerium des Landes Schleswig-Holstein vertreten durch die Gebäudemanagement Schleswig-Holstein AöR,DEU,DEF02,24103,Kiel,Gartenstraße 6 +d003794,Steril România,ROU,RO321,041831,Bucureşti,"Str. Metalurgiei nr. 3-5, sector 4" +d003795,Tante Randi reklamebyrå AS,NOR,NO,,Oslo, +d003796,"NTT Data Business Solutions, a.s.",CZE,CZ064,603 00,Brno - Pisárky,Hlinky 505/118 +d003797,"Consejería de Educación, Universidad e Investigación",ESP,ES53,07009,Palma,"C/ del Ter, 16, edificio Alexandre Rosselló i Pastor, torre A, 3.ª planta, Secretaría General (polígono Son Fuster)" +d003798,Loire Océan développement,FRA,FRG01,44035,Nantes Cedex 1,34 rue du Pré Gauchet — CS 93521 +d003799,Klinikum Hochsauerland GmbH,DEU,DEA57,59755,Arnsberg,"Goethestraße 15, 59755 Arnsberg" +d003800,CCAS de Cherbourg-en-Cotentin,FRA,FRD12,50100,Cherbourg-en-Cotentin,"10 place Napoléon, Cherbourg-Octeville" +d003801,Knorr-Bremse Rail Systems Italia srl,ITA,ITI14,50013,Campi Bisenzio (FI),via San Quirico 199/I +d003802,"Instituto Navarro de Tecnologías e Infraestructuras Agroalimentarias, S. A.",ESP,ES22,31610,Villava,"Avenida Serapio Huici, 22" +d003803,Kemijski inštitut,SVN,SI,1000,Ljubljana,Hajdrihova ulica 19 +d003804,Si4iT Sp. z o.o.,POL,PL514,52-222,Wrocław,ul. Uczniowska 23A +d003805,Région Guadeloupe,FRA,FRY10,97100,Basse-Terre,avenue Paul Lacavé — Petit Paris +d003806,MAMMUT Deutschland GmbH & Co.KG,DEU,DE600,,Hamburg, +d003807,Telecom Italia SpA,ITA,ITC4C,,Milano (M), +d003808,Úřad pro zastupování státu ve věcech majetkových,CZE,CZ010,128 00,Praha,Rašínovo nábřeží 390/42 +d003809,Canon Medical Systems GmbH,DEU,DEA1D,41460,Neuss,Hellersbergstr. 4 +d003810,UAB „Salmeda“,LTU,LT,,Vilnius, +d003811,Stadtwerke Eberbach (hier vertreten durch die Stadtverwaltung Eberbach),DEU,DE715,69412,Eberbach,"Stadtbauamt, Leopoldsplatz 1" +d003812,Per Aarsleff A/S,DNK,DK012,2650,Hvidovre,Industriholmen 2 +d003813,"Thomy F.E., medicinska zastopstva, trgovina, marketing in posredovanje, d.o.o.",SVN,SI,1236,Trzin,Brodišče 24 +d003814,"Consejería de Agricultura, Desarrollo Rural, Población y Territorio",ESP,ES431,06800,Mérida,"Avenida Luis Ramallo, s/n" +d003815,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d003816,Provincie Limburg,NLD,NL,6229 GA,Maastricht,Limburglaan 10 +d003817,Renault Retail Group,FRA,FR105,92142,Clamart Cedex,"2 avenue Denis Papin, CS 10001" +d003818,Brunner & Co Baugesellschaft mbH und Co München,DEU,DE212,81245,München,Paul-Gerhardt-Allee 46 +d003819,ZDRAVSTVENI DOM DR. ADOLFA DROLCA MARIBOR,SVN,SI,2000,Maribor,Ulica talcev 9 +d003820,CSL Behring s.r.o.,CZE,CZ01,140 00,Praha 4,Vyskočilova 1461/2a +d003821,Corlet Imprimeur,FRA,FRD11,14110,Condé-sur-Noireau, +d003822,SN Perfect,FRA,FR106,77290,Mitry-Mory,11 rue Henri Becquerel +d003823,Aktsiaselts Teede Tehnokeskus,EST,EE,11216,Tallinn,Väike-Männiku tn 26 +d003824,Atalian Propreté PACA,FRA,FRL04,13100,Aix-en-Provence,190 rue Nicolas-Ledoux +d003825,Medilab Firma Wytwórczo-Usługowa Sp. z o.o.,POL,PL,15-531,Białystok,ul. Niedźwiedzia 60 +d003826,Univerzita Hradec Králové,CZE,CZ052,500 03,Hradec Králové,Rokitanského 62 +d003827,"Elinkeino-, liikenne- ja ympäristökeskus",FIN,FI194,FI-60101,Seinäjoki,Alvar Aallon katu 8 +d003828,Electroechipament,ROU,RO422,325300,Bocșa,Str. Bichistin nr. 37 +d003829,"Consejo de Administración de Transportes Interurbanos de Tenerife, S. A. U.",ESP,ES70,38111,Santa Cruz de Tenerife,"C/ Punta de Anaga, 1, PI Cuevas Blancas, Santa M.ª del Mar" +d003830,Stadt Straubing,DEU,DE223,94315,Straubing,Theresienplatz 2 +d003831,Gemeente Hellevoetsluis,NLD,NL,,Hellevoetsluis, +d003832,ESI France,FRA,FRF11,67610,La Wantzenau,1 rue George Cuvier +d003833,Åberg's i Sorsele AB,SWE,SE,924 31,Sorsele,Varggatan 1 +d003834,Municipiul Mangalia,ROU,RO223,905500,Mangalia,Șoseaua Constanței nr. 13 +d003835,Institut klinické a experimentální medicíny,CZE,CZ010,140 00,Praha,Vídeňská 1958/9 +d003836,Hera SpA,ITA,ITH55,40127,Bologna,viale Carlo Berti Pichat 2/4 +d003837,PORR Construct,ROU,RO321,020337,București,Bulevardul Dimitrie Pompeiu nr. 5-7 +d003838,Scottish Ambulance Service,GBR,UKM75,EH12 9EB,Edinburgh,"National Headquarters, Gyle Square, South Gyle Crescent" +d003839,Region Hovedstaden,DNK,DK01,3400,Hillerød,Kongens Vænge 2 +d003840,Caverion Norge AS,NOR,NO0A2,0666,Oslo,Ole Deviks vei 10 +d003841,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003842,Gemeente Albrandswaard,NLD,NL,,Poortugaal, +d003843,Pontetorto SpA,ITA,ITI15,,Motemurlo, +d003844,"M&M Intercom trgovina in storitve, d.o.o.",SVN,SI,1000,Ljubljana,Letališka cesta 33F +d003845,Volkswirtschaft Berner Oberland,CHE,CH0,3800,Interlaken,Kammistrasse 13 +d003846,Garden Arrosage,FRA,FR,45140,Ingre, +d003847,Joensuun kaupunki,FIN,FI1D3,,Joensuu, +d003848,Zaloker & Zaloker trgovinska in proizvodna d.o.o.,SVN,SI,1000,Ljubljana,Kajuhova ulica 9 +d003849,Ville de Courbevoie,FRA,FR105,92401,Courbevoie,"Hôtel de Ville, 1 rue Albert-Simonin, service commande publique" +d003850,Lieferung von Ersatzteilen Ticketautomat,AUT,AT,,Wien, +d003851,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d003852,Macofil,ROU,RO412,210001,Târgu Jiu,Str. Bârsești nr. 217 +d003853,S.C. Apă-Canal Ilfov S.A.,ROU,RO321,052431,Bucureşti,Str. Livezilor nr. 94 +d003854,(Uczestnik) Tramco Spółka z o.o. Wolskie,POL,PL,05-860,Płochocin,ul. Wolska 14 +d003855,Outokummun seurakunta,FIN,FI1D3,,Outokumpu, +d003856,Titeca,FRA,FRE11,59710,Ennevelin,ZA de la Broyé +d003857,Direcția Generală de Asistență Socială și Protecția Copilului Bacău,ROU,RO211,600302,Bacău,Str. Condorilor nr. 2 +d003858,BEFA Fahrzeug- und Stahlbau GmbH,DEU,DED42,09376,Oelsnitz,Zum Vereinsglückschacht 20 +d003859,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d003860,"Saytel — Servicios Informáticos, S. A.",ESP,ES511,,Barcelona, +d003861,GRDF,FRA,FR,75009,Paris,6 rue Condorcet +d003862,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003863,"Medis, farmacevtska družba, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 1 +d003864,Univerzitetni klinični center Maribor,SVN,SI032,2000,Maribor,Ljubljanska ulica 5 +d003865,Podravka,HRV,HR0,48000,Koprivnica,A. Starčevića 32 +d003866,Alldea informacijske tehnologije d.o.o.,SVN,SI,4208,Šenčur,Poslovna cona A 10 +d003867,Macon,ROU,RO423,,Cristur,Șoseaua Hunedoarei nr. 1-3 +d003868,Alytaus miesto savivaldybės administracija,LTU,LT,LT-62504,Alytus,Rotušės a. 4 +d003869,Rønnow Arkitekter A/S,DNK,DK011,,København K, +d003870,Ipomagi srl,ITA,ITI43,,Roma, +d003871,isfa plus,DEU,DE,24103,Kiel,Lange Reihe 10-12 +d003872,Imaye Graphic,FRA,FRG03,53000,Laval,BD Henri-Becquerel +d003873,Transports publics de la région lausannoise SA,CHE,CH0,1020,Renens,Chemin du Closel 15 +d003874,Circet,FRA,FRL05,83210,Solies-Pont,14 avenue de Lion +d003875,Raffin médical,FRA,FRK26,69490,Saint-Romain-de-Popey,746 route de Sarcey +d003876,Input Interiör Småland Aktiebolag,SWE,SE,554 54,Jönköping,Huskvarnavägen 64 +d003877,Spitalul Clinic Județean de Urgență Brașov,ROU,RO122,500326,Brașov,Calea București nr. 25-27 +d003878,München Klinik gGmbH,DEU,DE212,80337,München,Thalkirchner Straße 48 +d003879,Vrtec Pod gradom,SVN,SI,1000,Ljubljana,Praprotnikova ulica 2 +d003880,"Bormia, trgovina in storitve, d.o.o.",SVN,SI,5270,Ajdovščina,Mirce 14 +d003881,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d003882,Natural trgovina d.o.o.,HRV,HR0,10000,Zagreb,Kvintička 10 +d003883,Universitätsklinikum Münster,DEU,DEA33,48149,Münster,Albert-Schweitzer-Campus 1 +d003884,Scan Expert,ROU,RO213,700032,Iași,Str. Sfântul Sava nr. 18 +d003885,Υπουργείο Υγείας,CYP,CY,1448,Λευκωσία,Προδρόμου 1 και Χείλωνος 17 +d003886,Katinala Live Oy,FIN,FI1C2,,Katinala, +d003887,Carbagas AG,CHE,CH0,3073,Gümligen,Hofgut +d003888,Accelat AS,NOR,NO082,0975,Oslo,Stålfjæra 9 +d003889,Fast Lane GmbH,DEU,DE30,10117,Berlin,Oranienburger Str. 66 +d003890,"Stadt Leipzig, Amt für Gebäudemanagement",DEU,DED51,04092,Leipzig,Prager Straße 118-136 +d003891,0592509-6,FIN,FI1B1,,Helsinki, +d003892,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4 b +d003893,Amaris vzw,BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d003894,DANLIN XXL,ROU,RO214,617415,Secuieni,Strada Principala bloc 3 ap.3 +d003895,CA Grand Paris Sud,FRA,FR104,91054,Évry-Courcouronnes,500 place des Champs-Élysées +d003896,Vermögen und Bau Baden-Württemberg Amt Ravensburg,DEU,DE148,88214,Ravensburg,Minneggstraße 1 +d003897,Chabanne Energetique,FRA,FRK26,69001,Lyon,1 montée de la Butte +d003898,Die Bremer Stadtreinigung AöR,DEU,DE501,28217,Bremen,An der Reeperbahn 4 +d003899,Geologo Giuseppe De Cosmo,ITA,ITF34,,Fontanarosa,c/da Corpo di Cristo 1 +d003900,Pleno del Ayuntamiento de Mogán,ESP,ES70,35140,Mogán,"Avenida de la Constitución, 4" +d003901,F.T.I vzw,BEL,BE212,2800,Mechelen,Technologielaan +d003902,Mairie de Bailly-Romainvilliers,FRA,FR102,77700,Bailly-Romainvilliers,51 rue de Paris +d003903,Toll Collect GmbH,DEU,DE300,10785,Berlin,Linkstr. 4 +d003904,"Repsol Comercial de Productos Petrolíferos, S. A.",ESP,ES,,Madrid, +d003905,Soproni Erzsébet Oktató Kórház és Rehabilitációs Intézet,HUN,HU221,9400,Sopron,Győri út 15. +d003906,Hamburger Krematorium GmbH,DEU,DE600,22337,Hamburg,Fuhlsbüttler Straße 756 +d003907,Holzbau Eberhardinger + Bosch,DEU,DE279,89250 Senden,Lange Straße 3, +d003908,Forestry Club de France,FRA,FRK1,63130,Royat,16 Ter boulevard de la Taillerie +d003909,"Meditrina, družba za trženje medicinskih pripomočkov in opreme d.o.o.",SVN,SI,1000,Ljubljana,Dunajska cesta 199 +d003910,Heidenbluth GmbH,DEU,DE734,,Fuldabrück, +d003911,Sonnek Engineering S.R.L.,ROU,RO126,550188,Sibiu,Str. Faurului nr. 9 +d003912,Stadtwerke Augsburg Holding GmbH,DEU,DE271,86152,Augsburg,Hoher Weg 1 +d003913,Täby kommun,SWE,SE,183 80,Täby,Esplanaden 3 +d003914,Ranton srl,ITA,ITF13,,Pescara,via Trieste 88 +d003915,Siun sote – Pohjois-Karjalan sosiaali- ja terveyspalvelujen kuntayhtymä,FIN,FI1D3,,Joensuu, +d003916,gepe Gebäudedienste PETERHOFF GmbH,DEU,DEA26,52353,Düren, +d003917,Phinelec,FRA,FRL,13015,Marseille,21 rue André Allar +d003918,Freie Waldorfschule Weilheim gemeinnützige eG,DEU,DE21N,82386,Huglfing,Am Bahnhof 6 +d003919,Ministerstvo vnútra Slovenskej republiky,SVK,SK,812 72,Bratislava-Staré Mesto,Pribinova 2 +d003920,Rambøll Danmark A/S,DNK,DK,2300,København S,Hannemanns Allè 53 +d003921,"Landeshauptstadt Dresden, GB Finanzen, Personal und Recht, Zentrales Vergabebüro",DEU,DED21,01001,Dresden,Postfach 120020 +d003922,LabTeam Scandinavia,SWE,SE2,254 57,Helsingborg,Vasatorpsvägen 1 +d003923,"Landesbetrieb für Hochwasserschutz und Wasserwirtschaft Sachsen-Anhalt, Vergabestelle Nord",DEU,DEE03,39104,Magdeburg,Otto-von-Guericke-Str. 5 +d003924,Belimed GmbH,DEU,DE21G,84453,Mühldorf am Inn, +d003925,SiteVision AB,SWE,SE124,702 10,Örebro,Vasagatan 10 +d003926,Staatliches Bauamt Aschaffenburg,DEU,DE261,63739,Aschaffenburg,Cornelienstraße 1 +d003927,Lambert Clôtures,FRA,FR,56450,Theix, +d003928,Roche farmacevtska družba d.o.o.,SVN,SI,1000,Ljubljana,Stegne 13G +d003929,Brüggemann Dächer GmbH,DEU,DE927,31618,Liebenau, +d003930,T-Systems International GmbH,DEU,DE212,81673,München,Dingolfingerstr. 1-15 +d003931,RMC Light & Sound Oy,FIN,FI1B1,,Vantaa, +d003932,B.Braun Adria d.o.o.,HRV,HR050,10000,Zagreb,Hondlova 2/9 +d003933,MH Wassertechnologie GmbH,DEU,DED2E,01468,Boxdorf,Ringstraße 22 +d003934,Grossistcentralen i Stockholm AB,SWE,SE,152 42,Södertälje,Morabergsvägen 8 +d003935,Aktsiaselts Elveso,EST,EE,75301,Rae vald,Ehituse tn 9 +d003936,Regia Națională a Pădurilor – Romsilva RA,ROU,RO423,330091,Hunedoara,"Sucursala Direcția Silvică Hunedoara, str. Mihai Viteazu nr. 10" +d003937,Kemi-Tornionlaakson koulutuskuntayhtymä Lappia,FIN,FI1D7,FI-95340,Loue,Kätkävaarantie 69 +d003938,MHW GmbH,DEU,DEB1D,55469,Simmern,Von-Drais-Str. 16 +d003939,MVM Démász Áramhálózati Kft.,HUN,HU333,6724,Szeged,Kossuth Lajos sgt. 64–66. +d003940,Prior und Preußner GmbH und Co KG,DEU,DE944,49084,Osnabrück,Dammstr. 16-20 +d003941,Schwebel Xavier,FRA,FR101,75011,Paris,97 boulevard Voltaire +d003942,Meier & Ritter AG,CHE,CH0,8105,Regensdorf,Adlikerstraße 236 +d003943,Trafikverket,SWE,SE312,,Borlänge, +d003944,Dirección General de Recursos Económicos del Servicio Canario de la Salud,ESP,ES70,35004,Las Palmas de Gran Canaria,"Avenida Juan XXIII, 17, 3.ª planta" +d003945,Olimpic International Turism,ROU,RO321,040392,București,"Str. Vişana nr. 5, sector 4" +d003946,ENVItech Bohemia s.r.o.,CZE,CZ,,Praha,"Ovocna 34, 161 00 PRAHA 6" +d003947,Medical intertrade d.o.o.,HRV,HR065,10431,Sveta Nedelja,Dr.Franje Tuđmana 3 +d003948,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d003949,Vermögen und Bau Baden-Württemberg Amt Tübingen,DEU,DE142,72076,Tübingen,Schnarrenbergstraße 1 +d003950,Zoan Oy,FIN,FI,,Lahti, +d003951,Ministerstvo obrany,CZE,CZ,160 00,Praha,Tychonova 221/1 +d003952,CEZ Vânzare S.A.,ROU,RO411,200581,Craiova,"Calea Severinului nr. 97, et. 1" +d003953,Transport Infrastructure Ireland (TII),IRL,IE,Dublin,"Dublin, D08 DK10","Parkgate Business Centre, Parkgate Street" +d003954,Fritz Massong GmbH,DEU,DE133,79332,Teningen,Tullastraße 5a +d003955,Derichebourg SNG Mandataire,FRA,FRK26,69310,Pierre Benite,84 boulevard de l'Europe +d003956,Agence Olivia Payerne,FRA,FR101,75001,Paris,7 boulevard de la Madeleine +d003957,J. Jensen Nedrivning A/S,DNK,DK013,3540,Lynge,Højlundevej 8 +d003958,Heinrich Böll Stiftung e. V.,DEU,DE300,10117,Berlin,Schumannstraße 8 +d003959,Stadt Nürnberg – Hochbauamt,DEU,DE254,90402,Nürnberg,Marientorgraben 11 +d003960,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d003961,"Trink- und Abwasserverband Bad Bentheim, Schüttorf, Salzbergen und Emsbüren",DEU,DE94B,48465,Schüttorf,Quendorfer Straße 34 +d003962,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003963,Dipartimento Stazione unica appaltante,ITA,ITF5,85100,Potenza,via Vincenzo Verrastro 4 +d003964,"Chemass d.o.o., merilni sistemi",SVN,SI,1000,Ljubljana,Baznikova ulica 2 +d003965,Stadtverwaltung Kaiserslautern - Stabstelle IV.1 Zentrale Vergabestelle,DEU,DEB32,67657,Kaiserslautern,Lauterstraße 2 +d003966,DB Station&Service AG (Bukr 11),DEU,DE30,10557,Berlin,Europaplatz 1 +d003967,Turku Energia Sähkönmyynti,FIN,FI,FI-20100,Turku,Linnankatu 65 +d003968,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d003969,Fuchs Planungsgesellschaft mbH & Co. KG,DEU,DEA5A,57078,Siegen,An den Weiden 17 +d003970,Sweco Polska Sp. z o.o.,POL,PL415,60-829,Poznań,ul. Franklina Roosevelta 22 +d003971,Regierungspräsidium Karlsruhe,DEU,DE122,76131,Karlsruhe,Schlossplatz 1-3 +d003972,Stadt Neumarkt in der Oberpfalz,DEU,DE236,92318,Neumarkt in der Oberpfalz,Rathausplatz 1 +d003973,Metrostav DIZ s.r.o.,CZE,CZ010,180 00,Praha 8,Koželužská 2450/4 +d003974,OMV Petrom Marketing,ROU,RO321,013329,București,"Str. Coralilor nr. 22, sector 1" +d003975,DHI Sverige AB,SWE,SE232,412 50,Göteborg,"Drakegatan 6, 6 tr" +d003976,Byggmester Dovland AS,NOR,NO092,4632,Kristiansand S,Ægirs vei 1 D +d003977,Liberecký kraj,CZE,CZ051,461 80,Liberec,U Jezu 642/2a +d003978,UAB „Ignitis grupės paslaugų centras“,LTU,LT,LT-09311,Vilnius,A. Juozapavičiaus g. 13 +d003979,Université de Nantes,FRA,FRG01,44035,Nantes Cedex 1,"1 quai de Tourville, BP 13522" +d003980,Perfony SAS,FRA,FR101,75008,Paris,91 rue du Faubourg Saint-Honoré +d003981,Gemeinde Ahrensfelde,DEU,DE405,16356,Ahrensfelde,Lindenberger Straße 1 +d003982,Italiana assicurazioni SpA,ITA,ITC4C,,Milano, +d003983,Mladinska knjiga Trgovina d.o.o.,SVN,SI,1000,Ljubljana,Slovenska cesta 29 +d003984,"Zarząd Dróg, Zieleni i Transportu w Olsztynie",POL,PL622,10-015,Olsztyn,ul. Knosały 3/5 B +d003985,"Region Skåne, Koncerninköp",SWE,SE224,291 89,Kristianstad, +d003986,Centrum Usług Informatycznych we Wrocławiu,POL,PL518,50-304,Wrocław,ul. Namysłowska 8 +d003987,"Københavns Kommune, Teknik- og Miljøforvaltningen, Afdeling for Mobilitet, Klimatilpasning og Byvedligehold, Islands Brygge 37, 2300 Københavns S. Att.:",DNK,DK011,2300,København,Islandsbrygge 37 +d003988,Impact Mail and Print (UK) Ltd,GBR,UKG21,,Telford,Horton Court +d003989,"KRAMBO storitve, trgovina in svetovanje d.o.o.",SVN,SI,2230,Lenart v Slov. goricah,Kraigherjeva ulica 19A +d003990,Dell SAS,FRA,FRJ13,34938,Montpellier Cedex 9,1 rond-point Benjamin-Franklin +d003991,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d003992,Terraverde S.R.L.,ROU,RO316,100173,Ploiești,Str. Stadionului nr. 26 +d003993,Geomatika d.o.o.,HRV,HR,21240,Trilj,Ulica bana Jelačića 30 +d003994,arxes-tolina GmbH,DEU,DEC01,66115,Saarbrücken,Heinrich-Barth-Str. 1 +d003995,Maxman,ROU,RO115,440210,Satu Mare,"Strada -, Nr. -" +d003996,Commune de Rillieux-la-Pape,FRA,FRK26,69140,Rillieux-la-Pape,165 rue Ampère +d003997,I/S Amager Ressourcecenter,DNK,DK01,2300,København S,Vindmøllevej 6 +d003998,Intendente de Ferrol,ESP,ES111,15490,Ferrol (A Coruña),"C/ Irmandiños, s/n, Arsenal Militar" +d003999,Eesti Töötukassa,EST,EE,11412,Tallinn,Lasnamäe tn 2 +d004000,"Göteborgs Stad, Lokalförvaltningen",SWE,SE232,402 26,Göteborg,Box 5163 +d004001,Vihertaiturit Ky,FIN,FI1B,,Espoo, +d004002,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d004003,Diese Angabe wird aufgrund § 39 Abs. 6 Nr. 1 VgV geheim gehalten,DEU,DE,,XX, +d004004,LC Sols,FRA,FRD,,Ranchy, +d004005,Medys Internationale Zrt.,HUN,HU110,1097,Budapest,Albert Flórián utca 3/B. +d004006,Gotthilf Benz Turngerätefabrik GmbH + Co.KG,DEU,DE116,71364,Winnenden,Grüninger Str. 1-3 +d004007,Zespół Opieki Zdrowotnej,POL,PL622,13-100,Nidzica,ul. Mickiewicza 23 +d004008,"FCC Medio Ambiente, S. A.",ESP,ES,08040,Catalunya-Cataluña,"Polígono industrial Zona Franca, c/ D, 49-51" +d004009,"Čepro, a.s.",CZE,CZ01,170 00,"Holešovice, Praha 7",Dělnická 213/12 +d004010,Umo Sp. z o.o.,POL,PL,05-220,Zielonka,ul. Henryka Sienkiewicza 61 +d004011,Region Jönköpings Län,SWE,SE211,551 11,Jönköping,Box 1024 +d004012,Kompost-Bauschutt-Altstoff Aufbereitung und Verwertung T & T GmbH & Co. KG,DEU,DEF05,,Bargenstedt, +d004013,Bezirksamt Reinickendorf von Berlin,DEU,DE3,13407,Berlin,Teichstraße 65 (Haus 2) +d004014,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d004015,ÉRV. Északmagyarországi Regionális Vízművek Zártkörűen Működő Részvénytársaság,HUN,HU311,3700,Kazincbarcika,Tardonai út 1. +d004016,Groupement ACCM Ingénierie et Maintenance — Snadec Environnement,FRA,FRK14,63000,Clermont-Ferrand,32 rue du Pré la Reine +d004017,Bundesministerium für Verkehr und digitale Infrastruktur,DEU,DEA22,53175,Bonn,Robert-Schuman-Platz 1 +d004018,Demathieu Bard construction,FRA,FRF33,57070,Metz,19 rue de Picardie +d004019,Stübiger Haustechnik GmbH,DEU,DE24,95100,Selb,Weißenbacher Str. 6 +d004020,EURAILPOOL GmbH,DEU,DE21H,85737,Ismaning, +d004021,Best Achiziții,ROU,RO321,021393,București,"Bulevardul Ferdinand I nr. 58, sector 2" +d004022,Santa Casa da Misericórdia de Lisboa,PRT,PTZZZ,1250-264,Lisboa,"Rua das Taipas, 1" +d004023,Prometna šola Maribor,SVN,SI,2000,Maribor,Preradovičeva ulica 33 +d004024,Istituto zooprofilattico sperimentale della Lombardia e dell'Emilia Romagna «Bruno Ubertini»,ITA,ITC47,25124,Brescia,via Bianchi 9 +d004025,Ústredná vojenská nemocnica SNP Ružomberok - fakultná nemocnica,SVK,SK031,034 26,Ružomberok,Generála Miloša Vesela 21 +d004026,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d004027,AGMAR d.o.o.,HRV,HR050,10000,Zagreb,Čazmanska 8 +d004028,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d004029,APR — JCB Nettoyage,FRA,FRI12,33700,Mérignac,11 rue Bernard Palissy +d004030,Signature,FRA,FR105,92022,Nanterre Cedex,"103-105 rue des Trois Fontanot, CS 30096" +d004031,Ville de Forcalquier,FRA,FRL01,04300,Forcalquier,1 place du Bourguet +d004032,Pohjanmaan ELY-keskus,FIN,FI,,Vaasa, +d004033,Siemens Healthcare SAS,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d004034,"Indra Sistemas, S. A.",ESP,ES3,28108,Alcobendas,"Avenida de Bruselas, 35" +d004035,"Sveučilište u Rijeci, Fakultet za menadžment u turizmu i ugostiteljstvu",HRV,HR03,51410,Opatija,"Ika, Primorska 42" +d004036,L'Association intercommunale pour le démergement et l'épuration,BEL,BE332,4420,Saint-Nicolas,Rue de la Digue 25 +d004037,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d004038,"Nextis Services, s.r.o.",CZE,CZ080,720 00,Ostrava,Krmelínská 934 4 +d004039,Mestna občina Ljubljana,SVN,SI,1000,Ljubljana,Mestni trg 1 +d004040,Main-Kinzig-Kreis,DEU,DE719,63571,Gelnhausen,Barbarossa Straße 16-18 +d004041,Centrex,FRA,FR106,93160,Noisy-le-Grand,2 rue de la Butte Verte +d004042,GO! Scholengroep 19 'Dender',BEL,BE231,9300,Aalst,Welvaartstraat 70/4 +d004043,Energotech S.A.,ROU,RO321,061334,București,"Str. Timișoara nr. 104 B, sector 6" +d004044,"Správa železnic, státní organizace",CZE,CZ01,1100,Praha 1,Dlážděná 1003/7 +d004045,ITURRI Feuerwehr- und Umwelttechnik GmbH,DEU,DEA5A,57234,Wilnsdorf,Essener Str. 8 +d004046,"Nextis Services, s.r.o.",CZE,CZ080,720 00,Ostrava,Krmelínská 934 4 +d004047,Bundesamt für Wirtschaft und Ausfuhrkontrolle,DEU,DE71A,65760,Eschborn,Frankfurter Straße 29-35 +d004048,Savo-Karjalan Linja Oy,FIN,FI1D3,FI-80100,Joensuu,Pamilonkatu 28 +d004049,"Partner Mérnöki Iroda Tervező, Kivitelező Szolgáltató Korlátolt Felelősségű Társaság",HUN,HU,2800,Tatabánya,Bárdos lakópark 2/c. fsz. 3. +d004050,DOIMAN COM S.R.L.,ROU,RO411,200047,Craiova,"Strada Dacia, Nr. 149" +d004051,Département de la Seine-Saint-Denis,FRA,FR106,93000,Bobigny,"hôtel du département, 3 esplanade Jean Moulin" +d004052,"Republik Österreich – Bund – Vertreten durch den Bundesminister für Kunst, Kultur, öffentlichen Dienst und Sport",AUT,AT,1030,Wien,Radetzkystraße 2 +d004053,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d004054,Sale della terra,ITA,ITF32,,Benevento, +d004055,LAGOD trgovina in storitve d.o.o.,SVN,SI,1000,Ljubljana,Ob železnici 14 +d004056,pbr Planungsbüro Rohling,DEU,DE111,70182,Stuttgart, +d004057,Landesbetrieb Bau und Immobilien Hessen Niederlassung Mitte Zentrale Vergabe,DEU,DE7,61231,Bad Nauheim,Dieselstraße 1-7 +d004058,Egis Structures & Environnement SAS,FRA,FR,78286,Saint-Quentin-en-Welines,15 avenue du centre +d004059,Vrtec Hansa Christiana Andersena,SVN,SI,1000,Ljubljana,Rašiška ulica 7 +d004060,Profils Consultants SAS Profils,FRA,FRL04,13002,Marseille,10 place de la Joliette-les-Docks-Atrium 10.4 +d004061,Wilhelm Brugger,AUT,AT323,5300,Hallwang,Döbringstraße 22 +d004062,Ville de Bergerac,FRA,FRI11,24100,Bergerac,19 rue Neuve d'Argenson +d004063,Občina Prebold,SVN,SI,3312,Prebold,Hmeljarska cesta 3 +d004064,Allianz IARD,FRA,FR10,97185,Jarry Cedex,ZAC de Houelbourd Sud — BP 2458 +d004065,Distribuidora Farmacéutica de Gipuzkoa,ESP,ES212,,San Sebastián-Donostia, +d004066,Buchhandlung Schmitz,DEU,DEA13,45239,Essen, +d004067,"Alter, s.r.o.",CZE,CZ052,500 03,Hradec Králové,Vavákova 963 +d004068,CFVC-Ortemetec-EMSA — UTE,ESP,ES617,,Málaga, +d004069,Pragolab s.r.o,CZE,CZ010,190 00,Praha,Nad Krocínkou 285/55 +d004070,Vergabe und Beschaffungszentrum Dortmund,DEU,DEA52,44135,Dortmund,Viktoriastraße 15 +d004071,ICSEO,FRA,FRE22,60160,Montataire,100 rue Louis Blanc +d004072,Colt Technology Services GmbH,DEU,DE712,60322,Frankfurt/Main,Gerviniusstraße 18-22 +d004073,Tinmar Energy,ROU,RO321,014476,Bucureşti,Str. Floreasca nr. 246C +d004074,Občina Šentjur,SVN,SI,3230,Šentjur,Mestni trg 10 +d004075,Politie,NLD,NL,3068 AV,Rotterdam,Marten Meesweg 35 +d004076,Valtex & Co. trgovina in zastopstva d.o.o.,SVN,SI,1000,Ljubljana,Koprska ulica 62A +d004077,Gras Savoye Guadeloupe,FRA,FRY10,97122,Baie-Mahault,immeuble Connexion — boulevard Marquisat de Houelbourg — BP 2064 Jarry Cedex +d004078,Loxia Mälardalen AB,SWE,SE124,703 61,Örebro,Järntorgsgatan 3 +d004079,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d004080,"Futura Soft, s.r.o.",CZE,CZ064,602 00,Brno,Příkop 843/4 +d004081,"CROSS Zlin, a. s.",CZE,CZ072,76302,Zlin — Louky,Hasicska 397 +d004082,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d004083,Vema Lift Oy,FIN,FI1B,FI-20780,Kaarina,Voivalantie 30 +d004084,"Proinlec Norte, S. L.",ESP,ES120,33970,Laviana,"Carretera Tiraña, 14 (Barredos)" +d004085,Amia Invest,ROU,RO213,700452,Iași,Șoseaua Sărăriei nr. 46 +d004086,Coral Impex S.R.L.,ROU,RO316,100510,Ploiești,"Str. Peneș Curcanu nr. 8, bloc 151C, ap. 10" +d004087,"Esclapes e Hijos, S. L.",ESP,ES521,03007,Alicante,"Avenida Saturno, s/n" +d004088,Romold Security S.R.L.,ROU,RO216,730003,Vaslui,"Str. Războieni, nr. 18" +d004089,Azienda socio sanitaria territoriale (ASST) dei Sette Laghi,ITA,ITC41,21100,Varese,v.le Luigi Borri 57 +d004090,"Surovina, družba za predelavo odpadkov d.o.o.",SVN,SI,2000,Maribor,Ulica Vita Kraigherja 5 +d004091,Javno podjetje Energetika Ljubljana d.o.o.,SVN,SI,1000,Ljubljana,Verovškova ulica 62 +d004092,Igretec,BEL,BE32B,6000,Charleroi,Boulevard Mayence 1 +d004093,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d004094,CM-CIC Leasing Solution,FRA,FR,92988,Paris,"tour D2, 17 bis place des Reflets" +d004095,Väylävirasto,FIN,FI1B1,FI-00521,Helsinki,PL 33 (Opastinsilta 12 A) +d004096,Leonhard Weiss GmbH & Co. KG,DEU,DE212,81249,München, +d004097,Total Sec Oy,FIN,FI1C3,,Lahti, +d004098,UAB „Stelsa“,LTU,LT,LT-49412,Kaunas,P. Lukšio g. 53 +d004099,SAS APASE,FRA,FRE12,62220,Carvin,"69 rue Élie-Cartan, PA du Château" +d004100,VDL Bus & Coach Deutschland GmbH,DEU,DEA47,33142,Büren,Oberer Westring 1 +d004101,Ministerul Finanțelor Publice,ROU,RO321,050706,Bucureşti,Bulevardul Libertății nr. 16 +d004102,Landesbetrieb Bau und Immobilien Hessen Niederlassung Mitte Zentrale Vergabe,DEU,DE7,61231,Bad Nauheim,Dieselstraße 1-7 +d004103,Société Baxter,FRA,FRJ13,78280,Guyancourt,4 bis rue de la Redoute +d004104,DRAGOS INVEST,ROU,RO214,617423,Secuienii Noi,"Strada Principala, Nr. 67" +d004105,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d004106,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d004107,Commissariat à l'énergie atomique et aux énergies alternatives,FRA,FR,91191,Gif-sur-Yvette Cedex,"CEA Paris Saclay, bâtiment 482, PC nº 70" +d004108,"Serviço de Saúde da Região Autónoma da Madeira, E. P. E.",PRT,PT300,9004-514,Funchal,"Avenida Luís de Camões, 57" +d004109,Swietelsky Energie GmbH,AUT,AT,4050,Traun,Styriastraße 41 +d004110,Association verte vallée,FRA,FRY10,97119,Vieux-Habitants,route de Grande Rivière +d004111,"Landeshauptstadt Magdeburg, Der Oberbürgermeister",DEU,DEE03,39090,Magdeburg,(Sitz) Katzensprung 2 +d004112,"Atisoluciones seguridad, S. L.",ESP,ES,18210,Peligros (Granada),"C/ Córdoba, s/n, parcela 2-A, polígono de Asegra" +d004113,Mestna občina Ljubljana,SVN,SI,1000,Ljubljana,Mestni trg 1 +d004114,Unitatea Militară 01144,ROU,RO214,611047,Roman,Str. Profesor Dumitru Mărtinaş nr. 2 +d004115,Direcţia Servicii Publice Bistriţa,ROU,RO112,420008,Bistriţa,Str. Liviu Rebreanu nr. 2-4 +d004116,SPL Midi-Pyrénées Construction,FRA,FRJ23,31086,Toulouse Cedex,"Mandataire agissant au nom et pour le compte de la région Occitanie représentée par la présidente de la région Occitanie Pyrénées Méditerranée, Mme Carole Delga, 11 avenue Parmentier, Central Parc 2, 4e étage, BP 22414" +d004117,TTK GmbH,DEU,DE12,76131,Karlsruhe,Gerwigstraße 53 +d004118,Somogy Megyei Dr. Takács Imre Szociális Otthon,HUN,HU232,8660,Tab,Kossuth Lajos utca 107. 422 +d004119,Innherred Innkjøp,NOR,NO060,7670,Inderøy,Vennalivegen 7 +d004120,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d004121,Michael Schmidt GmbH Co.KG,DEU,DEA12,42228,Duisburg, +d004122,Česká televize,CZE,CZ010,140 70,Praha 4,"Kavčí hory, Na Hřebenech II 1132/4" +d004123,"Thüringer Landesamt für Bau und Verkehr, Referat 21",DEU,DEG01,99091,Erfurt,Europaplatz 3 +d004124,Brandner Unterallgäu KG,DEU,DE27C,,Babenhausen, +d004125,Città metropolitana di Torino,ITA,ITC11,10138,Torino, +d004126,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d004127,Euromaster Snc,FRA,FRK24,38330,Montbonnot-Saint-Martin,180 avenue de l'Europe +d004128,Osnovna šola Starše,SVN,SI,2205,Starše,Starše 5 +d004129,OMV Petrom S.A,ROU,RO321,013329,Bucureşti,Str. Coralilor nr. 22 +d004130,Babiel GmbH,DEU,DE,40233,Düsseldorf, +d004131,Santa Casa da Misericórdia de Lisboa,PRT,PT17,1200-470,Lisboa,Largo Trindade Coelho +d004132,Ružić graditeljstvo d.o.o.,HRV,HR0,51000,Rijeka,Sušačko-kastavskog odreda 21 +d004133,OMV Petrom S.A.,ROU,RO321,013329,Bucureşti,Str. Coralilor nr. 22 +d004134,Ville de Crépy-en-Valois,FRA,FRE22,60803,Crepy-en-Valois,hôtel de ville +d004135,Comité d'organisation des jeux olympiques Paris 2024,FRA,FR1,93210,Saint-Denis,"Parc Icade, Les Portes de Paris, 46 rue Proudhon" +d004136,Lindø port of Odense A/S,DNK,DK031,5000,Odense C,Noatunvej 2 +d004137,Communauté de communes Sud Roussillon,FRA,FRJ15,66751,Saint-Cyprien Cedex,"16 rue Jean & Jérôme Tharaud, CS 50034" +d004138,SILVA PAN,ROU,RO424,307382,Utvin,"Strada Principala, Nr. 312/C" +d004139,"MV Service Erd-, Wasser-, Landschaftsbau",DEU,DE80,17159,Dargun,Demminer Str. 38a +d004140,"Amt für Arbeitslosenversicherung AVA, Arbeitsvermittlung LAM Office de l'assurance-chômage, Service de l'emploi LMMT",CHE,CH0,3018,Berne,Lagerhausweg 10 +d004141,APVB,FRA,FRE23,80100,Abbeville,43 rue René-Dingeon +d004142,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d004143,Passus S.A,POL,PL911,,Warszawa, +d004144,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d004145,O. Žuravliovo įmonė „Avsista“,LTU,LT,LT-30270,Visaginas,"Pramonės g. 18, Karlų k., Visagino savivaldybė" +d004146,Spijtenburg Werving en Advies bv,NLD,NL,,Breda, +d004147,"Kostak, komunalno in gradbeno podjetje, d.d.",SVN,SI,8270,Krško,Leskovška cesta 2A +d004148,Kokkolan kaupunki,FIN,FI1D5,FI-67200,Kokkola,Kustaa Aadolfinkatu 76 +d004149,entra,FRA,FR106,93306,Aubervilliers,102 bis rue Danielle Casanova +d004150,"Elfetex, spol. s.r.o.",CZE,CZ032,312 16,Plzeň,Hřbitovní 31a +d004151,Gemeente Rotterdam,NLD,NL,3002 AN,Rotterdam,Wilhelminakade 179 +d004152,"Z+M Logistics, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Gorkého 621/26, Moravská Ostrava" +d004153,Société techniques de sondages et tests (test),FRA,FR1,78000,Versailles,7 rue Jean Mermoz +d004154,Transpordiamet,EST,EE,11413,Tallinn,Valge tn 4 +d004155,The Common Services Agency (more commonly known as NHS National Services Scotland) (‘NSS’),GBR,UKM,EH12 9EB,Edinburgh,"Gyle Square (NSS Head Office), 1 South Gyle Crescent" +d004156,Messer Slovenija podjetje za proizvodnjo in distribucijo tehničnih plinov d.o.o.,SVN,SI,2342,Ruše,Jugova ulica 20 +d004157,HMS Sanitärinstallation GmbH,DEU,DED4,09125,Chemnitz,Saydaer Straße 15 +d004158,Mairie de Chessy,FRA,FR102,77700,Chessy,32 rue Charles-de-Gaulle +d004159,Eesti Kaubandus-Tööstuskoda,EST,EE,10130,Tallinn,Toom-Kooli tn 17 +d004160,Oceans of Fire s. L.,ESP,ES,,Granada, +d004161,Emde APEV GmbH,DEU,DE261,,Aschaffenburg, +d004162,Lenka Schön Navrátilová,CZE,CZ080,252 17,Tachlovice,Sportovní 263 +d004163,Junta de Gobierno de la Diputación Provincial de Almería,ESP,ES611,04001,Almería,"C/ Navarro Rodrigo, 17" +d004164,Osaühing Semidor,EST,EE,51013,Tartu linn,Teguri tn 45c +d004165,Fuller GmbH,DEU,DE1,76131,Karlsruhe,Veilchenstraße 33 +d004166,MV Service Dargun,DEU,DE,17159,Dargun,Demminer Straße 38a +d004167,Liperin kunta,FIN,FI1D3,,Liperi, +d004168,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d004169,B. Braun SE,DEU,DE73,34212,Melsungen, +d004170,Vallois SAS,FRA,FRD11,14130,Saint-Hymer,agence de Caen — 16 avenue de la Grande Plaine +d004171,Zone de secours Luxembourg,BEL,BE341,6700,Arlon,"1, place Léopold — annexe du Palais" +d004172,"Centre de Jardineria Sils, S. A.",ESP,ES512,17410,Sils, +d004173,VĮ Lietuvos automobilių kelių direkcija,LTU,LT,LT-03109,Vilnius,J. Basanavičiaus g. 36 +d004174,GMC BUSINESS ACT,ROU,RO321,013167,Bucuresti,"Strada Pecetei, Nr. 4, Sector: 1" +d004175,Studentenwerk München — Anstalt des öffentlichen Rechts,DEU,DE212,80802,München,Leopoldstraße 15 +d004176,Gerencia de Asistencia Sanitaria de Palencia,ESP,ES414,34005,Palencia,"Avenida Donantes de Sangre, s/n" +d004177,Eduix Oy,FIN,FI197,FI-33210,Tampere,Finlaysoninkuja 21 A +d004178,Herbert Smith Freehills LLP,GBR,UKI,000000,Londres,"Exchange House, Primrose Street, Ec2a 2eg" +d004179,Občina Štore,SVN,SI,3220,Štore,Cesta XIV. divizije 15 +d004180,Občina Rogaška Slatina,SVN,SI,3250,Rogaška Slatina,Izletniška ulica 2 +d004181,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d004182,Landratsamt Esslingen SG 112 Beschaffungsstelle,DEU,DE113,73728,Esslingen,Pulverwiesen 11 +d004183,Salzburger Verkehrsverbund GmbH,AUT,AT,5020,Salzburg,Schallmooser Hauptstraße 10 +d004184,Siemens Healthcare Korlátolt Felelősségű Társaság,HUN,HU110,1143,Budapest,Gizella út 51–57. +d004185,Bayerische Staatsforsten AöR,DEU,DE232,93053,Regensburg,Tillystraße 2 +d004186,Xylem Water solutions Magyarország Kft,HUN,HU120,2045,Törökbálint,Tópark utca 9. +d004187,Občina Polzela,SVN,SI,3313,Polzela,Malteška cesta 28 +d004188,ratiopharm GmbH,DEU,DE,,Ulm, +d004189,BWI GmbH,DEU,DE30,12489,Berlin,Rudower Chaussee 13 +d004190,Mairie de Magny-le-Hongre,FRA,FR102,77700,Magny-le-Hongre,21 rue du Moulin-à-Vent +d004191,Oktal Pharma d.o.o.,HRV,HR050,10020,Zagreb,Utinjska 40 +d004192,Bundeswehr-Dienstleistungszentrum Idar-Oberstein,DEU,DEB15,55743,Idar-Oberstein,Am Rilchenberg 61 +d004193,Flughafen München GmbH,DEU,DE21A,85326,München,Postfach 23 17 55 +d004194,Telecom Italia SpA,ITA,ITC4C,,Milano (MI), +d004195,Pharmafarm,ROU,RO125,060044,Corunca,Str. Principală nr. 1B/1 +d004196,"Berliner Verkehrsbetriebe, Bereich Einkauf/ Materialwirtschaft (VEM)",DEU,DE300,10179,Berlin,Holzmarktstraße 15-17 +d004197,Gemeente Peel en Maas,NLD,NL,5981 CC,Panningen,Wilhelminaplein 1 +d004198,Cloitre Imprimeurs,FRA,FRH02,29800,Saint-Thonan, +d004199,"Luka Koper, pristaniški in logistični sistem, delniška družba",SVN,SI,6000,Koper - Capodistria,Vojkovo nabrežje 38 +d004200,Ecoservices SA,CHE,CH0,1227,Carouge,Rue de Veyrier 9 bis +d004201,GR Dienst Dommelvallei,NLD,NL,5731 JL,Mierlo,Dorpsstraat 210 +d004202,UAB „Principalmed 1L“,LTU,LT,,Kaunas, +d004203,E-Builder Építőipari és Mérnöki Tanácsadó Korlátolt Felelősségű Társaság,HUN,HU11,1094,Budapest,Páva Utca 32./B. 2.em.12. +d004204,Servicio de Salud de las Illes Balears,ESP,ES53,07003,Palma,C/ Reina Esclaramunda +d004205,Veszprémi Intézményi Szolgáltató Szervezet,HUN,HU213,8200,Veszprém,Haszkovó utca 39. +d004206,Organismo Autónomo Agencia para el Empleo de Madrid,ESP,ES300,28005,Madrid,"Paseo de Pontones, 10" +d004207,OHL ŽS a.s.,CZE,CZ064,602 00,Brno–Veveří,Burešova 938/17 +d004208,Lietuvos ir Šveicarijos UAB „Hospitex Diagnostics Kaunas“,LTU,LT,,Kaunas, +d004209,Berliner Wasserbetriebe,DEU,DE300,10179,Berlin,Neue Jüdenstr. 2 +d004210,"Universitäts- und Hansestadt Greifswald, Der Oberbürgermeister, Stadtbauamt, Abt. Bauverwaltung",DEU,DE80N,17489,Greifswald,Markt 15 +d004211,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d004212,Mugo,FRA,FR103,78530,Buc,356 rue Fourny +d004213,"Italcomma Slovakia, s.r.o.",SVK,SK,010 01,Žilina,Dolné Rudiny 1 +d004214,Bialmed Sp. z o.o.,POL,PL911,02-546,Warszawa,ul. Kazimierzowska 46/48 lok. 35 +d004215,Spitalul Clinic Județean de Urgență „Sfântul Apostol Andrei”,ROU,RO224,800578,Galați,Str. Brăilei nr. 177 +d004216,"Asseco Central Europe, a.s.",CZE,CZ010,140 00,Praha 4,Budějovická 778/3a +d004217,Trogir Holding d.o.o.,HRV,HR035,21220,Trogir,Put Mulina 2 +d004218,Wilhelm Barth GmbH & Co.KG,DEU,DE116,70736,Fellbach,Steinbeisstr. 14 +d004219,Alcaldía del Ayuntamiento de Suances,ESP,ES130,39340,Suances,"Plaza de Viares, 1" +d004220,S.C. Stofe Buhuși S.A.,ROU,RO211,605100,Buhuși,Str. Libertății nr. 36 +d004221,Vrtec Pod gradom,SVN,SI,1000,Ljubljana,Praprotnikova ulica 2 +d004222,Université Savoie Mont-Blanc,FRA,FRK27,73011,Chambéry Cedex,"27 rue Marcoz, BP 1104" +d004223,Stadibau GmbH — Gesellschaft für den Staatsbediensteten Wohnungsbau in Bayern mbH,DEU,DE212,80804,München,Mottlstr. 1 +d004224,Baltrade Oy,FIN,FI,FI-01120,Västerskog,Sipoonranta 10 B LT 1 +d004225,Valstybinio socialinio draudimo fondo valdyba prie Socialinės apsaugos ir darbo ministerijos,LTU,LT,LT-09308,Vilnius,Konstitucijos pr. 12 +d004226,Universitatea din București,ROU,RO321,050107,Bucureşti,Str. Mihail Kogălniceanu nr. 0213077347 +d004227,"Strojnik, družba za inženiring, storitve, servis in trgovino, d.o.o.",SVN,SI,2000,Maribor,Tržaška cesta 21 +d004228,Guivarch l'Imprimerie,FRA,FRH01,22190,Plérin, +d004229,Nye Veier,NOR,NO,4608,Kristiansand,Tangen 76 +d004230,Holzaufarbeitung Sporrer,DEU,DE,,Neualbenreuth, +d004231,RG Industrie SÀRL,CHE,CH0,1214,Vernier,Chemin des Batailles 24 +d004232,UAB „Kerista“,LTU,LT,,Vilnius, +d004233,Ministerul Apărării Naționale – Unitatea Militară 01020,ROU,RO113,405200,Dej,"Str. Tudor Vladimirescu nr. 1, mun. Dej, județ Cluj" +d004234,LumiraDx AB,SWE,SE110,169 61,Solna,Västra Storgatan 5A +d004235,Universitatea „Alexandru Ioan Cuza” Iași,ROU,RO213,700506,Iași,Str. Carol I nr. 11 +d004236,Aplinkos apsaugos agentūra,LTU,LT,LT-09311,Vilnius,A. Juozapavičiaus g. 9 +d004237,Stadtverwaltung Nordhausen — Rechtsamt und Beteiligungen / Vergabestelle,DEU,DEG07,99734,Nordhausen,Markt 1 +d004238,Uždaroji akcinė bendrovė „Vilniaus vandenys“,LTU,LT,LT-05132,Vilnius,Spaudos g. 8 +d004239,Silvacultura S.R.L.,ROU,RO125,545500,Sovata,"Str. Minei nr. 4, Sovata, Mureș" +d004240,Międzygminne Przedsiębiorstwo Gospodarki Odpadami sp. z o.o.,POL,PL426,78-320,Połczyn Zdrój,Wardyń Górny 35 +d004241,"Laboratorij - um, trgovina z laboratorijsko tehniko, opremo in kemikalijami, d.o.o.",SVN,SI,1351,Brezovica pri Ljubljani,Pod Goricami 69 +d004242,Railport Antwerpen nv,BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d004243,Bio-optica Milano SpA,ITA,ITC4,,Milano, +d004244,Invacare AB,SWE,SE110,163 91,Spånga,Box 66 +d004245,O2 Czech Republic a.s.,CZE,CZ,140 22,Praha 4–Michle,Za Brumlovkou 266/2 +d004246,Peyrou Joel,FRA,FRI12,33130,Begles,56 rue Pauly +d004247,TREBOR DRUM CONSTRUCT SRL,ROU,RO111,410265,Oradea,"Strada Erofte Grigore, Nr. 1B" +d004248,"Göteborgs Stad, Lokalförvaltningen",SWE,SE232,402 26,Göteborg,Box 5163 +d004249,Agenzia delle entrate — Riscossione,ITA,IT,00142,Roma,via Giuseppe Grezar 14 +d004250,S.C. Artromed Class S.R.L.,ROU,RO321,123,București,"Splaiul Independenței nr. 273, sector: -, județ București, localitate: București, cod poștal: 123" +d004251,CHU de Montpellier,FRA,FRJ13,34295,Montpellier Cedex 5,191 avenue du Doyen-Gaston-Giraud +d004252,Senaatti-kiinteistöt,FIN,FI1B,FI-00530,Helsinki,Lintulahdenkatu 5 A +d004253,Österreichische Postbus Aktiengesellschaft,AUT,AT130,1100,Wien,Am Hauptbahnhof 2 +d004254,Sopra Steria SE,DEU,DE60,22085,Hamburg,Hans-Henny-Jahnn-Weg 29 +d004255,Ministerul Afacerilor Interne – Direcția Generală Anticorupție,ROU,RO321,041337,Bucureşti,Șoseaua Olteniţei nr. 390A +d004256,Jasika d.o.o.,HRV,HR050,10250,Zagreb-Lučko,Dolenica 55 +d004257,Ing. Pompilio Mobilia,ITA,ITF34,83037,Montecalvo Irpino,via Dietro Corte 31 +d004258,"Instituto de Vivienda, Infraestructura y Equipamiento de la Defensa (Invied)",ESP,ES300,28015,Madrid,"C/ Isaac Peral, 20" +d004259,Aannemingsbedrijf Vermeulen Benthuizen bv,NLD,NL,,Hazerswoude-Dorp, +d004260,Szpital Powiatowy w Zawierciu,POL,PL22B,42-400,Zawiercie,"ul. Miodowa 14, Zawiercie" +d004261,Kamstrup A/S Mannheim,DEU,DE126,68165,Mannheim,Werderstraße 23-25 +d004262,Javno podjetje Vodovod Kanalizacija Snaga d.o.o.,SVN,SI,1000,Ljubljana,Vodovodna cesta 90 +d004263,Juuan seurakunta,FIN,FI1D3,,Juuka, +d004264,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d004265,Gemeinde Rastede,DEU,DE946,26180,Rastede,Sophienstraße 27 +d004266,Moi rør as,NOR,NO092,4632,Kristiansand,Ægirsvei 10 +d004267,Bright Finland Oy,FIN,FI1B1,,Vantaa, +d004268,Cancom GmbH,DEU,DEA1C,,Langenfeld, +d004269,Serviciul de Telecomunicații Speciale,ROU,RO321,060044,Bucureşti,Splaiul Independenței nr. 323A +d004270,RTC Proffice Experience,ROU,RO321,050881,București,Str. Tudor Vladimirescu nr. 29 +d004271,Taksi ja Tilausajot O. Vänskä,FIN,FI1D3,FI-82290,Nieminen,Hammaslahdentie 1516b +d004272,Bau- und Liegenschaftsbetrieb NRW Bielefeld,DEU,DEA41,33602,Bielefeld,August- Bebel-Straße 91 +d004273,Biosigma SpA,ITA,ITH35,30010,Cantarana di Cona,via Valletta 5 +d004274,Direct Cleaning Services (SW) Ltd,GBR,UKK15,SN15 3HR,Chippenham,41-43 Market Place +d004275,Groupe Pierre le Goff,FRA,FRG01,44480,Saint-Aignan-de-Grand-Lieu, +d004276,Gotthilf Benz Turngerätefabrik GmbH + Co.KG,DEU,DE116,71364,Winnenden,Grüninger Str. 1-3 +d004277,Habitat du Gard — Office public de l'Habitat,FRA,FRJ12,30911,Nîmes,92 bis avenue Jean Jaurès +d004278,Malmö Universitet,SWE,SE224,205 06,Malmö,Neptuniplan 7 +d004279,Pohjolan Turistiauto Oy,FIN,FI1D,,Iisalmi, +d004280,Junta de Gobierno del Ayuntamiento de Oviedo,ESP,ES120,33071,Oviedo,"Plaza de la Constitución, s/n" +d004281,Bröderna Berner AB,SWE,SE224,202 11,Malmö,Box 50132 +d004282,"Presidencia de la Agencia Estatal Consejo Superior de Investigaciones Científicas, M. P.",ESP,ES300,28006,Madrid,"C/ Serrano, 117" +d004283,Karl Streb GmbH,DEU,DE236,92334,Berching, +d004284,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschiz,"Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" +d004285,Eurofins Labtium Oy,FIN,FI1B,,Espoo, +d004286,"Gemeinde Untergruppenbach, vertreten durch die Gt-service GmbH",DEU,DE118,74199,Untergruppenbach,Kirchstraße 2 +d004287,Česká republika - Státní zemědělská a potravinářská inspekce,CZE,CZ064,603 00,Brno,Květná 504/15 +d004288,Beckman Coulter GmbH,DEU,DEA14,47807,Krefeld,Europark Fichtenhain B 13 +d004289,AC environnement,FRA,FRC14,,Quetigny,21800 +d004290,Storstockholms brandförsvar,SWE,SE110,111 83,Stockholm,Box 1328 +d004291,Karl Storz Endoscopie,FRA,FR,78280,Guyancourt,12 rue Georges Guynemer +d004292,Uppsala Vatten och Avfall AB,SWE,SE121,754 50,Uppsala,Uppsala Vatten och Avfall AB Rapsgatan 7 +d004293,FastWeb SpA,ITA,ITC4C,,Milano (MI), +d004294,bed,FRA,FR,,Semoy, +d004295,Stadtverwaltung Kaiserslautern,DEU,DEB32,67657,Kaiserslautern,Willy-Brandt-Platz 1 +d004296,AMD Global Construct S.R.L.,ROU,RO322,,Voluntari,Str. Crinului nr. 14-16 +d004297,Bundesimmobiliengesellschaft m. b. H. Unternehmensbereich Spezialimmobilien,AUT,AT323,5020,Salzburg,Aigner Straße 8 +d004298,Weatherford Atlas GIP S.A.,ROU,RO,100189,Ploiești,Str. Clopoței nr. 2A +d004299,Byggmester Per Otto Ingebretsen,NOR,NO092,4706,Vennesla,Drivenesvegen 26 +d004300,"PITUS storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d004301,"Cardio Medical družba za trgovino in storitve, d.o.o.",SVN,SI,1236,Trzin,Špruha 1 +d004302,Generali Italia SpA,ITA,ITH34,,Mogliano Veneto, +d004303,TREBOR DRUM CONSTRUCT SRL,ROU,RO111,410265,Oradea,"Strada Erofte Grigore, Nr. 1B" +d004304,Gemeente Waddinxveen,NLD,NL,,Waddinxveen, +d004305,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d004306,Göteborg Energi Aktiebolag,SWE,SE232,401 20,Göteborg,Box 53 +d004307,Mondial Protection,FRA,FRD11,14123,Cormelles-le-Royal,"boulevard de l'Espérance, 12 espace Jean Mantelet" +d004308,Deutsches Institut für Ernährungsforschung,DEU,DE40E,14558,Nuthetal,Arthur-Scheunert-Allee 114-116 +d004309,„Sachsen-Anhalt AZV“ Eisleben-Süßer See“,DEU,DEE0A,06295,Lutherstadt Eisleben,Landwehr 9 (Kläranlage) +d004310,Konsorcjum firm:(Lider) Baxter Polska Sp. z o.o.,POL,PL,00-380,Warszawa,ul. Kruczkowskiego 8 +d004311,Politechnika Poznańska,POL,PL,60-965,Poznań,pl. M. Skłodowskiej-Curie 5 +d004312,Coral Impex S.R.L.,ROU,RO316,100510,Ploiești,"Str. Peneș Curcanu nr. 8, bloc 151C, ap. 10" +d004313,O2 Czech Republic a.s.,CZE,CZ,140 22,Praha 4–Michle,Za Brumlovkou 266/2 +d004314,"Orlen Unipetrol RPA, s.r.o.",CZE,CZ0,436 01,Litvínov,1 +d004315,Peter Lukáč,SVK,SK,905 01,Senica,S. Jurkoviča 1205/34 +d004316,Hyrican Informationssysteme AG,DEU,DEG0D,99638,Kindelbrück,Kalkplatz 5 +d004317,Sonnek Engineering S.R.L.,ROU,RO126,550188,Sibiu,Str. Faurului nr. 9 +d004318,Albert Ziegler GmbH,DEU,DE123,89531,Giengen a. d. Brenz, +d004319,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d004320,L2V Ascenseurs,FRA,FR102,94380,Bonneuil-sur-Marne,"4 avenue des Marronniers, bâtiment 13" +d004321,Besiktningsförrättare Sverige AB,SWE,SE122,613 36,Oxelösund,"c/o Stefan Sköld, Vallsundsvägen 90" +d004322,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d004323,Junta de Gobierno del Ayuntamiento Villa de Agüimes,ESP,ES70,35260,Villa de Agüimes,"C/ Doctor Joaquín Artiles, 1" +d004324,"Otto-von-Guericke-Universität Magdeburg, Dezernat Technik und Bauplanung",DEU,DEE03,39106,Magdeburg,Universitätsplatz 2 +d004325,UAB „Irgita“,LTU,LT,,Kaunas,"Baltų pr. 139-21, LT-48201" +d004326,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d004327,OMV Petrom Marketing,ROU,RO321,013329,București,"Str. Coralilor nr. 22, sector 1" +d004328,SPRL Godart,BEL,BE3,,Ittre, +d004329,Norconsult AB,SWE,SE232,402 76,Göteborg,Box 8774 +d004330,APR — JCB Nettoyage,FRA,FRI12,33700,Mérignac,11 rue Bernard Palissy +d004331,Općina Pirovac,HRV,HR,22213,Pirovac,Zagrebačka 23 +d004332,Kommunale Immobilien Jena,DEU,DEG03,07743,Jena,Paradiesstraße 6 +d004333,ISPE,ITA,ITF45,73100,Lecce,via San Lazzaro 15 +d004334,Carps International,FRA,FR,75007,Paryžius,168 rue de Grenelle +d004335,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d004336,Liberecký kraj,CZE,CZ051,461 80,Liberec,U Jezu 642/2a +d004337,Amt für Bau und Immobilien,DEU,DE712,60329,Frankfurt am Main,Gutleutstr. 7-11 +d004338,Mairie de Montesson,FRA,FR103,78360,Montesson,1 place Roland-Gauthier +d004339,Holz Klade GmbH,AUT,AT,9400,Wolfsberg,Auenfischerstraße 61 +d004340,"Delegación Territorial de Empleo, Formación, Trabajo Autónomo, Transformación Económica, Industria, Conocimiento y Universidades en Granada",ESP,ES614,18013,Granada,"Avenida Joaquina Eguaras, 2, Edificio Administrativo Almanjáyar" +d004341,"Dahme-Nuthe Wasser-, Abwasserbetriebsgesellschaft mbH",DEU,DE406,15711,Königs Wusterhausen,Köpenicker Str. 25 +d004342,Ministarstvo turizma i sporta,HRV,HR0,10000,Zagreb,Prisavlje 14 +d004343,Pfizer Pharma GmbH,DEU,DE,,Berlin, +d004344,Rengøringsservice Danmark A/S,DNK,DK02,2600,Glostrup,Produktionsvej 8-10 +d004345,Johanneberg Science Park AB,SWE,SE232,,Göteborg, +d004346,Agence de services et de paiement,FRA,FR,87040,Limoges,2 rue du Maupas +d004347,Taxicentrale Zwolle bv,NLD,NL,8042 PH,Zwolle,Hoekerweg 14 +d004348,Urtica Sp. z o.o.,POL,PL51,54-613,Wrocław,ul. Krzemieniecka 120 +d004349,"Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle",DEU,DED41,09111,Chemnitz,Friedensplatz 1 +d004350,Opetus- ja kulttuuriministeriö,FIN,FI,FI-00100,Valtioneuvosto,PL 29 +d004351,NxtPort bv,BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d004352,10:8 Architekten GmbH,CHE,CH0,8037,Zürich,Scheffelstraße 3 +d004353,Vilogia SA HLM,FRA,FRE11,59650,Villeneuve-d'Ascq,197 rue du 8 Mai 1945 +d004354,Castrén Engine Osakeyhtiö,FIN,FI1B1,,Helsinki, +d004355,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d004356,INNEO Solutions GmbH,DEU,DE11D,,Ellwangen, +d004357,Javno podjetje Energetika Ljubljana d.o.o.,SVN,SI,1000,Ljubljana,Verovškova ulica 62 +d004358,Hera SpA,ITA,ITH55,40127,Bologna,viale Carlo Berti Pichat 2/4 +d004359,Glas Oswald GmbH & Co. KG,DEU,DE217,85764,Oberschleißheim,Mittenheimer Straße 74 +d004360,CHUBB France,FRA,FRF31,54320,Maxéville,6 rue Alfred Kastler +d004361,Deluxe Cards,ROU,RO321,030615,București,"Str. Călăraşi nr. 167, sector 3" +d004362,"Skytech — Comércio de Aparelhos e Equipamentos de Telecomunicações e Serviços, Lda.",BRA,,20090-030,Santo António de Pádua,"Rua dos Leites, 1" +d004363,Åkericentralen i Alingsås AB,SWE,SE232,441 38,Alingsås,Sävelundsgatan 10 B +d004364,CBF Balducci SpA,ITA,ITI33,,Montecassiano, +d004365,REMONDIS Olpe GmbH,DEU,DEA59,57462,Olpe,Raiffeisenstraße 39 +d004366,Põltsamaa Vallavalitsus,EST,EE,48104,Põltsamaa vald,Lossi tn 9 +d004367,Axicorp Pharma B.V.,NLD,NL,2585 EC,Den Haag,Nassauplein 30 +d004368,Csongrád Megyei Dr. Bugyi István Kórház,HUN,HU333,6600,Szentes,Sima Ferenc utca 44–58. +d004369,Instituto Municipal de Parques y Jardines de Barcelona,ESP,ES511,08018,Barcelona,"Avinguda Diagonal, 240, 5.ª planta" +d004370,"T-Mobile Czech Republic, a.s.",CZE,CZ010,148 00,Praha 11- Chodov,Tomíčkova 2144/1 +d004371,Lernen fördern e. V.,DEU,DEA37,49477,Ibbenbüren, +d004372,Employment Service Agency of the Republic of North Macedonia,MKD,MK008,1000,Skopje,str. Vasil Gjorgov no.43 +d004373,Servicefirmaet Renell A/S,DNK,DK013,3000,Helsingør, +d004374,Bellcom Estonia OÜ,EST,EE,11411,Tallinn,Kivimurru tn 34-2 +d004375,MVZ Landau a. d. Isar GmbH MVZ Klinikum Deggendorf GmbH MVZ Donauisar Klinikum Dingolfing GmbH MVZ Klinikum am Luitpoldplatz Deggendorf GmbH üBAG,DEU,DE22C,94405,Landau a. d. I.,Bayerwaldring 17 +d004376,Arpiem Aviation,ROU,RO322,075100,Otopeni,Calea Bucureștilor nr. 224E +d004377,"Helsingin kaupunki, kaupunkiympäristön toimiala",FIN,FI1B1,FI-00510,Helsinki,Elimäenkatu 5 +d004378,Alta kommune,NOR,NO074,9506,Alta,Postboks 1403 +d004379,Uptime OÜ,EST,EE,11317,Tallinn,Pärnu mnt 158 +d004380,Strabag Pozemné a inžinierske staviteľstvo s. r. o.,SVK,SK,820 15,Bratislava,Mlynské nivy 61/A +d004381,Kreisverwaltung Mainz-Bingen,DEU,DEB3J,55218,Ingelheim am Rhein,Georg-Rückert-Str. 11 +d004382,Gras Savoye,FRA,FR105,92814,Puteaux Cedex,"immeuble Quai 33, 33/34 quai de Dion Bouton — CS 70001" +d004383,Toyota Billia AS,NOR,NO060,7300,Orkanger,Løypstrengen 14 +d004384,Volcano,BEL,BE,1930,Zaventem,Excelsiorlaan 41 +d004385,AMGEN GmbH,DEU,DE21,80992,München,Riesstr. 24 +d004386,Statens vegvesen,NOR,NO,2605,Lillehammer,Postboks 1010 Nordre Ål +d004387,Viešoji įstaiga Alytaus apskrities S. Kudirkos ligoninė,LTU,LT,LT-62114,Alytus,Ligoninės g. 12 +d004388,Port of Antwerp International nv,BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d004389,SUTURA Képviseleti és Kereskedelmi Korlátolt Felelősségű Társaság,HUN,HU,1097,Budapest,Gubacsi út 47. +d004390,BWI GmbH,DEU,DE212,80637,München,Dachauer Straße 128 +d004391,Mark Medical trgovina in storitve d.o.o.,SVN,SI,6210,Sežana,Partizanska cesta 109 +d004392,BWI GmbH,DEU,DE212,80637,München,Dachauer Straße 128 +d004393,Udviklingsselskabet By & Havn I/S,DNK,DK011,1259,København K,Nordre Toldbod 7 +d004394,Planungsgruppe VA GmbH,DEU,DE929,30539,Hannover, +d004395,"IT Děčín, s.r.o.",CZE,CZ04,405 02,Děčín,Teplická 27/29 +d004396,BCMM Kontor GmbH,DEU,DEA1,40211,Düsseldorf,Schirmerstraße 80 +d004397,Th. Geyer GmbH & Co. KG Niederlassung Berlin,DEU,DE300,10553,Berlin,Huttenstr. 34-35 +d004398,mCost storitve in trgovina d.o.o.,SVN,SI,1234,Mengeš,Ropretova cesta 45B +d004399,Remondis A/S,DNK,DK01,2605,Brøndby,Abildager 16 +d004400,Hees + Peters GmbH,DEU,DEB21,,Trier, +d004401,Schuessler-Plan Inżynierzy Sp. z o.o.,POL,PL91,00-807,Warszawa,Al. Jerozolimskie 96 +d004402,Entur AS,NOR,NO081,Rådhusgata 5,Oslo,Rådhusgata 5 +d004403,"KXN CZ, s.r.o.",CZE,CZ052,503 01,Hradec Králové,Říčařova 611/30 +d004404,Coler GmbH & Co. KG,DEU,DEB21,,Trier, +d004405,NIF Nemzeti Infrastruktúra Fejlesztő zártkörűen működő Részvénytársaság,HUN,HU,1134,Budapest,Váci út 45. +d004406,Joseph Hubert Bauunternehmung GmbH & Co. KG,DEU,DE254,90429,Nürnberg, +d004407,Radexpert Consulting&Management,ROU,RO321,023555,București,"Str. Ion Berindei nr. 11, sector 2" +d004408,Česká republika - Ministerstvo obrany,CZE,CZ010,160 00,Praha,Tychonova 221/1 +d004409,"Ikusi, S. L.",ESP,ES,,San Sebastián, +d004410,Bundeskanzleramt (BKAmt),DEU,DE300,10557,Berlin,Willy-Brandt-Straße 1 +d004411,"Medica, medicinska zastopstva, trgovina, marketing in posredovanje, d.o.o.",SVN,SI,1236,Trzin,Špruha 44 +d004412,"Clínica Santa Catalina, S. A.",ESP,ES705,,Las Palmas de Gran Canaria, +d004413,"Notes CS, a.s.",CZE,CZ010,149 00,Praha,Türkova 2319 5b +d004414,DB RegioNetz Infrastruktur GmbH (Bukr 76),DEU,DE712,60486,Frankfurt am Main,Europa-Allee 70-76 +d004415,"Stadt Mannheim, Dezernat III",DEU,DE126,68159,Mannheim,E 5 +d004416,RTI gruppo servizi associati SpA,ITA,ITI43,,Roma, +d004417,Conseil départemental 13,FRA,FRL04,13256,Marseille Cedex 20,52 avenue de Saint-Just +d004418,Spitalul Județean de Urgență Alexandria,ROU,RO317,140009,Alexandria,Str. Libertății nr. 1 +d004419,"Saubermacher Slovenija storitve pri varstvu okolja, trgovina in transport d.o.o.",SVN,SI,9000,Murska Sobota,Ulica Matije Gubca 2 +d004420,"Omega svetovanje, inženiring, razvoj in raziskovanje, d.o.o.",SVN,SI,1000,Ljubljana,Dolinškova ulica 8 +d004421,Standrew Wyrąb Cięcia Pielęgnacyjne Drzew Piotr Stańczak,POL,PL62,13-214,Uzdowo,Uzdowo 6 +d004422,Alliance Healthcare România,ROU,RO321,060859,București,Str. Amilcar C. Săndulescu nr. 7 +d004423,GKK AG,DEU,DEE07,39171,Sülzetal,Lange Göhren 19 +d004424,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d004425,Grad Zagreb,HRV,HR050,10020,Zagreb,Avenija Dubrovnik 15 +d004426,Communauté d'agglomération Beaune Côte et Sud — Chagny Nola,FRA,FRC11,21208,Beaune Cedex,14 rue Philippe Trinquet — BP 40288 +d004427,Société UP,FRA,FR105,92230,Gennevilliers,27/29 avenue des Louvresses +d004428,Landratsamt Coburg – Kommunaler Hochbau,DEU,DE247,96450,Coburg,Lauterer Straße 60 +d004429,Solita Oy,FIN,FI,FI-33100,Tampere,Peltokatu 26 +d004430,Promicra s.r.o.,CZE,CZ010,160 00,Praha 6,Evropská 1483/39 +d004431,Come Back Graphic,FRA,FR1,92213,Saint-Cloud, +d004432,Blindeninstitutsstiftung,DEU,DE263,97076,Würzburg,Ohmstr.7 +d004433,"Altego, zbiranje, predelava in trgovina z alternativnimi gorivi, d.o.o.",SVN,SI,5210,Deskle,Anhovo 1 +d004434,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d004435,"EKODOM, čistilni servis, Vasil Samarakov s.p.",SVN,SI,1000,Ljubljana,Mucherjeva ulica 3 +d004436,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Straße 8 +d004437,BRIARI'S IND,ROU,RO411,,Carcea,"Strada Calea Bucuresti, Nr. 2" +d004438,GIP SIB,FRA,FRH03,35065,Rennes Cedex,4 rue du Professeur-Jean-Pecker +d004439,Colas Nord-Est,FRA,FRC11,21600,Longvic, +d004440,Prolan Irányítástechnikai Zrt.,HUN,HU120,2011,Budakalász,Szentendrei út 1–3. +d004441,SocioFactor s.r.o.,CZE,CZ080,709 00,Ostrava–Mariánské Hory,Daliborova 631/22 +d004442,ADN Nevers,FRA,FRC12,58027,Nevers,124 route de Marzy — BP 41 +d004443,Powerpoint Engineering Ltd,IRL,IE0,Portlaoise,Co. Laois,Kea-Lew Business Park +d004444,"IRIS, Mednarodna trgovina, d.o.o.",SVN,SI,1000,Ljubljana,Cesta v Gorice 8 +d004445,Arpiem Aviation,ROU,RO322,075100,Otopeni,Calea Bucureștilor nr. 224E +d004446,"Stadt Ostfildern, Fachbereich 4, Gebäudemanagement",DEU,DE113,73760,Ostfildern,Otto-Vatter-Str. 12 +d004447,Valeor,FRA,FRL05,83300,Draguignan,109 rue Jean Aicard +d004448,Jumbo Omnichannel bv,NLD,NL,,Veghel, +d004449,"EG.D, a.s.",CZE,CZ064,602 00,Brno,"Lidická 1873/36, Černá Pole" +d004450,KKB Fastigheter AB,SWE,SE224,244 22,Kävlinge,Box 109 +d004451,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d004452,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d004453,Osnovna šola Markovci,SVN,SI,2281,Markovci,Markovci 33D +d004454,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d004455,GTN Gebäudetechnik Nord GmbH,DEU,DE80K,18209,Bad Doberan,Kröpeliner Str. 6 +d004456,Asociación Punto de Encuentro «Encontro»,ESP,ES111,15702,Santiago de Compostela,"C/ Cruceiro do Sar, 46, bajo" +d004457,"Gas Natural Comercializadora, S. A.",ESP,ES300,28028,Madrid,"Avenida América, 38" +d004458,Kommunales Vergabezentrum Kreis Groß-Gerau für den Kreis Groß-Gerau,DEU,DE717,64521,Groß-Gerau,Wilhelm-Seipp-Str. 4 +d004459,Chantiers Modernes Construction,FRA,FR107,94550,Chevilly-Larue,"3 rue Ernest Flammarion, ZAC du Petit Leroy" +d004460,BIA podjetje za laboratorijsko in procesno opremo d.o.o. Ljubljana,SVN,SI,1000,Ljubljana,Teslova ulica 30 +d004461,Commissariat à l'énergie atomique et aux énergies alternatives,FRA,FR,91191,Gif-sur-Yvette Cedex,CEA Paris Saclay — Bâtiment 482 — PC n° 70 +d004462,Iclean ehf,ISL,IS001,201,Kópavogur,Dalvegur 16c +d004463,GKB Realisatie bv,NLD,NL,2992 SP,Barendrecht,Middelweg 1 +d004464,Duponchel,FRA,FRE11,59790,Ronchin,18 rue Paul Lafargue +d004465,Uždaroji akcinė bendrovė „Adranas“,LTU,LT,LT-51231,Kaunas,Draugystės g. 19D +d004466,Avfall Sør AS,NOR,NO092,,Kristiansand S, +d004467,LIAMED,ROU,RO122,500182,Brasov,"Strada Griviţei, Nr. A8" +d004468,VšĮ Respublikinė Klaipėdos ligoninė,LTU,LT,LT-92231,Klaipėda,S. Nėries g. 3 +d004469,VRTEC MOJCA,SVN,SI,1000,Ljubljana,Levičnikova ulica 11 +d004470,Canon Norge AS,NOR,NO,1256,Oslo,Hallagerbakken 110 +d004471,EPS,FRA,FRL04,13240,Septèmes-les-Vallons,40 ZAC de la Haute-Bédoule +d004472,Občina Šmartno ob Paki,SVN,SI,3327,Šmartno ob Paki,Šmartno ob Paki 69 +d004473,"Metalka Media, podjetje za prodajo medicinskih pripomočkov, d.o.o.",SVN,SI,1000,Ljubljana,Cesta v Gorice 34C +d004474,"Delegación Territorial de Empleo, Formación, Trabajo Autónomo, Transformación Económica, Industria, Conocimiento y Universidades en Granada",ESP,ES614,18013,Granada,"Avenida Joaquina Eguaras, 2, Edificio Administrativo Almanjáyar" +d004475,AMOES,FRA,FR105,92600,Asnières-sur-Seine,31 rue Bapst +d004476,Hansataucher GmbH,DEU,DE600,20539,Hamburg,Peuter Elbdeich 35 +d004477,Gemeente Oosterhout,NLD,NL,4902 ZP,Oosterhout,Slotjesveld 1 +d004478,Istituto zooprofilattico sperimentale della Lombardia e dell'Emilia Romagna «Bruno Ubertini»,ITA,ITC47,25124,Brescia,via Bianchi 9 +d004479,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d004480,Standrew Wyrąb Cięcia Pielęgnacyjne Drzew Piotr Stańczak,POL,PL62,13-214,Uzdowo,Uzdowo 6 +d004481,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d004482,"L-Med, trgovina z medicinskimi potrebščinami in materiali, d.o.o.",SVN,SI,2351,Kamnica,Pod vinogradi 45 +d004483,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d004484,Trumm d.o.o.,HRV,HR03,51511,Malinska,Kralja Tomislava 19 +d004485,Peab Sverige AB,SWE,SE,904 06,Umeå,Box 4203 +d004486,"Torfal, Lda.",PRT,PT16J,,Belmonte, +d004487,GEC Rhône Alpes,FRA,FRK26,69130,Ecully,20 chemin Louis Chirpaz +d004488,Coral Impex S.R.L.,ROU,RO316,100510,Ploiești,"Str. Peneș Curcanu nr. 8, bloc 151C, ap. 10" +d004489,Union CO,ROU,RO113,400552,Cluj-Napoca,Str. Miron Costin nr. 12A +d004490,OMV Petrom S.A,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d004491,GrassMark Oy,FIN,FI1C1,,Lieto, +d004492,"Lurraska, S. L.",ESP,ES213,,Arakaldo, +d004493,Irish Commercials,IRL,IE06,,Naad,Millennium Park +d004494,Infimed,FRA,FR,59000,Lille,2 rue Gauthier de Châtillon +d004495,"RJ Autocares, S. L.",ESP,ES3,28906,Getafe,"C/ Solidaridad, 6" +d004496,Volkswirtschaft Berner Oberland,CHE,CH0,3800,Interlaken,Kammistrasse 13 +d004497,APR — JCB Nettoyage,FRA,FRI12,33700,Mérignac,11 rue Bernard Palissy +d004498,Zakład Zamówień Publicznych przy Ministrze Zdrowia,POL,PL,02-326,Warszawa,"Al. Jerozolimskie 155, pok. 115" +d004499,"KPL, družba za gradnjo in vzdrževanje cest, zelenih površin ter inženiring d.o.o.",SVN,SI,1000,Ljubljana,Tbilisijska ulica 61 +d004500,"Altran Innovación, S. L.",ESP,ES,28022,Madrid,"C/ Campezo, 1" +d004501,SAE POPB,FRA,FR101,75012,Paris,www.accorarena.com +d004502,DAA Deutsche Angestellten-Akademie GmbH,DEU,DEA,53111,Bonn,Kaiser-Karl-Ring 12 +d004503,Adden Auvergne-Rhone-Alpes,FRA,FRK26,69001,Lyon,1 rue de la République +d004504,Steril România,ROU,RO321,041831,București,"Str. Metalurgiei nr. 3-5, sector 4" +d004505,Staatliches Hochbauamt Freiburg,DEU,DE131,79104,Freiburg,Kartäuserstraße 61b +d004506,Gmina Tułowice,POL,PL52,49-130,Tułowice,ul. Szkolna 1 +d004507,OMV Petrom S.A.,ROU,RO321,013329,București,Str. Coralilor nr. 22 +d004508,"GreenChem CZ, s.r.o.",CZE,CZ0,149 00,Praha 4,"Pyšelská 2327/7, Chodov" +d004509,Flemming'S,FRA,FRB04,37210,Parçay-Meslay,470 rue Henri-Potez +d004510,Tuinwijk cvba,BEL,BE232,9160,Lokeren,Meersstraat 8 +d004511,Arimex Comexim 2000,ROU,RO321,042056,București,Str. Călțunași nr. 2 +d004512,Scania Danmark A/S,DNK,DK0,2635,Ishøj,Industribuen 19 +d004513,Östad Bergtäkt AB,SWE,SE232,441 91,Alingsås,"c/o Östads stiftelse, Östads säteri 1" +d004514,Københavns Kommune,DNK,DK011,2200,København,Sjællandsgade 40 +d004515,Stadt Schleswig,DEU,DEF0C,24837,Schleswig,Rathausmarkt 1 +d004516,"Furialltrade, Lda.",PRT,PTZZZ,4760-841,Vila Nova de Famalicão,"Rua do Progresso, 140, lote 1, escadas 11 e 12" +d004517,"SIJ, podjetje za proizvodnjo in ekonomske storitve z marketingom, d.o.o.",SVN,SI,1230,Domžale,Krumperška ulica 11 +d004518,Bialmed Sp. z o.o.,POL,PL9,02-546,Warszawa,ul. Kazimierzowska 46/48/35 +d004519,Presidencia de la Diputación Provincial de Ourense,ESP,ES113,,Galicia, +d004520,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d004521,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d004522,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d004523,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d004524,RER VEST,ROU,RO111,410270,Oradea,"Strada Vladimirescu Tudor, Nr. 79" +d004525,"Aeronaval de Construcciones e Instalaciones, S. A.",ESP,ES,00000,No especificado,No especificado +d004526,"Rhein-Sieg-Kreis, Der Landrat, Allgemeine Dienste und Zentrale Vergabestelle",DEU,DEA2C,53721,Siegburg,Kaiser-Wilhelm-Platz 1 +d004527,"Teknoservice, S. L.",ESP,ES618,,Sevilla, +d004528,"Solvent Iniciativas Empresariales, S. L.",ESP,ES620,30007,Murcia,"C/ Molina de Segura, 5, bloque 3, 2.º C" +d004529,Stadibau GmbH — Gesellschaft für den Staatsbediensteten Wohnungsbau in Bayern mbH,DEU,DE212,80804,München,Mottlstr. 1 +d004530,Engie,FRA,FRK26,69246,Lyon,127 avenue Barthélémy Buyer +d004531,MDO cotraitant,FRA,FRB02,28240,La Loupe,11 bis avenue de Beauce +d004532,Veikko Lehti Oy,FIN,FI196,,Pori, +d004533,CEZ Vânzare S.A.,ROU,RO411,200581,Craiova,"Calea Severinului nr. 97, et. 1" +d004534,Scanmar AS,NOR,NO,3179,Åsgårdstrand,Åsgårdstrandsveien 359 +d004535,"Hospital Garcia de Orta, E. P. E.",PRT,PT170,2805-267,Almada,Avenida Torrado da Silva +d004536,LUBW Landesanstalt für Umwelt Baden-Württemberg,DEU,DE12,76185,Karlsruhe,Griesbachstraße 1 +d004537,Mestna občina Celje,SVN,SI,3000,Celje,Trg celjskih knezov 9 +d004538,BioCat,DEU,DE125,69120,Heidelberg,Im Neuenheimer Feld 584 +d004539,Dell SA,CHE,CH0,1218,Le Grand-Saconnex,route de l'Aéroport 29 +d004540,AGS Abbruch GmbH & Co. KG,DEU,DE80K,,Dummerstorf, +d004541,"Allianz, Compañía de Seguros y Reaseguros, S. A.",ESP,ES300,,Madrid,"C/ Ramirez de Arellano, 35" +d004542,Albaida Infraestructuras,ESP,ES,04006,Almería,"C/ el Alcázar, 7, 1.º B" +d004543,Ministerstvo spravedlnosti České republiky,CZE,CZ010,128 10,Praha 2,Vyšehradská 16 +d004544,Tiefenthaler-Schichtle GmbH,AUT,AT323,5110,Oberndorf,Paracelsusstraße 20 +d004545,Rems-Murr-Kliniken gGmbH,DEU,DE116,71364,Winnenden,Am Jakobsweg 1 +d004546,Spitalul Județean de Urgență Zalău,ROU,RO116,450129,Zalău,Str. Simion Bărnuţiu nr. 67 +d004547,"Extra Lux, proizvodno in trgovsko podjetje d.o.o., Ljubljana",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 17B +d004548,"Futura Soft, s.r.o.",CZE,CZ064,612 00,Brno,Příkop 843/4 +d004549,Vestra Industry S.R.L.,ROU,RO212,,Cătămărești-Deal,Str. Mihai Eminescu nr. 85 +d004550,ANDYTEH CONCEPT S.R.L.,ROU,RO321,031126,Bucuresti,"Strada Negoiu, Nr. 6" +d004551,Bright Finland Oy,FIN,FI1B1,,Vantaa, +d004552,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d004553,Dirección General del Agua,ESP,ES300,28071,Madrid,Plaza de San Juan de la Cruz +d004554,Stadt Hanau,DEU,DE719,63450,Hanau,Hessen-Homburg-Platz 7 +d004555,Faber Bygg AS,NOR,NO0A1,,Stavanger, +d004556,"CSF, s.r.o.",CZE,CZ052,500 02,Hradec Králové,Střelecká 672/14 +d004557,Wohn- und Pflegeheim Zell am Ziller - Kaiser Franz Josef Stiftung,AUT,AT335,6280,Zell am Ziller,Gerlosstraße 5 +d004558,Planungsgesellschaft Denzer + Kiefer bR,DEU,DEC02,66663,Merzig-Besseringen,Pastor-Krayer-Straße 2 a +d004559,"Meditrina, družba za trženje medicinskih pripomočkov in opreme d.o.o.",SVN,SI,1000,Ljubljana,Dunajska cesta 199 +d004560,Versamed Sp. z o.o.,POL,PL841,15-703,Białystok, +d004561,MTI,FRA,FRY30,97393,Saint-Laurent-du-Maroni,"Nº 2 rue du Bac, BP 61, 97393" +d004562,CEIT SpA,ITA,ITF14,,San Giovanni Teatino (CH),"via Aterno 108, fraz. Sambuceto" +d004563,Osaühing Gevatex,EST,EE,13516,Tallinn,Rannamõisa tee 4 +d004564,BOC Information Technologies Consulting GmbH,DEU,DE300,10245,Berlin,Naglerstraße 5 +d004565,Cappellotto,FRA,FRI12,33074,Fontanafredda,Via A.-Malignani 2N +d004566,Loiste Sähkönmyynti Oy,FIN,FI,FI-50101,Mikkeli,PL 40 +d004567,Wojewódzki Szpital Zespolony im. Stanisława Rybickiego,POL,PL71,96-100,Skierniewice,ul. Rybickiego 1 +d004568,VRT,BEL,BE1,1043,Brussel,Auguste Reyerslaan 52 +d004569,Roche Polska Sp. z o.o.,POL,PL,02-672,Warszawa,ul. Domaniewska 39b +d004570,FB-Aufzüge GmbH & Co. KG - Dresden,DEU,DED2,01257,Dresden,Straße des 17. Juni 25 +d004571,BSI,FRA,FR102,77550,Limoges-Fourches,10 rue de l'Industrie +d004572,VIŠKI VRTCI,SVN,SI,1000,Ljubljana,Jamova cesta 23 +d004573,Solexperts France,FRA,FRF31,54500,Vandœuvre-lès-Nancy,10 allée de la Forêt de la Reine +d004574,"Land Schleswig-Holstein - Ministerium für Energiewende, Landwirtschaft, Umwelt, Natur und Digitalisierung",DEU,DEF02,24106,Kiel,Mercatorstraße 3 +d004575,"Amcobex Information Technologies, s.r.o.",CZE,CZ064,627 00,Brno, +d004576,Fanenbruck GmbH & Co. KG,DEU,DEA45,32105,Bad Salzuflen,Otto-Hahn-Straße 44 +d004577,Institut klinické a experimentální medicíny,CZE,CZ010,140 00,Praha,Vídeňská 1958/9 +d004578,Docerom Sistem S.R.L.,ROU,RO224,806400,Movileni (Sendreni),Str. Principală nr. 21 +d004579,Sorsele kommun,SWE,SE,924 31,Sorsele,Burevaga 4 +d004580,Ville de Charleroi,BEL,BE32B,6000,Charleroi,Place Charles II 14-15 +d004581,"Hulleras del Norte, S. A., S. M. E.",ESP,ES120,33005,Oviedo,"Avenida de Galicia, 44" +d004582,Sittomat,FRA,FRL05,83200,Toulon,"chemin Gaëtan Gastaldo, quartier Escaillon" +d004583,Caretec i Forserum AB,SWE,SE211,571 78,Forserum,Stenserydsvägen 3 +d004584,H2OLAND AB,SWE,SE232,441 31,Alingsås,Grindgatan 1 +d004585,Distribuție Energie Oltenia S.A.,ROU,RO411,200769,Craiova,"Calea Severinului nr. 97, parter, et. 2, 3, 4" +d004586,K. Gerdes GmbH,DEU,DE943,26125,Oldenburg,Wilhelmshavener Heerstraße 325 +d004587,Colin Romain Microentreprise,FRA,FRF11,67300,Schiltigheim,21a rue des Petits Champs +d004588,"Autonova, s.r.o.",SVK,SK041,058 01,Poprad,Priemyselný areál Východ 3406 +d004589,"Labohem trgovina, zastopstvo, posredništvo, d.o.o.",SVN,SI,1230,Domžale,Kettejeva ulica 16 +d004590,Sundsvall Hamn AB,SWE,SE,851 21,Sundsvall,Box 722 +d004591,Groupement GA-Architecture (mandataire)/OTE Ingénierie,FRA,FR101,75020,Paris,27 rue du Repos +d004592,Lusk Motor Factors Ltd T/A Swords Motor Factors,IRL,IE,Co. Dublin,Dublin,"Forest Rd, Swords" +d004593,Regierung von Oberbayern — Zentrale Vergabestelle,DEU,DE212,80538,München,Maximilianstr. 39 +d004594,Willich Elektrotechnik GmbH,DEU,DE733,36179,Bebra,Kerschensteinerstraße 15 +d004595,"HR Protecção, S. A.",PRT,PT11D,,Mangualde, +d004596,Mestna občina Velenje,SVN,SI,3320,Velenje,Titov trg 1 +d004597,Bosch Sicherheitssysteme GmbH,DEU,DE300,10407,Berlin,Storkower Str. 101 +d004598,Biodiagramm srl,ITA,ITI,,Napoli, +d004599,"Nextis Services, s.r.o.",CZE,CZ080,720 00,Ostrava,Krmelínská 934 4 +d004600,Agence française de développement,FRA,FR101,75012,Paris,5 rue Roland-Barthes +d004601,Wojewódzki Szpital Zespolony im. Stanisława Rybickiego,POL,PL71,96-100,Skierniewice,ul. Rybickiego 1 +d004602,Schäble GmbH Schreinerei,DEU,DE11D,73469,Goldburghausen,Goldbergstraße 24 +d004603,DANLIN XXL,ROU,RO214,617428,Horia,"Strada-, nr.-" +d004604,Telford and Wrekin Council,GBR,UKG21,TF3 4JA,Telford,"Darby House, Lawn Central" +d004605,Bordeaux métropole,FRA,FRI12,33045,Bordeaux,esplanade Charles de Gaulle +d004606,Huber Fenster AG,CHE,CH0,9100,Herisau,St. Gallerstraße 57 +d004607,T-Systems International GmbH,DEU,DE712,60528,Frankfurt,Hahnstraße 43 +d004608,Nybloms Pappers Aktiebolag,SWE,SE213,390 04,Kalmar,Box 4016 +d004609,Gmina Miasto Lębork,POL,PL636,84-300,Lębork,ul. Armii Krajowej 14 +d004610,Zeiler-Technik GmbH & Co. KG,DEU,DE214,84524,Neuötting,August-Unterholzner-Straße 5 +d004611,Česká republika - Kancelář Poslanecké sněmovny,CZE,CZ010,118 26,Praha 1,Sněmovní 176/4 +d004612,"Timestamp — Sistemas de Informação, S .A.",PRT,PT17,1700-036,Lisboa,"Praça de Alvalade, 6, 11.º frente" +d004613,Vrtec Mojca,SVN,SI,1000,Ljubljana,Levičnikova ulica 11 +d004614,insert'Net,FRA,FRI12,33000,Bordeaux, +d004615,Weatherford Atlas GIP S.A.,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2A +d004616,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Str. 8 +d004617,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d004618,Triolab Oy,FIN,FI,,Turku, +d004619,Terraverde S.R.L.,ROU,RO316,100173,Ploiești,Str. Stadionului nr. 26 +d004620,Nybloms Pappers Aktiebolag,SWE,SE213,390 04,Kalmar,Box 4016 +d004621,Steril România,ROU,RO321,041831,București,"Str. Metalurgiei nr. 3-5, sector 4" +d004622,Region Kalmar Län,SWE,SE213,392 44,Kalmar,Sjöbrings väg 4A plan 2 +d004623,Veiligheids- en Gezondheidsregio Gelderland-Midden,NLD,NL,6828HZ,Arnhem,Eusebiusbuitensingel 43 +d004624,Association verte vallée,FRA,FRY10,97119,Vieux-Habitants,route de Grande Rivière +d004625,Forstbetrieb Manuel Kiesow,DEU,DE40C,15848,Rietz-Neuendorf OT Glienicke,Storkower Straße 4 +d004626,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d004627,Geotec,FRA,FR,21800,Quétigny,9 boulevard de I'Europe +d004628,"Land Tirol, Amt der Tiroler Landesregierung, Abteilung Landessanitätsdirektion",AUT,AT,6020,Innsbruck,Boznerplatz 6 +d004629,Sansia Oy,FIN,FI1D2,FI-70600,Kuopio,"PL 2000, Viestikatu 3" +d004630,Medika d.d.,HRV,HR050,10000,Zagreb,Capraška 1 +d004631,"Golias, proizvodnja, trgovina in storitve d.o.o.",SVN,SI,1000,Ljubljana,Cesta na Mesarico 2 +d004632,Hemminger Ingenieurbüro GmbH & Co. KG,DEU,DE113,73730,Esslingen,Röntgenstraße 1/1 +d004633,Techartstav s.r.o.,CZE,CZ080,708 00,Ostrava–Poruba,Rabasova 1157/8 +d004634,"ČEZ, a.s.",CZE,CZ01,140 53,Praha 4,Duhová 2/1444 +d004635,Kantega AS,NOR,NO081,0153,Oslo,Kirkegata 5 +d004636,Palm Recycling GmbH & Co. KG,DEU,DE11D,73432,Aalen,Neukochen 10 +d004637,Günther Priese GmbH,DEU,DE922,49356,Diepholz,Kielweg 98 +d004638,Polskie Koleje Państwowe S.A.,POL,PL911,02-305,Warszawa,Al. Jerozolimskie 142 A +d004639,Nurmeksen kaupunki,FIN,FI1D3,,Nurmes, +d004640,Wasserverband Weddel-Lehre,DEU,DE91,38162,Cremlingen,Hauptstr. 2b +d004641,Maxigel S.R.L.,ROU,RO316,100070,Ploiești,Str. Laboratorului nr. 29B +d004642,"Havenbedrijf Antwerpen, nv van publiek recht",BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d004643,K.Westermann GmbH & Co.KG,DEU,DE113,73770,Denkendorf,Albstr. 1 +d004644,Conseil départemental du Rhône,FRA,FRK26,69483,Lyon,29-31 cours de la Liberté +d004645,LWL — Bau- und Liegenschaftsbetrieb (LWL-BLB),DEU,DEA33,48145,Münster,Warendorfer Straße. 24 +d004646,ASOBO studio SAS,FRA,FRI12,33074,Bordeaux,23 parvis des Chartrons +d004647,DB Netz AG (Bukr 16),DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 11-13 +d004648,S.C. Edilitara Public S.A. Târgu Jiu,ROU,RO412,210234,Târgu Jiu,Str. Victoriei nr. 45 +d004649,Agmar d.o.o.,HRV,HR050,10000,Zagreb,Čazmanska 8 +d004650,Hera SpA,ITA,ITH55,40127,Bologna,viale Carlo Berti Pichat 2/4 +d004651,GPI SpA,ITA,ITH2,,Trento, +d004652,DB Netz AG (Bukr 16),DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 11-13 +d004653,Concejalía Delegada en Materia de Contratación del Ayuntamiento de Torremolinos,ESP,ES617,29620,Torremolinos,"Plaza Blas Infante, 1" +d004654,Pleno del Ayuntamiento de Mogán,ESP,ES70,35140,Mogán,"Avenida de la Constitución, 4" +d004655,Zehm Vertrieb und Service GmbH,DEU,DEE06,39288,Burg,Bahnhofstraße 16 +d004656,RER VEST,ROU,RO111,410270,Oradea,"Strada Vladimirescu Tudor, Nr. 79" +d004657,"Imesapi, S. A.",ESP,ES705,35219,Telde,"C/ Beneficiado José Estupiñán, 11, Telde" +d004658,köhler architekten + beratende ingenieure gmbh,DEU,DE21L,82131,Gauting, +d004659,Stölting GmbH Reinigung und Service,DEU,DEA32,45891,Gelsenkirchen,Willy-Brandt-Allee 314 +d004660,Stadtverwaltung Balingen,DEU,DE143,72336,Balingen,Neue Straße 31 +d004661,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d004662,"José Pereira Remelhe & Filhos, Lda.",PRT,PT112,,Barcelos, +d004663,HSY Helsingin seudun ympäristöpalvelut -kuntayhtymä,FIN,FI1B1,FI-00240,Helsinki,Ilmalantori 1 +d004664,Hees + Peters GmbH,DEU,DEB21,,Trier, +d004665,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d004666,In Extenso Innovation Croissance,FRA,FR,06410,Biot,"2000 route des Lucioles Les Algorithmes, Thalès B" +d004667,"Italcomma Slovakia, s.r.o.",SVK,SK,010 01,Žilina,Dolné Rudiny 1 +d004668,Lease Green,FRA,FRB06,45140,Ormes,6 rue des Châtaigniers +d004669,Amt Döbern-Land,DEU,DE40G,03159,Döbern,Forster Straße 8 +d004670,Centre de gestion de la FPT du Rhône,FRA,FRK26,69110,Sainte Foy-lès-Lyon,9 allée Alban Vistel +d004671,European Border and Coast Guard Agency — Frontex,POL,PL911,00-844,Warsaw,Plac Europejski 6 +d004672,adelphi consult GmbH,DEU,DE300,10559,Berlin, +d004673,"Bundesrepublik Deutschland, vertreten durch das Beschaffungsamt des Bundesministeriums des Innern",DEU,DEA22,53119,Bonn,Brühler Straße 3 +d004674,Stadt Neubukow,DEU,DE80K,18233,Neubukow,Am Markt 1 +d004675,Sector 3 (Primăria Sectorului 3 București),ROU,RO321,031084,Bucureşti,Calea Dudești nr. 191 +d004676,"Z + M Partner, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Valchařská 3261/17, Moravská Ostrava" +d004677,TTW Waldpflege GmbH,DEU,DE238,93047,Regensburg,Waffnergasse 6 +d004678,Trafikverket,SWE,SE,781 99,Borlänge,Huvudkontoret Röda vägen 1 +d004679,"Harald Bruhns GmbH, Vertriebscenter Berlin",DEU,DE405,13407,Berlin,Montanstraße 6 +d004680,Eigen Thuis vzw,BEL,BE,1850,Grimbergen,Schildpadstraat 30 +d004681,"OPH émeraude habitation, office public de l'habitat de Saint-Malo agglomération.",FRA,FRH03,35400,Saint-Malo,12 avenue Jean Jaurès +d004682,"Med - Art, spol. s r.o.",SVK,SK023,949 01,Nitra,Hornočermánska 4 +d004683,AGMAR d.o.o.,HRV,HR050,10000,Zagreb,Čazmanska 8 +d004684,"STRABAG AG, Direktion Nord, Bereich Weser-Ems",DEU,DE94C,26349,Jaderberg,Am Esch 19 +d004685,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d004686,"Indra Soluciones Tecnologias de la Información, S. L. U.",ESP,ES,,Madrid, +d004687,HEDELIUS Maschinenfabrik GmbH,DEU,DEA,49716,Meppen,Sandstraße 11 +d004688,Bundesagentur für Arbeit Regionales Einkaufszentrum Nord,DEU,DE,30147,Hannover,Postfach +d004689,Työyhteenliittymä Radalla,FIN,FI1B1,,Vantaa, +d004690,Ceste Rijeka d.o.o.,HRV,HR03,51227,Kukuljanovo,Kukuljanovo 377 +d004691,"Fresenius Kabi, s.r.o.",CZE,CZ01,140 00,Praha,Na strži 1702/65 +d004692,"Segalab — Laboratório de Sanidade Animal e Segurança Alimentar, S. A.",PRT,PT,4490-258,Póvoa de Varzim,"Lugar de Cassapos, Argivai" +d004693,SPL Paris et Métropole aménagement,FRA,FR101,75927,Paris Cedex 19,12 passage Susan Sontag — CS 30054 +d004694,"Roche Diagnostics, S. L. U.",ESP,ES511,08174,San Cugat de Vallés (Barcelona), +d004695,Veolia Energie România,ROU,RO321,020276,București,Str. Tunari nr. 60A +d004696,Deutsche Angestellten-Akademie GmbH,DEU,DEA12,47053,Duisburg,Werthauser Straße 164-166 +d004697,HKF Haustechnik GmbH,DEU,DE,23992,Krassow,Kastanienallee 56 +d004698,Distribuție Energie Oltenia S.A.,ROU,RO411,200769,Craiova,"Calea Severinului nr. 97, parter, et. 2, 3, 4" +d004699,Fraher Distribution S.R.L.,ROU,RO225,,Tulcea,Str. Forestierului nr. 34 +d004700,Junta de Gobierno Local del Ayuntamiento de Cartagena,ESP,ES620,30201,Cartagena,"C/ San Miguel, 8" +d004701,UAB „Real Fusion“,LTU,LT,,Vilnius, +d004702,Mittetulundusühing Valga Arvutikeskus,EST,EE,68204,Valga vald,Vabaduse tn 22-7 +d004703,EMU IDF,FRA,FR104,91700,Sainte-Geneviève-des-Bois,5 rue du Petit Fief — ZI de la Croix Blanche +d004704,Service d'entretien et nettoyage industriel,FRA,FR107,94250,Gentilly,35 rue de Valenton +d004705,Concejalía Delegada de Planificación y Recursos del Ayuntamiento de Valladolid,ESP,ES418,47001,Valladolid,"Plaza Mayor, 1" +d004706,ID UP,FRA,FRG01,,Nantes, +d004707,"Vilex '94. Ipari-, Szolgáltató- és Kereskedelmi Kft.",HUN,HU,4100,Berettyóújfalu,Széchenyi utca 74. +d004708,Siemor,FRA,FRD22,76350,Oissel,1792 avenue du Général de Gaulle +d004709,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschiz,"Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" +d004710,"Generalidad de Cataluña, Departamento de Territorio y Sostenibilidad",ESP,ES51,08029,Barcelona,"Avenida Josep Tarradellas, 2, 4, 6" +d004711,Kur- und Touristikunternehmen der Stadt Bad Salzungen (kAöR),DEU,DEG0P,36433,Bad Salzungen,Am Flößrasen 1 +d004712,"Landeshauptstadt München, Direktorium, Vergabestelle 1 Abt. 2",DEU,DE212,80636,München,Birkerstraße 18 +d004713,"Medicoengineering d.o.o., podjetje za projektiranje, inženiring, izvajanje in vodenje investicijskih projektov",SVN,SI,1236,Trzin,Prevale 1 +d004714,"Notes CS, a.s.",CZE,CZ010,149 00,Praha,Türkova 2319 5b +d004715,adesso SE,DEU,DEA52,44269,Dortmund, +d004716,Ville de Pontault-Combault,FRA,FR102,77347,Pontault-Combault Cedex,107 avenue de la République +d004717,BWI GmbH,DEU,DE300,80637,München,Dachauer Straße 128 +d004718,SNTFC „CFR Călători” S.A.,ROU,RO321,010867,Bucureşti,"Str. Dinicu Golescu nr. 38, sector 1, București" +d004719,Silvacultura S.R.L.,ROU,RO125,545500,Sovata,"Str. Minei nr. 4, Sovata, Mureș" +d004720,Genel Marie,FRA,FR106,93170,Bagnolet,45 rue de la Capsulerie +d004721,Ríkiskaup,ISL,IS,IS-105,Reykjavik,Borgartun 7c +d004722,Artemis,FRA,FRE22,60210,Halloy,8 bis route de Beauvais +d004723,M.N.O. Stühler GmbH & Co. KG,DEU,DE254,90411,Nürnberg, +d004724,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 — Haus 6 +d004725,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d004726,FIATC Mútua de Seguros y Reaseguros,ESP,ES511,08017,Barcelona,"Avenida Diagonal, 648" +d004727,Asclepios S.A.,POL,PL514,50-502,Wrocław,ul. Hubska 44 +d004728,Direcția Generală de Salubritate Sector 3,ROU,RO321,032494,București,"Str. Steriadi Jean Alexandru nr. 17, sector 3, judet: București, localitate: București, cod poștal: 032494" +d004729,Markt Marktleugast,DEU,DE24B,95352,Marktleugast,Neuensorger Weg 10 +d004730,SVA System Vertrieb Alexander GmbH,DEU,DE714,65205,Wiesbaden,Borsigstraße 26 +d004731,Comune di Monza,ITA,ITC4D,20900,Monza,p.zza Trento e Trieste +d004732,"Dräger Slovenija, servis in prodaja, d.o.o.",SVN,SI,1231,Ljubljana - Črnuče,Nadgoriška cesta 19 +d004733,Direction des achats,CHE,CH0,1015,Lausanne,"Station 7, Bâtiment BI, bureau BI A0 528" +d004734,Katinala Live Oy,FIN,FI1C2,,Katinala, +d004735,Laireiter Forstbetrieb GmbH,AUT,AT32,5611,Grossarl,Ellmau 8 +d004736,"Nemocnice Pardubického kraje, a.s.",CZE,CZ053,532 03,Pardubice,Kyjevská 44 +d004737,Stadt Vacha,DEU,DEG0P,36404,Vacha,Bahnhofstraße 21 +d004738,Centre Hospitalier de Saint-Brieuc,FRA,FRH01,22027,Saint-Brieuc Cedex 1,10 rue Marcel Proust +d004739,Meidän IT ja Talous Oy,FIN,FI1D3,,Lappeenranta, +d004740,HEES + PETERS GmbH,DEU,DEB21,,Trier, +d004741,civillent GmbH,DEU,DE141,,Reutlingen, +d004742,Majone & Partners srl,ITA,ITC4C,,Milano, +d004743,NMP nv,BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d004744,Sarre et Moselle,FRA,FRF11,57400,Strasbourg,17 avenue Poincaré +d004745,"SIJ, podjetje za proizvodnjo in ekonomske storitve z marketingom, d.o.o.",SVN,SI,1230,Domžale,Krumperška ulica 11 +d004746,Serviceplan Berlin GmbH & Co. KG,DEU,DE300,,Berlin, +d004747,Sungran Sp. z o.o.,POL,PL841,15-542,Białystok,ul. Ciesielska 1/23 +d004748,SARL Serial Acoustique (cotraitant),FRA,FRJ15,66000,Perpignan,136 rue Louis-Delaunay +d004749,Briand Construction Métallique,FRA,FRG05,85101,Les Herbiers,"29 avenue des Sables, CS 10117" +d004750,Dachdeckerei K.H. Fischer GmbH,DEU,DEB3F,66987,Thaleischweiler-Fröschen,Fröschener Str. 83 A +d004751,Sträter GmbH,DEU,DEA35,,Dülmen, +d004752,Gemeente Rijswijk,NLD,NL,,Rijswijk, +d004753,ProRail bv,NLD,NL,3511 EP,Utrecht,Moreelsepark 3 +d004754,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 - Haus 6 +d004755,wemove digital solutions GmbH,DEU,DE,60314,Frankfurt am Main,Hanauer Landstraße 52 +d004756,Helmecke Blitzschutz und Erdungsanlagen,DEU,DEE07,39387,Oschersleben, +d004757,Komenda Główna Policji,POL,PL,02-624,Warszawa,ul. Puławska 148/150 +d004758,J. F. Brammer Rohstoffe GmbH,DEU,DEF05,,Nordhastedt, +d004759,Aicher Group GmbH & Co. KG,DEU,DE212,81829,München,Karl-Schmid-Straße 9 +d004760,UAB „Salmeda“,LTU,LT,,Vilnius, +d004761,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d004762,ProRail bv,NLD,NL,3511 EP,Utrecht,Moreelsepark 3 +d004763,Informationstechnikzentrum Bund (ITZBund),DEU,DEA22,53175,Bonn,Bernkasteler Straße 8 +d004764,Jan Håkansson Byggplanering Aktiebolag,SWE,SE232,431 49,Mölndal,Alfagatan 20 +d004765,Bundesministerium für Gesundheit,DEU,DEA22,53123,Bonn, +d004766,TTK GmbH,DEU,DE12,76131,Karlsruhe,Gerwigstraße 53 +d004767,Bundesagentur für Arbeit Regionales Einkaufszentrum NRW,DEU,DE,40474,Düsseldorf,Josef-Gockeln-Str. 7 +d004768,"Salus, Veletrgovina, družba za promet s farmacevtskimi, medicinskimi in drugimi proizvodi, d.o.o.",SVN,SI,1000,Ljubljana,Litostrojska cesta 46A +d004769,"Ústav fyziky materiálů AVČR, v.v.i.",CZE,CZ064,616 00,Brno,Žižkova 513/22 +d004770,Zorginstituut Nederland,NLD,NL329,1112 ZA,Diemen,Willem Dudokhof 1 +d004771,Vodafone,IRL,IE,Dublin,Dublin 18,"Mountainview, Leopardstown" +d004772,Sleth A/S,DNK,DK,8000,Århus C,Sonnesgade 11 +d004773,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d004774,Pro-Las sp. z o.o. sp. k.,POL,PL841,15-620,Białystok,ul. Elewatorska 11/1 +d004775,Ministrstvo za notranje zadeve,SVN,SI,1000,Ljubljana,Štefanova ulica 2 +d004776,Magdeburger Verkehrsbetriebe GmbH & Co. KG,DEU,DEE03,39104,Magdeburg,Otto-von-Guericke-Straße 25 +d004777,Projexia,FRA,FRK25,42800,Rive-de-Gier,40 boulevard des Provinces +d004778,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d004779,AUTRIGA società consortile coop. sociale,ITA,ITI21,06125,Perugia,via F.lli Cairoli 24 +d004780,"Braintec podjetje za sodobne tehnologije, d.o.o.",SVN,SI,1000,Ljubljana,Cesta Andreja Bitenca 68 +d004781,costituendo R.T.I. KPMG advisory SpA — INFO.C.E.R. srl,ITA,ITI4,,Roma, +d004782,"Harald Bruhns GmbH, Vertriebscenter Berlin",DEU,DE405,13407,Berlin,Montanstraße 6 +d004783,"Servizi integrati srl, via Sistina 121, 00187, Roma",ITA,ITF45,00187,Roma,via Sistina 121 +d004784,Martin & Servera Restauranghandel AB,SWE,SE110,121 23,Johanneshov,"c/o Martin & Servera Aktiebolag, Box 1003" +d004785,NUMERIS COM,ROU,RO114,430061,Baia Mare,"Strada Victoriei, Nr. 146" +d004786,Fabimex Więcek sp.j.,POL,PL911,04-565,Warszawa,ul. Cedrowa 16 +d004787,Geaprodukt trgovsko podjetje na debelo in drobno d.o.o.,SVN,SI,1000,Ljubljana,Dolenjska cesta 242 +d004788,EWIBO GmbH,DEU,DEA34,46399,Bocholt,Adenauerallee 59 +d004789,Atelier Bernard Fournier,FRA,FRI12,33140,Villenave-d'Ornon, +d004790,"Departement Bau, Verkehr und Umwelt Abteilung Tiefbau",CHE,CH0,5001,Aarau,Entfelderstraße 22 +d004791,iThera Medical GmbH,DEU,DE212,81379,München,Zielstattstraße 13 +d004792,Abelmann Vielain Pock Architekten BDA,DEU,DE300,10967,Berlin,Hasenheide 61/II +d004793,"Kostak, komunalno in gradbeno podjetje, d.d.",SVN,SI,8270,Krško,Leskovška cesta 2A +d004794,Groupement AEI — Egis Villes et Transport — Écosphère — agence Presence et Noctiluca,FRA,FR106,93310,Le Pré-Saint-Gervais,8 rue Jean-Baptiste-Clément +d004795,Miltton Oy,FIN,FI,,Helsinki, +d004796,Komunalne TBS Sp. z o.o. w Białymstoku,POL,PL841,15-684,Białystok,"Komisji Edukacji Narodowej 36, lokal 5" +d004797,"Miejskie Przedsiębiorstwo Wodociągów i Kanalizacji w m.st. Warszawie S.A. zarejestrowane w Krajowym Rejestrze Sądowym w Sądzie Rejonowym dla m.st. Warszawy w Warszawie, XII Wydział Gospodarczy Krajowego Rejestru Sądowego pod numerem KRS 0000146138",POL,PL911,02-015,Warszawa,pl. Starynkiewicza 5 +d004798,Suez Consulting/Safege,FRA,FRK23,26000,Valence,Agence Rhône Alpes +d004799,Man TP,FRA,FR,35500,Pocé-les-Bois, +d004800,"Bundesministerium für Wirtschaft und Energie (BMWi), Referat I C 4",DEU,DEA22,53123,Bonn,Villemombler Str. 76 +d004801,Région Île-de-France,FRA,FR1,,Saint-Ouen,2 rue Simone-Veil +d004802,"Autonova, s.r.o.",SVK,SK041,058 01,Poprad,Priemyselný areál Východ 3406 +d004803,SAS arbres plus,FRA,FRE11,59330,Beaufort,ZA des Wazrennes +d004804,"L3P Architekten ETH FH SIA, AG",CHE,CH0,8158,Regensberg,"Unterburg, 33" +d004805,ArGe Bio,DEU,DE239,,Neunburg, +d004806,KPMG Oy Ab,FIN,FI1B,,Helsinki, +d004807,Zètema progetto cultura srl,ITA,ITI43,00156,Roma,via Attilio Benigni 59 +d004808,Carl Zeiss Microscopy Deutschland GmbH,DEU,DE11D,73447,Oberkochen,Carl-Zeiss-Straße 22 +d004809,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d004810,Gesellschaft für digitale Bildung mbH,DEU,DE600,22763,Hamburg,Friesenweg 5g +d004811,"Ambiente SpA con sede in via Bertolotti 7, Torino — P.IVA 01501491219, con ribasso del 30,80 % per un importo di 480 801,60 EUR, oltre IVA",ITA,ITC11,,Torino,via Bertolotti 7 +d004812,Provincie Zuid-Holland,NLD,NL,2596 AW,Den Haag,Zuid-Hollandplein 1 +d004813,VitaVerita AB,SWE,SE110,196 31,Kungsängen,Västra Rydsvägen 138 +d004814,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d004815,Ministerul Apărării – Unitatea Militară 02444 Sibiu,ROU,RO126,550194,Sibiu,Str. Armelor nr. 10 +d004816,Västblekinge Miljö Aktiebolag,SWE,SE221,375 22,Mörrum,Box 56 +d004817,Societatea Națională de Gaze Naturale Romgaz S.A.,ROU,RO126,551129,Mediaș,Șoseaua Sibiului nr. 5 +d004818,La Ligue de l'enseignement,FRA,FRJ15,66000,Perpignan,1 rue Michel Doutres +d004819,Taksi Pia Nieminen,FIN,FI1D3,FI-82110,Heinävaara,Heinävaara LV 5 +d004820,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d004821,Schemmer und Frank PV GmbH,DEU,DEA45,32791,Lage,Daimlerstr. 21 +d004822,SARL pépinière de Beaufort,FRA,FRE11,59330,Beaufort,route Nationale 2 +d004823,"Max-Planck-Gesellschaft zur Förderung der Wissenschaften e. V., Max-Planck-Institut für Plasmaphysik",DEU,DE21H,85748,Garching bei München,Boltzmannstraße 2 +d004824,Conseil départemental de la Charente-Maritime,FRA,FRI32,17076,La Rochelle Cedex 9,"85 boulevard de la République, CS 60003" +d004825,VĮ Lietuvos automobilių kelių direkcija,LTU,LT,LT-03109,Vilnius,J. Basanavičiaus g. 36 +d004826,"Palex Medical, S. A.",ESP,ES51,08174,Sant Cugat del Vallès, +d004827,Avfall Sør AS,NOR,NO092,,Kristiansand S, +d004828,Ayuntamiento de Marbella,ESP,ES617,29601,Marbella,"Plaza de los Naranjos, s/n" +d004829,Reta - Prevozi Marko Krže s.p.,SVN,SI,1310,Ribnica,Žlebič 38 +d004830,BET de Marne,FRA,FR,51100,Reims, +d004831,Konsumentverket,SWE,SE,651 02,Karlstad,Box 48 +d004832,"Residuos de Melilla, S. A.",ESP,ES640,52002,Melilla,"C/ Río Jarama, s/n" +d004833,Palir d.o.o.,HRV,HR,10000,Zagreb,Dane Duića 3 +d004834,"Infrabel SA — Procurement, division I-FBA.51",BEL,BE100,1060,Bruxelles,Place Marcel Broodthaers 2 +d004835,RTI gruppo servizi associati SpA,ITA,ITI43,,Roma, +d004836,Compania Națională de Transporturi Aeriene Române TAROM,ROU,RO322,075150,Otopeni,Calea Bucureștilor nr. 224F +d004837,PGF S.A.,POL,PL,91-342,Łódź,ul. Zbąszyńska 3 +d004838,Silvacultura S.R.L.,ROU,RO125,545500,Sovata,"Str. Minei nr. 4, Sovata, Mureș" +d004839,Ministarstvo zdravstva,HRV,HR,10000,Zagreb,Ksaver 200a +d004840,Stadt Nürnberg – Hochbauamt,DEU,DE254,90402,Nürnberg,Marientorgraben 11 +d004841,Originalis B. V.,NLD,NL,,Amsterdam, +d004842,Väylävirasto,FIN,FI,FI-00521,Helsinki,PL 33 (Opastinsilta 12 A) +d004843,"Futura Soft, s.r.o.",CZE,CZ064,602 00,Brno,Příkop 843/4 +d004844,ESP sécurité,FRA,FR103,78180,Montigny-le-Bretonneux,6 rue Jean-Pierre Timbaud +d004845,Fachhochschule Bielefeld,DEU,DEA41,33619,Bielefeld,Interaktion 1 +d004846,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d004847,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d004848,"Vilex '94. Ipari-, Szolgáltató- és Kereskedelmi Kft.",HUN,HU,4100,Berettyóújfalu,Széchenyi utca 74. +d004849,"Centro Hospitalar Universitário de Lisboa Norte, E. P. E.",PRT,PT170,1649-035,Lisboa,Lisboa +d004850,"UTE Telefónica de España, S. A. U. — Telefónica Móviles España, S. A. U.",ESP,ES30,28013,Madrid,"Gran Vía, 28" +d004851,Fichtner Water & Transportation GmbH,DEU,DE13,79110,Freiburg,Linnéstr. 5 +d004852,adelphi consult GmbH,DEU,DE300,10559,Berlin, +d004853,Antea srl,ITA,ITH56,,Comacchio, +d004854,Județul Botoșani,ROU,RO212,710236,Botoșani,Str. Revoluţiei nr. 1-3 +d004855,Garant Bau GesmbH,AUT,AT130,1020,Wien,Holubstraße 3/5/B1 +d004856,Euromed trgovina in storitve d.o.o.,SVN,SI,1351,Brezovica pri Ljubljani,Podpeška cesta 14 +d004857,Studio Speri società di ingegneria,ITA,ITI43,00196,Roma,Lungotevere delle Navi 19 +d004858,Ayuntamiento de Marbella,ESP,ES617,29601,Marbella,"Plaza de los Naranjos, s/n" +d004859,Croatia osiguranje d.d.,HRV,HR050,10000,Zagreb,Vatroslava Jagića 33 +d004860,Direção-Geral de Reinserção e Serviços Prisionais,PRT,PT,1250-052,Lisboa,"Rua Braamcamp, 90, 5.º piso" +d004861,Unipharma - 1. slovenská lekárnická akciová spoločnosť,SVK,SK022,972 01,Bojnice,Opatovská cesta 4 +d004862,LWL — Bau- und Liegenschaftsbetrieb (LWL-BLB),DEU,DEA33,48145,Münster,Warendorfer Straße. 24 +d004863,Sogin SpA,ITA,ITI43,00185,Roma,via Marsala 51/c +d004864,Eco-Equip SAM,ESP,ES511,08223,Terrassa,"C/ Esla, 34" +d004865,Training Designers,ROU,RO321,021792,București,"Str. Cislău nr. 1, sector 2" +d004866,"Staatsbetrieb Sächsisches Immobilien- und Baumanagement, Zentrale, SSC VVM, Außenstelle Dresden 1, Zentrale Vergabestelle",DEU,DED2,01099,Dresden,Königsbrücker Str. 80 +d004867,"Vetges Tu i Mediterrània, S. L. P.",ESP,ES,46003,Valencia,"C/ Aparisi i Guijarro, 5-3" +d004868,Bluerock International d.o.o.,HRV,HR0,10000,Zagreb,Kaptol ulica 18 +d004869,Autoridad Portuaria de Vigo,ESP,ES114,36201,Vigo,"Plaza de la Estrella, 1" +d004870,Centron Slovakia spol. s r.o.,SVK,SK010,841 03,Bratislava,Podháj 107 +d004871,Organizația Utilizatorilor de Apă pentru Irigații (OUAI) „Perișoru – SPP5”,ROU,RO312,917195,Perișoru,Siloz Perișoru nr. 1 +d004872,Groupement Citemetrie SAS (mandataire) + La Lestoux & Associés,FRA,FR101,75014,Paris,23 rue de la Tombe Issoire +d004873,Automated Lab Solutions GM,DEU,DE,07745,Jena,Otto-Eppenstein-Str. 30 +d004874,"Kastor - Medical Dental podjetje za veleprodajo, zastopanje, inženiring in zunanjo trgovino, Ljubljana, Vošnjakova 6",SVN,SI,1000,Ljubljana,Vošnjakova ulica 6 +d004875,"Laboratório de Medicina Veterinária (LMV), Lda.",PRT,PT,2005-110,Almoster,"Lugar de Sorrateia, Atalaia" +d004876,OCLC B.V.,NLD,NL423,,Leiden, +d004877,Gold Medical Kft.,HUN,HU110,1221,Budapest,Hasadék utca 22. B. ép. +d004878,Asunto Oy Ruokolahden Elvinkulma,FIN,FI,,Ruokolahti, +d004879,Ing. Slavka Kylarová,CZE,CZ010,141 00,Praha 10,Podle náhonu 3224/67 +d004880,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d004881,"Habitat Servicios Medioambientales, S. L.",ESP,ES618,,Castilleja de la Cuesta (Sevilla), +d004882,"Vantaan kaupunki / Maankäytön, rakentamisen ja ympäristön toimiala",FIN,FI1B,FI-01300,Vantaa,Asematie 7 +d004883,Ing. Pietro Luigi Caputo,ITA,ITF35,83026,Postiglione,via Acquara 2 +d004884,Stadt Kehl – Zentrale Vergabestelle,DEU,DE134,77694,Kehl,Postanschrift: Rathausplatz 1 / Dienstgebäude: Rathausplatz 3 +d004885,"Centre de Jardineria Sils, S. A.",ESP,ES512,17410,Sils, +d004886,Obec Bohdašín,CZE,CZ052,518 01,Bohdašín,Bohdašín 21 +d004887,Medgal sp. z o.o.,POL,PL84,16-001,Księżyno,ul. Niewodnicka 26a +d004888,Euromaster France SNC,FRA,FR1,,Montbonnot, +d004889,Groupement local de coopération transfrontalière des transports publics,FRA,FRK28,74160,Archamps,bâtiment le Salève — 155 rue Ada Byron +d004890,Szpital Kliniczny im. Heliodora Święcickiego Uniwersytetu Medycznego im. Karola Marcinkowskiego w Poznaniu,POL,PL415,60-355,Poznań,ul. Przybyszewskiego 49 +d004891,Abacus Medicine A/S,DNK,DK,,Kopenhagen, +d004892,ANDROMI COM,ROU,RO111,410222,Oradea,"Strada CALEA APATEULUI, Nr. 291/L" +d004893,agrodalm,HRV,HR,10040,Zagreb,Blizno 13 +d004894,Ville de Vannes,FRA,FRH04,56019,Vannes,"place Maurice Marchais, BP 509" +d004895,Stedyan Com S.R.L.,ROU,RO221,6100,Brăila,Str. Școlilor nr. 39 +d004896,"Carestream Health Spain, S. A.",ESP,ES30,28224,Pozuelo de Alarcón,"Vía de las Dos Castillas, 33, edificio 6, 3.ª planta, ático" +d004897,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d004898,Järfällahus AB,SWE,SE110,,Järfälla, +d004899,Romferex Import Export S.R.L.,ROU,RO412,,Bălești,Str. Gavănești nr. - +d004900,Ministerstvo spravedlnosti České republiky,CZE,CZ010,128 10,Praha 2,Vyšehradská 16 +d004901,Consorzio stabile con.service s.c.p.a.,ITA,ITH55,,Bologna,via Alessandrini 13 +d004902,costituendo R.T.I. KPMG advisory SpA — INFO.C.E.R. srl,ITA,ITI4,,Roma, +d004903,Axon Lab trgovina in medicinske storitve d.o.o.,SVN,SI,2310,Slovenska Bistrica,Rimska ulica 4 +d004904,ARI cotraitant,FRA,FRI34,86102,Châtellerault,"11 rue Bernard Palissy, BP 70224" +d004905,Zini Elio srl,ITA,ITH55,,Bologna, +d004906,Občina Ribnica,SVN,SI,1310,Ribnica,Gorenjska cesta 3 +d004907,Grupa Azoty Zakłady Azotowe Kędzierzyn S.A.,POL,PL52,47-220,Kędzierzyn-Koźle,ul. Mostowa 30A +d004908,Garage Largentière autos,FRA,FRK22,07110,Largentière,51 impasse du Ginestet +d004909,Veitur ohf.,ISL,IS001,,Reykjavik, +d004910,Zweckverband für weiterführende Schulen im westlichen Teil des Landkreises Starnberg,DEU,DE21L,82205,Gilching,Talhofstr. 7 +d004911,Serviciul de Ambulanță Județean Iași,ROU,RO213,700173,Iași,Str. Primăverii nr. 74 +d004912,Klinički bolnički centar Sestre milosrdnice,HRV,HR,10000,Zagreb,Vinogradska cesta 29 +d004913,"Kemis kemični izdelki, predelava in odstranjevanje odpadkov d.o.o.",SVN,SI,1360,Vrhnika,Pot na Tojnice 42 +d004914,Gemeinnützige Salzburger Landeskliniken Betriebsgesellschaft mbH,AUT,AT,5020,Salzburg,Müllner Hauptstr. 48 +d004915,Tamási Város Önkormányzata,HUN,HU233,7090,Tamási,Szabadság utca 46–48. +d004916,Tornion kaupunki,FIN,FI,FI-95400,Tornio,Suensaarenkatu 4 +d004917,Impel Tech Solutions Sp. z o.o. Sp.k.,POL,PL911,04-242,Warszawa,e.sitarek@impel.pl +d004918,IREN SpA (in nome e per conto di Ireti SpA e di altre società del gruppo),ITA,ITH53,42123,Reggio Emilia,via Nubi di Magellano 30 +d004919,Associated Equipment Ltd,MLT,MT,SGN 2010,San Gwann [San Ġwann],11 Lourdes Square +d004920,Enel Italia SpA in nome e per conto di e-distribuzione SpA,ITA,ITI43,00198,Roma (RM),viale Regina Margherita 125 +d004921,Aarhus Kommune,DNK,DK042,8000,Aarhus C,Rådhuspladsen 2 +d004922,Dirección del Instituto de Astrofísica de Canarias,ESP,ES70,38200,La Laguna,Vía Láctea +d004923,Péterfy Sándor Utcai Kórház-Rendelőintézet és Baleseti Központ,HUN,HU110,1076,Budapest,Péterfy Sándor utca 8–20. +d004924,Nisa Nurmohamed Advie,NLD,NL,2013 AS,Haarlem,Kinderhuissingel 28 +d004925,"Bayer, farmacevtska družba d.o.o.",SVN,SI,1000,Ljubljana,Bravničarjeva ulica 13 +d004926,WEERWERK vzw,BEL,BE,9000,Gent,Gaardeniersweg 80 +d004927,Autospurghi CM srl,ITA,ITI32,,Jesi, +d004928,Integrata Cegos GmbH,DEU,DE111,70567,Stuttgart,Zettachring 4 +d004929,Green Petrol Sp. z o.o.,POL,PL911,,Warszawa, +d004930,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d004931,winston & Strawn LLP,GBR,UKI,000000,Londres,"1 Ropemaker street, Ec2y 9aw" +d004932,Siemens Financial Services,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d004933,WIRO Wohnen in Rostock Wohnungsgesellschaft mbH,DEU,DE803,18055,Rostock,Lange Str. 38 +d004934,J E Eriksson Mark & Anläggningsteknik AB,SWE,SE110,186 24,Vallentuna,Box 207 +d004935,Pfister GmbH & Co. Betonwerk Seßlach KG,DEU,DE247,,96145 Seßlach, +d004936,SAS Kabelis,FRA,FR,29610,Plouigneau, +d004937,Jefatura de Asuntos Económicos del Estado Mayor de la Defensa,ESP,ES300,28006,Madrid,"C/ Vitruvio, 1" +d004938,"Probo, trgovinska družba za promet z medicinskimi pripomočki, d.o.o.",SVN,SI,3211,Škofja vas,Prekorje 48 +d004939,"Medtronic, trgovina z medicinsko tehnologijo in opremo d.o.o.",SVN,SI,1000,Ljubljana,Ameriška ulica 8 +d004940,Intendente de Ferrol,ESP,ES111,15490,Ferrol (A Coruña),"C/ Irmandiños, s/n, Arsenal Militar" +d004941,University of Jyväskylä,FIN,FI193,40014,Jyväskylän yliopisto,Seminaarinkatu 15 +d004942,"Sociedad Pública de Gestión y Promoción Turística y Cultural del Principado de Asturias, S. A. U.",ESP,ES120,33203,Gijón,"C/ Luis Moya Blanco, 261" +d004943,Schroers GmbH,DEU,DEA14,47475,Kamp-Lintfort,Wiesenbruchstr. 46 +d004944,Syndicat Trivalis,FRA,FRG05,85015,La Roche-sur-Yon,"31 rue de l'Atlantique, CS 30605" +d004945,Teatrul Național „Radu Stanca” – Sibiu,ROU,RO126,550245,Sibiu,Str. Corneliu Coposu nr. 2 +d004946,Tornion Palveluasunnot Oy,FIN,FI,FI-95401,Tornio, +d004947,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d004948,Gemeente Grimbergen,BEL,BE241,1850,Grimbergen,Prinsenstraat 3 +d004949,Hera SpA,ITA,ITH55,40127,Bologna,viale Carlo Berti Pichat 2/4 +d004950,Mark Medical trgovina in storitve d.o.o.,SVN,SI,6210,Sežana,Partizanska cesta 109 +d004951,Heinrich Schmid GmbH & Co.KG,DEU,DED5,04275,Leipzig,Kurt-Eisner-Straße 1 +d004952,Albert Ziegler GmbH,DEU,DE11C,,Giengen, +d004953,Markt Berchtesgaden,DEU,DE215,83471,Berchtesgaden,Rathausplatz 1 +d004954,NIF Nemzeti Infrastruktúra Fejlesztő zártkörűen működő Részvénytársaság,HUN,HU,1134,Budapest,Váci út 45. +d004955,Accord Healthcare S.L.U. vertreten durch Accord Healthcare GmbH,ESP,ES,,Barcelona, +d004956,UAB „MedGo“,LTU,LT,LT-08307,Vilnius,Maumedžių g. 25-6 +d004957,Agefiph,FRA,FR105,92226,Bagneux,192 avenue Aristide Briand +d004958,Hrvatske šume d.o.o.,HRV,HR026,10000,Zagreb,Ulica kneza Branimira 1 +d004959,Lacroix City,FRA,FRG01,44801,Saint-Herblain, +d004960,FOCUS TRADING '94 S.R.L.,ROU,RO321,011657,Bucuresti,"Strada Tudor Stefan, Nr. 10, Sector: 1" +d004961,SUTURA Képviseleti és Kereskedelmi Korlátolt Felelősségű Társaság,HUN,HU,1097,Budapest,Gubacsi út 47. +d004962,MESTNA OBČINA LJUBLJANA,SVN,SI,1000,Ljubljana,Mestni trg 1 +d004963,The ICON Group Ltd,IRL,IE,Ranelagh,Dublin,8 St Anne's Terrace +d004964,Groupement atelier du trait/Odetec/ID Bâtiment,FRA,FRI34,86700,Couhé,3 rue du Commerce +d004965,"Javno podjetje Ljubljanska parkirišča in tržnice, d.o.o.",SVN,SI,1000,Ljubljana,Kopitarjeva ulica 2 +d004966,Professionshøjskolen Absalon,DNK,DK022,4180,Sorø,Slagelsevej 7 +d004967,"Finson - prevozi potnikov in blaga, posredništvo pri prodaji izdelkov in kompenzacije Sonja Rigler s.p.",SVN,SI,1310,Ribnica,Cesta IX 5 +d004968,"SALUS, Veletrgovina, družba za promet s farmacevtskimi, medicinskimi in drugimi proizvodi, d.o.o.",SVN,SI,1000,Ljubljana,Litostrojska cesta 46A +d004969,BIMP groupe LDLC,FRA,FRK26,69760,Limonest,2 rue des Érables +d004970,Nyír-Mix-Trade Korlátolt Felelősségű Társaság,HUN,HUZZZ,4461,Nyírtelek,Diófa utca 2. +d004971,Université de Nantes,FRA,FRG01,44035,Nantes cedex 1,1 quai de Tourville — BP 13522 +d004972,Emil Nils Peter Lindberg,SWE,SE212,360 30,Lammhult,Äpplaryd 3 +d004973,Métropole européenne de Lille,FRA,FRE11,59034,Lille,1 rue du Ballon +d004974,eSell Bayern GmbH,DEU,DE21F,,Holzkirchen, +d004975,MLM Medical S.R.L.,ROU,RO321,040214,București,"Str. Şerban Vodă nr. 180a, sector 4" +d004976,ARI Cotraitant,FRA,FRI34,86102,Châtellerault,"11 rue Bernard Palissy, BP 70224" +d004977,ÅF-Infrastructure AB,SWE,SE110,169 99,Stockholm, +d004978,"Quilaban — Química Laboratorial Analítica, S. A.",PRT,PT170,2710-693,Sintra,"Beloura Office Park, edifício III, Quinta da Beloura" +d004979,Hlavní město Praha,CZE,CZ010,110 00,Praha 1 - Staré Město,Mariánské náměstí 2/2 +d004980,BTL ROMANIA APARATURA MEDICALA S.R.L.,ROU,RO321,040184,Bucuresti,"Strada CPT MIRCEA VASILESCU, Nr. 12-14, Sector: 4" +d004981,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d004982,Euromaster France SNC,FRA,FR1,,Montbonnot, +d004983,Universität Siegen,DEU,DEA5A,57076,Siegen,Adolf-Reichwein-Str. 2 a +d004984,Javno podjetje Vodovod Kanalizacija Snaga d.o.o.,SVN,SI,1000,Ljubljana,Vodovodna cesta 90 +d004985,Suntel Czech s.r.o.,CZE,CZ07,760 01,Zlín,Březnická 5602 +d004986,Rambøll Danmark A/S,DNK,DK042,8200,Aarhus N,Olof Palmes Allé 20-22 +d004987,"ha-vel internet, s.r.o.",CZE,CZ,712 00,Ostrava,Olešní 587/11a +d004988,Comune di Pieve Emanuele (MI),ITA,ITC4C,,Pieve Emanuele (MI), +d004989,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d004990,Brekke & Strand Akustik AB,SWE,SE232,405 23,Göteborg,Box 1084 +d004991,Eesti Töötukassa,EST,EE,11412,Tallinn,Lasnamäe tn 2 +d004992,Maandag Interim Professionals bv,NLD,NL,,Rotterdam, +d004993,Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos,LTU,LT,LT-50161,Kaunas,Eivenių g. 2 +d004994,Sweco Infra & Rail Oy,FIN,FI,FI-00240,Helsinki,Ilmalanportti 2 +d004995,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschiz,"Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" +d004996,"Mape Asesores, S. A.",ESP,ES114,36158,Pontevedra,"Rua das Mamoas, parcela 69b" +d004997,Otto Hermann GmbH,DEU,DE212,82008 Unterhaching,Hans-Sachs-Str. 1, +d004998,Diamedix Impex,ROU,RO321,012902,București,"Str. Fabrica de Glucoză nr. 15A, sector 2" +d004999,Medinova zastopstva in trgovina d.o.o.,SVN,SI,1000,Ljubljana,Ukmarjeva ulica 6 +d005000,Regie de quartier habiter Bacalan,FRA,FRI12,33300,Bordeaux, +d005001,Norton Rose Fulbright LLP,GBR,UKI,000000,Londres,3 More London Riverside Se1 2aq +d005002,"UTE Otipsa Consultores, S. L. — Viasur, Prevención e Ingeniería, S. A.",ESP,ES,04004,Almería,Rambla Obispo Orberá +d005003,Newcastle University,GBR,UK,NE1 7RU,Newcastle upon Tyne,"Newcastle University, King's Gate" +d005004,Bayerische Staatsforsten AöR,DEU,DE232,93053,Regensburg,Tillystraße 2 +d005005,MOE A/S,DNK,DK,2860,Søborg,Buddingevej 272 +d005006,Bundesministerium für Wirtschaft und Energie,DEU,DE300,10115,Berlin,Scharnhorststraße 34-37 +d005007,Rosenbauer Deutschland GmbH,DEU,DE40H,14943,Luckenwalde,Rudolf-Breitscheid-Straße 79 +d005008,CBF Balducci SpA,ITA,ITI33,,Montecassiano, +d005009,Kewatec Aluboat Oy Ab,FIN,FI1,,Kokkola, +d005010,Euromed trgovina in storitve d.o.o.,SVN,SI,1351,Brezovica pri Ljubljani,Podpeška cesta 14 +d005011,Mikroregion Velkomeziříčsko–Bítešsko,CZE,CZ063,594 01,Velké Meziříčí,Radnická 29/1 +d005012,SCC,FRA,FRD,92744,Nanterre,96 rue des 3 Fontanots +d005013,Steril România,ROU,RO321,041831,Bucureşti,"Str. Metalurgiei nr. 3-5, sector 4" +d005014,ASBL Pôle hospitalier Jolimont,BEL,BE323,7100,La Louvière,Rue Ferrer 159 +d005015,Szpital Powiatowy w Zawierciu,POL,PL22B,42-400,Zawiercie,ul. Miodowa 14 +d005016,"PETROL, Slovenska energetska družba, d.d., Ljubljana",SVN,SI,1000,Ljubljana,Dunajska cesta 50 +d005017,"Land Berlin, Sondervermögen Immobilien des Landes Berlin (SILB), vertreten durch die Berliner Immobilienmanagement GmbH",DEU,DE300,10178,Berlin,Alexanderstraße 3 +d005018,Alb Fils Kliniken GmbH,DEU,DE114,73035,Göppingen,Eichertstraße 3 +d005019,"LIPIS, Proizvodnja in trgovina d.o.o.",SVN,SI,1000,Ljubljana,Cesta v Šmartno 35 +d005020,Smabtp,FRA,FRH,69396,Lyon,10 boulevard vivier Merle +d005021,Gislaveds kommun,SWE,SE,332 80,Gislaved,Mari Backstig +d005022,Bau- und Liegenschaftsbetrieb NRW Bielefeld,DEU,DEA41,33602,Bielefeld,August- Bebel-Straße 91 +d005023,Sihtasutus Tallinna Hambapolikliinik,EST,EE,10142,Tallinn,Toompuiestee 4b +d005024,Verrier Majuscule,FRA,FRG05,85504,Les Herbiers,61 avenue Gerorges Clemenceau +d005025,PalliDONIS gGmbH,DEU,DE224,94469,Deggendorf,Otto-Denk-Str. 25 +d005026,OneCo Elektro AS,NOR,NO0A2,0667,Oslo,Brynsveien 12 +d005027,Stena Recycling AB,SWE,SE,691 42,Karlskoga,Botorpsvägen 5 +d005028,Roche Diagnostics Deutschland GmbH,DEU,DE126,68305,Mannheim,Sandhofer Strasse 11 +d005029,"Solaris Slovakia, s.r.o.",SVK,SK,040 11,Košice - Juh,Rozvojová 2 +d005030,Kristiansand kommune,NOR,NO,4685,Nodeland,Postboks 4 +d005031,Kommunales Vergabezentrum Kreis Groß-Gerau für Kreis Groß-Gerau,DEU,DE717,64521,Groß-Gerau,Wilhelm-Seipp-Str. 4 +d005032,Leica Microsystèmes SAS,FRA,FR10,,Nanterre Cedex, +d005033,SJM Avocats,FRA,FRG01,44000,Nantes,3 place Graslin +d005034,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d005035,Relico Oy,FIN,FI1C1,,Turku, +d005036,Dico și Țigănaș – Birou de proiectare,ROU,RO113,400609,Cluj-Napoca,Calea Dorobanților nr. 98-100 +d005037,Hirm & Partner ZT GmbH,AUT,AT21,9020,Klagenfurt,St. Ruprechter Straße 19 +d005038,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d005039,Skandinaviska Enskilda Banken AB,SWE,SE,106 40,Stockholm,Kungsträdgårdsgatan 8 +d005040,"Dvojica proizvodnja, storitve, trgovina, d.o.o.",SVN,SI,1000,Ljubljana,Litostrojska cesta 42D +d005041,UAB „Limeta“,LTU,LT,,Vilnius, +d005042,France Environnement,FRA,FRE1,59710,Avelin,ZA Les Marlières +d005043,Turto valdymo ir ūkio departamentas prie Lietuvos Respublikos vidaus reikalų ministerijos,LTU,LT,LT-01510,Vilnius,Šventaragio g. 2 +d005044,Schaffitzel Holzindustrie GmbH & Co. KG,DEU,DE11A,74523,Schwäbisch Hall,Herdweg 23-24 +d005045,Roche farmacevtska družba d.o.o.,SVN,SI,1000,Ljubljana,Stegne 13G +d005046,Facts & Feelings BVBA,BEL,BE,2940,Antwerpen,Rijnkaai 23-24 +d005047,Județul Tulcea,ROU,RO225,820033,Tulcea,Str. Păcii nr. 20 +d005048,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d005049,"Mölnlycke Healthcare, S. L.",ESP,ES300,,Madrid, +d005050,Rectorado de la Universidad de Salamanca,ESP,ES415,37008,Salamanca,"Patio de Escuelas, 1" +d005051,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d005052,"Zdravotnická záchranná služba Zlínského kraje, příspěvková organizace",CZE,CZ072,760 01,Zlín,Peroutkovo nábřeží 434 +d005053,Euromedia,FRA,FRJ23,,Montastruc-la-Conseillère, +d005054,"Davinci Tecnologías de la Información, S. L.",ESP,ES511,08290,Cerdanyola del Vallés, +d005055,Grgić obrt za poljodjelstvo i usluge poljoprivrednim i šumskim strojevima vl.Josip Grgić,HRV,HR,32245,Nijemci,Podgrađe Braće Radića 15 +d005056,Bundesministerium für Wirtschaft und Energie,DEU,DE300,10115,Berlin,Scharnhorststraße 34-37 +d005057,Osnovna šola Radlje ob Dravi,SVN,SI,2360,Radlje ob Dravi,Koroška cesta 17 +d005058,PLG Paris Île-de-France,FRA,FR103,95140,Garges-lès-Gonesse,29 avenue des Morillons +d005059,Invitalia,ITA,ITI43,,Roma,via Calabria 46 +d005060,Eurovia Alsace Lorraine,FRA,FRF33,57190,Florange,2 route de Metz +d005061,Medika d.d.,HRV,HR050,10000,Zagreb,Capraška 1 +d005062,Schreibwaren Wegmann,DEU,DE229,94227,Zwiesel, +d005063,"Finson - prevozi potnikov in blaga, posredništvo pri prodaji izdelkov in kompenzacije Sonja Rigler s.p.",SVN,SI,1310,Ribnica,Cesta IX 5 +d005064,"Elinkeino-, liikenne- ja ympäristökeskus",FIN,FI1D,FI-90100,Oulu,Veteraanikatu 1 +d005065,Jätehuolto t.askonen,FIN,FI196,,Eura, +d005066,FastWeb SpA,ITA,IT,,Milano (MI), +d005067,Ministarstvo unutarnjih poslova,HRV,HR,10000,Zagreb,Ilica 335 +d005068,G3 Worldwide Mail (Germany) GmbH,DEU,DEA1B,46446,Emmerich, +d005069,"Moravostav Brno, a.s. stavební společnost",CZE,CZ064,614 00,Brno,Maříkova 1899/1 +d005070,SIP Omnium Façades,FRA,FRL04,13011,Marseille,117 traverse de la Montre +d005071,Pfizer,ITA,ITI43,,Roma, +d005072,Glass Ingenieurbau Leipzig GmbH,DEU,DED52,04416,Markkleeberg,Südring 16 +d005073,Molnlyclke healthcare,FRA,FRL04,13471,Marseille Cedex 02,europrogramme 40 bouvelard de Dunkerque — CS 41221 +d005074,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d005075,Westrop Primary and Nursery School,GBR,UKK14,SN6 7DN,Swindon,"Newburgh Place, Highworth" +d005076,Flexeurope AB,SWE,SE232,852 29,Sundsvall,Stuvarvägen 7 +d005077,Domeni d.o.o.,HRV,HR031,51211,Matulji,Frana Supila 11 +d005078,Groupement Artelia/MAP/Antea group,FRA,FRL04,13322,Marseille,18 rue Elie Pelas +d005079,Pharma,ROU,RO213,700552,Iaşi,Str. Bucium nr. 73E +d005080,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Str. 8 +d005081,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d005082,Santa Casa da Misericórdia de Lisboa,PRT,PT17,1200-470,Lisboa,Largo Trindade Coelho +d005083,"Prospectiva — Projetos, Serviços, Estudos, S. A.",PRT,PT,1500-411,Lisboa,Lisboa +d005084,"PETROL, Slovenska energetska družba, d.d., Ljubljana",SVN,SI,1000,Ljubljana,Dunajska cesta 50 +d005085,Sodeco,FRA,FRI23,87000,Limoges,6-8 rue Frédric Le Play +d005086,Česká zemědělská univerzita v Praze,CZE,CZ01,165 00,Praha–Suchdol,Kamýcká 129 +d005087,Alcaldía del Ayuntamiento de Llíria,ESP,ES523,46160,Llíria,"Plaza Mayor, 1" +d005088,CBXS,FRA,FRK26,69009,Lyon,25 rue Saint-Simon +d005089,Cloitre Imprimeurs,FRA,FRH02,29800,Saint-Thonan, +d005090,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d005091,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d005092,ha-vel internet s.r.o.,CZE,CZ,712 00,Ostrava,Olešní 587/11a +d005093,B. Braun Medical,ROU,RO424,,Sânandrei,Str. Bernd Braun nr. 1 +d005094,Komenda Główna Policji,POL,PL,02-642,Warszawa,ul. Puławska 148/150 +d005095,Xenocs SAS,FRA,FRK24,,Grenoble, +d005096,Szpital Powiatowy w Pyrzycach,POL,PL427,74-200,Pyrzyce,ul. Jana Pawła II 2 +d005097,Lloyd’s Insurance Company S.A.,ITA,ITC4C,,Milano, +d005098,Halmstads kommun,SWE,SE231,301 05,Halmstad,Box 153 +d005099,"Państwowe Gospodarstwo Leśne Lasy Państwowe, Nadleśnictwo Kaczory",POL,PL411,64-810,Kaczory,ul. Kościelna 17 +d005100,Opća bolnica i bolnica branitelja Domovinskog rata Ogulin,HRV,HR027,47300,Ogulin,Bolnička ulica 38 +d005101,Société du Grand Paris,FRA,FR106,93212,La Plaine-Saint-Denis,"Immeuble Moods, 2 mail de la Petite Espagne" +d005102,Pohjois-Karjalan hankintatoimi,FIN,FI1D3,FI-80110,Joensuu,Linnunlahdentie 2 +d005103,Rosenbauer Deutschland GmbH,DEU,DE40H,14943,Luckenwalde,Rudolf-Breitscheid-Str. 79 +d005104,Stadt Boppard am Rhein,DEU,DEB1D,56154,Boppard,Mainzer Straße 46 +d005105,"Javno podjetje Ljubljanski potniški promet, d.o.o.",SVN,SI,1000,Ljubljana,Celovška cesta 160 +d005106,Easy servizi srl,ITA,ITF33,,Napoli,via Calata San Marco 4 +d005107,Farmexim S.A.,ROU,RO321,011934,București,Str. Pictor Daniel Constantin Rosenthal nr. 14 +d005108,Stredná odborná škola informačných technológií,SVK,SK032,975 90,Banská Bystrica,Tajovského 30 +d005109,Landratsamt Coburg,DEU,DE247,96450,Coburg,Lauterer Straße 60 +d005110,iBL Ingenieurbüro Leirich,DEU,DE804,,Schwerin, +d005111,ABB bv,NLD,NL,3068 AX,Rotterdam,George Hintzenweg 81 +d005112,Aquinno Service Szolgáltató és Kereskedelmi Korlátolt Felelősségű Társaság,HUN,HU231,7627,Pécs,Rigóder út 2/A. +d005113,Defence Forces Ireland,IRL,IE,Blackhorse Ave,Dublin 7,McKee Barracks +d005114,Cooperativa CrescereInsieme scs impresa sociale,ITA,ITC18,,Acqui Terme (AL), +d005115,RTR,FRA,FRF23,51100,Reims,25 ter rue du Jard +d005116,CONNEX Werbeagentur GmbH,DEU,DE300,,Berlin, +d005117,Občina Laško,SVN,SI,3270,Laško,Mestna ulica 2 +d005118,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d005119,OÜ Inseneribüroo Steiger,EST,EE,11216,Tallinn,Männiku tee 104 +d005120,Land Tirol,AUT,AT33,6020,Innsbruck,Herrengasse 1-3 +d005121,Procurator AB,SWE,SE,200 39,Malmö,Box 9504 +d005122,UAB „Ignitis“,LTU,LT,,Vilnius, +d005123,Boston Scientific Nordic AB,SWE,SE224,250 24,Helsingborg,Box 22220 +d005124,Eurovia Bourgogne,FRA,FRC11,21600,Longvic, +d005125,Baxter,FRA,FR,78280,Guyancourt,4 bis rue de la Redoute +d005126,Villeret Laurent,FRA,FR101,75020,Paris,22 rue Bisson +d005127,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 — Haus 6 +d005128,Stichting Pantar Amsterdam,NLD,NL,1111 PT,Diemen,Kriekenoord 3 +d005129,Moholy-Nagy Művészeti Egyetem,HUN,HU,1121,Budapest,Zugligeti út 9–25. +d005130,Graitex Innovation GmbH,DEU,DE9,30453,Hannover, +d005131,Lom Praha s.p.,CZE,CZ010,108 00,Praha 10,Tiskařská 270/8 +d005132,"Cardio Medical družba za trgovino in storitve, d.o.o.",SVN,SI,1236,Trzin,Špruha 1 +d005133,Medika d.d.,HRV,HR050,10000,Zagreb,Capraška 1 +d005134,Planungsgruppe M+M AG,DEU,DE112,71034,Böblingen,Hanns-Klemm-Straße 1 +d005135,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d005136,ENAIRE,ESP,ES300,28022,Madrid,"Avenida de Aragón, 330" +d005137,Ferring Arzneimittel GmbH,DEU,DE,,Kiel, +d005138,Panier des touches Olivier,FRA,FRI12,33000,Bordeaux,25 rue Raze +d005139,Commune de Le Mesnil-Amelot,FRA,FR,77990,Le Mesnil-Amelot,"2, rue du chapeau" +d005140,Serviciul de Telecomunicații Speciale,ROU,RO321,060044,Bucureşti,Str. Independenței nr. 323A +d005141,Phywe Systeme GmbH & Co. KG,DEU,DE91C,37079,Göttingen,Robert-Bosch-Breite 10 +d005142,Bil-Beställning AB,SWE,SE232,422 46,Hisings Backa,Exportgatan 73 +d005143,Allavoine Parc et Jardins,FRA,FR10,91570,Bièvres,4 route de Favreuse +d005144,Getelec Guyane,FRA,FRY30,97337,Cayenne,"ZI Collery, BP 779" +d005145,Bright Finland Oy,FIN,FI1B1,,Vantaa, +d005146,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 — Haus 6 +d005147,Watson Farley & Williams,FRA,FR101,75116,Paris,28 avenue Victor-Hugo +d005148,ARA srl,ITA,ITH20,,Parma, +d005149,"Landeshauptstadt Düsseldorf, Der Oberbürgermeister, Rechtsamt",DEU,DEA11,40227,Düsseldorf,Willi-Becker-Allee 10 +d005150,"Pinus, S. A.",ESP,ES616,,Jaén, +d005151,"Limpiezas Crespo, S. A.",ESP,ES30,28045,Madrid,"C/ General Palanca, 34" +d005152,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d005153,SAE POPB,FRA,FR101,75012,Paris,www.accorarena.com +d005154,HPA-SDVA Peugeot Orange,FRA,FRL06,84100,Orange,15 rue d'Allemagne — ZAC du Coudoulet +d005155,Autohaus Saurwein GmbH & Co.KG,DEU,DEA56,58332,Schwelm,Berliner Str.59 +d005156,AB Sundplast,SWE,SE,250 15,Helsinborg ELSINGBORG,Box 15084 +d005157,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d005158,Airgen SAS,FRA,FRJ23,31670,Labège,815 la Pyrénéenne +d005159,Région Normandie,FRA,FRD,14035,Caen Cedex 01,"place Reine Mathilde, CS 50523" +d005160,SpektraVision s.r.o.,CZE,CZ020,251 01,Nupaky,Kruhová 128 +d005161,Gemeindeverband Bezirkskrankenhaus Schwaz,AUT,AT,6130,Schwaz,Swarovskistrasse 1-3 +d005162,Aktsiaselts Kaupmees & Ko,EST,EE,10621,Tallinn,Mustamäe tee 46 +d005163,Direção-Geral de Alimentação e Veterinária,PRT,PT,1700-093,Lisboa,"Campo Grande, 50" +d005164,Couleurs de Tollens,FRA,FR105,92583,Clichy,71 boulevard du Général Leclerc +d005165,B. Mikkelsen AS,NOR,NO0A2,5750,Odda,Smelteverket 118 +d005166,Studio Majone ingegneri associati,ITA,ITC4C,,Milano, +d005167,Sintec,FRA,FRK26,69007,Lyon,2 allée de Lodz +d005168,"Inetum España, S. A., sucursal em Portugal",PRT,PT,1069-413,Lisboa,"Avenida António Augusto Aguiar, 31" +d005169,"Dopravný podnik Bratislava, akciová spoločnosť",SVK,SK,814 52,Bratislava-mestská časť Staré Mesto,Olejkárska 1 +d005170,Amag Reti Gas SpA,ITA,ITC18,,Alessandria,via Damiano Chiesa 18 +d005171,Ayuntamiento de Marbella,ESP,ES617,29601,Marbella,"Plaza de los Naranjos, s/n" +d005172,Compania Națională Administrația Canalelor Navigabile SA Constanța,ROU,RO223,907015,Agigea,Str. Ecluzei nr. 1 +d005173,Landkreis Cloppenburg,DEU,DE948,49661,Cloppenburg,Eschstraße 29 +d005174,Euromat,FRA,FRM,20250,Corte,RT50 — zone Artisanale +d005175,INTER CONECTER S.R.L.,ROU,RO424,300548,Timisoara,"Strada Miu Lerca Constantin, Nr. 7/c" +d005176,Scan Water,NOR,NO,1415,Oppegård,Haukeliveien 48 +d005177,Kedrion,ITA,ITI12,,Lucca, +d005178,Občina Žalec,SVN,SI,3310,Žalec,Ulica Savinjske čete 5 +d005179,Lamos,FRA,FR1,,Noisy-le-Grand, +d005180,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d005181,Société de livraison ouvrages olympiques,FRA,FR101,75009,Paris,18 rue de Londres +d005182,"BIJOL zastopanje, proizvodnja d.o.o.",SVN,SI,2367,Vuzenica,Livarska cesta 17 +d005183,Direcția Generală Regională a Finanțelor Publice Brașov,ROU,RO122,500090,Brașov,Str. Mihail Kogălniceanu nr. 7 +d005184,Rompetrol Well Services,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2BIS +d005185,Sihtasutus Pärnu Haigla,EST,EE,80010,Pärnu linn,Ristiku tn 1 +d005186,Setec ALS,FRA,FRK26,69003,Lyon,"Immeuble le Crystallin, 191/193 cours Lafayette" +d005187,Tohmajärven kunta,FIN,FI1D3,,Tohmajärvi, +d005188,"Salus, Veletrgovina, družba za promet s farmacevtskimi, medicinskimi in drugimi proizvodi, d.o.o.",SVN,SI,1000,Ljubljana,Litostrojska cesta 46A +d005189,ELVA ProcessAutomation AB,SWE,SE123,591 05,Motala,Box 5048 +d005190,Telge Inköp AB,SWE,SE110,151 27,Södertälje,Box 633 +d005191,Agropartner land u forstechnik GmbH,DEU,DE80J,17192,Schloen-Dratow,Tiergartenweg 3 +d005192,Cleverchefs Ltd,GBR,UKL22,,Cardiff,CF24 5HJ +d005193,Česká republika – Úřad práce ČR,CZE,CZ01,,Praha 7, +d005194,S.A.B. Slovakia s. r. o.,SVK,SK01,851 07,Bratislava-Petržalka,Betliarska 3809/22 +d005195,Metallbau Konrad GmbH,DEU,DE127,69427,Mudau,Im Stöckig 1 +d005196,Česká republika - Úřad práce ČR,CZE,CZ01,170 00,Praha 7,Dobrovského 1278/25 +d005197,Järfällahus AB,SWE,SE110,177 24,Järfälla,Box 197 +d005198,Healex GmbH,DEU,DEA23,51149,Köln,Sophienstraße 5 +d005199,Deutsche Post AG,DEU,DE300,10317,Berlin, +d005200,PreZero Service Centrum Sp. z o.o.,POL,PL712,99-300,Kutno,ul. Łąkoszyńska 127 +d005201,Office of Public Works (OPW),IRL,IE0,D02DR67,Dublin 2,52 St. Stephen's Green +d005202,CG Medical,FRA,FRK26,69620,Ternand,Lieu dit les Verchères 107 impasse de la Mairie +d005203,Connectel-MK Dooel export-import Skopje,MKD,MK,1000,Skopje,Rilski Kongres n.99 +d005204,Česká republika - Ministerstvo spravedlnosti,CZE,CZ01,128 10,Praha 2,Vyšehradská 16 +d005205,Goedemensen detachering bv,NLD,NL,,Amsterdam, +d005206,Municipiul Timișoara,ROU,RO424,300030,Timișoara,"Bulevardul C.D. Loga nr. 1, sector, județ Timiș" +d005207,AMD Global Construct S.R.L.,ROU,RO322,,Voluntari,Str. Crinului nr. 14-16 +d005208,A. Enggaard A/S,DNK,DK042,8000,Aarhus C,Ceresbyen 64 +d005209,Pirkanmaan sairaanhoitopiiri kuntayhtymä,FIN,FI197,,Tampere, +d005210,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d005211,Česká republika - Ministerstvo zemědělství,CZE,CZ010,110 00,Praha 1 - Nové Město,Těšnov 65/17 +d005212,Splošna bolnišnica Celje,SVN,SI,3000,Celje,Oblakova ulica 5 +d005213,"Roche Diagnostics, S. L.",ESP,ES511,,Sant Cugat del Vallès, +d005214,Holzschlägerung und Schneeräumung Söllner,AUT,AT32,5640,Bad Gastein,Hauptschulstraße 14 +d005215,Osnovna šola Fram,SVN,SI,2313,Fram,Turnerjeva ulica 120 +d005216,RS Ingénieurs SA,CHE,CH0,1805,Jongny,Chemin de Faug 11 +d005217,Recherches & Réalisations Rémy SAS,FRA,FRJ28,82000,Montauban, +d005218,JT-Line Oy,FIN,FI1B1,FI-00170,Helsinki,Vironkatu 3 D +d005219,IKS GmbH,DEU,DE241,,Bamberg, +d005220,VAJPRO AB,SWE,SE232,441 60,Alingsås,Prostens väg 18 +d005221,"Statutární město Brno, městská část Brno–Líšeň",CZE,CZ064,628 00,Brno,Jírova 2 +d005222,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d005223,Spirale Print,FRA,FR101,75017,Paris,2-4 rue Barye +d005224,Total Packaging AS,NOR,NO082,1618,Fredrikstad,Tomteveien 29 +d005225,Wissenschaftsstadt Darmstadt Der Magistrat Schulamt,DEU,DE711,64295,Darmstadt,Mina-Rees-Straße 12 +d005226,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d005227,"Stadtverwaltung Cottbus, Zentrales Vergabemanagement",DEU,DE402,03046,Cottbus,Neumarkt 5 +d005228,Cloitre Imprimeurs,FRA,FRH02,29800,Saint-Thonan, +d005229,Izobraževalni Center Piramida Maribor,SVN,SI,2000,Maribor,Park mladih 3 +d005230,Mladinska knjiga Trgovina d.o.o.,SVN,SI,1000,Ljubljana,Slovenska cesta 29 +d005231,"Diahem, trgovina na debelo s farmacevstkimi in medicinskimi izdelki, d.o.o.",SVN,SI,2324,Lovrenc na Dravskem polju,Apače 207 +d005232,Unipharma - 1. slovenská lekárnická akciová spoločnosť,SVK,SK022,972 01,Bojnice,Opatovská cesta 4 +d005233,"RAM 2 trgovina, proizvodnja, zastopanje in inženiring, d.o.o.",SVN,SI,1000,Ljubljana,Bratislavska cesta 7 +d005234,MSIG Insurance Europe AG,FRA,FR101,75009,Paris,65 rue de la Victoire +d005235,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschziz,Ferma Hameicola nr. 6 +d005236,Accord Healthcare Italia,ITA,ITC4C,,Milano, +d005237,Bau und Service Hillebrand GmbH,AUT,AT,,Wals, +d005238,"Stadt Plauen, Vergabestelle",DEU,DED44,08523,Plauen,Unterer Graben 1 +d005239,Société Abiomed France,FRA,FRJ13,75750,Paris Cedex 12,37-39 avenue Ledru-Rollin +d005240,Merck Serono GmbH,DEU,DE71,64289,Darmstadt,Alsfelder Straße 17 +d005241,Vitré Communauté,FRA,FR,35500,Vitré,16 bis BD des Rochers +d005242,Materna Information & Communications SE,DEU,DEA52,,Dortmund,Voßkuhle 27 +d005243,PET-CT Wien / GmbH & Co KG,AUT,AT,1010,Wien,Fleischmarkt 19 +d005244,Staatliches Bauamt Schweinfurt,DEU,DE262,97422,Schweinfurt,Mainberger Straße 14 +d005245,Miasto Łódź – Urząd Miasta Łodzi działający jako podmiot wykonujący zadania Centralnego Zamawiającego zgodnie z art. 15b ust. 1 pkt 3 i art. 15c ustawy Prawo zamówień publicznych,POL,PL711,90-926,Łódź,ul. Piotrkowska 104 +d005246,"Talleres y Grúas González, S. L.",ESP,ES,04640,Pulpí (Almería),"C/ Sebastián, 1" +d005247,geologo dott. Massimo Morachioli,ITA,ITC34,,Luni (SP), +d005248,Roland Ribi & associés,FRA,FRF11,67002,Strasbourg,"15 avenue de la Paix Simone Veil, BP 30069" +d005249,SDIS de la Sarthe,FRA,FRG04,72190,Coulaines,15 boulevard Saint-Michel +d005250,"Paul Hartmann Adriatic, družba za medicinske proizvode in storitve na področju preventive, diagnostike, higiene in zdravstvene oskrbe d.o.o.",SVN,SI,1000,Ljubljana,Letališka cesta 3C +d005251,Norconsult AB,SWE,SE232,402 76,Göteborg,Box 8774 +d005252,Luonnonvarakeskus,FIN,FI1,FI-00791,Helsinki,PL 2 (Latokartanonkaari 9) +d005253,Ganser Maschienen GmbH,AUT,AT125,A-4171 St. Peter am,Markt 26, +d005254,Inspectoratul General de Aviație al MAI,ROU,RO321,013696,Bucureşti,Calea Ion Zăvoi nr. 14 +d005255,Aktsiaselts Telegrupp,EST,EE,11313,Tallinn,Töökoja tn 3 +d005256,Quinten Matsys nv,BEL,BE211,2030,Antwerpen,Zaha Hadidplein 1 +d005257,Przedsiębiorstwo Budowlane Dombud sp. z o.o.,POL,PL417,64-300,Nowy Tomyśl,ul. Emili Sczanieckiej 2 +d005258,"Francisco Chiner, S. L.",ESP,ES52,,Picanya,46210 +d005259,K&S Gebäudetechnik mbH,DEU,DEA17,46149,Oberhausen,Im Erlengrund 17a +d005260,"Interpart trgovina na debelo in drobno, posredništvo, d.o.o.",SVN,SI,1000,Ljubljana,Cesta na Brdo 85 +d005261,HP - Hrvatska pošta d.d.,HRV,HR,10000,Zagreb,Jurišićeva 13 +d005262,Techno Vision Consulting,ROU,RO321,022315,București,"Str. Fundeni nr. 159, sector 2" +d005263,"MAKOM TRGOVINA, d.o.o.",SVN,SI,3320,Velenje,Koroška cesta 64 +d005264,Peab asfalt Norge As,NOR,NO082,1366,lysaker,strandveien 15a +d005265,Västra Götalandsregionen,SWE,SE232,462 80,Vänersborg,Östergatan 1 +d005266,Szabolcs-Szatmár-Bereg Megyei Szilárdhulladék-gazdálkodási Társulás,HUN,HU323,4400,Nyíregyháza,Hősök tere 5. +d005267,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d005268,"Lombardi Ingénierie SAS, mandataire solidaire du groupement conjoint",FRA,FRK26,69003,Lyon,70 rue de la Villette +d005269,"Javni holding Ljubljana, d.o.o., družba za izvajanje strokovnih in razvojnih nalog na področju gospodarskih javnih služb",SVN,SI,1000,Ljubljana,Verovškova ulica 70 +d005270,Ratiodata AG,DEU,DEA3,,Münster, +d005271,Wiker U.K. Ltd,GBR,UKD6,CW11 3HT,Cheshire,"Units 1 and 2, Millbuck Park, Millbuck Way, Springvale Industrial Estate, Sandbach" +d005272,Gruber Innenausbau-Holzbau GmbH,DEU,DE279,D-92444 Rötz-Bernrie,Gruberweg 11, +d005273,Tiszamenti Regionális Vízművek Zártkörűen Működő Részvénytársaság,HUN,HU322,5000,Szolnok,Kossuth Lajos út 5. +d005274,Kedrion,ITA,ITI12,,Lucca, +d005275,Samodzielny Publiczny Wojewódzki Szpital Chirurgii Urazowej im. dr. Janusza Daaba w Piekarach Śląskich,POL,PL22,41-940,Piekary Śląskie,ul. Bytomska 62 +d005276,Ayuntamiento de Cunit,ESP,ES514,43881,Cunit,"C/ Mayor, 12" +d005277,Gemeente Hoeksche Waard,NLD,NL,,Oud-Beijerland, +d005278,Heidelberg Instruments Mikrotechnik GmbH,DEU,DE125,69126,Heidelberg,Tullastr. 2 +d005279,"Cores, informacijski sistemi, d.o.o., Kranj",SVN,SI,4000,Kranj,Ulica Mirka Vadnova 6 +d005280,Transpordiamet,EST,EE,11413,Tallinn,Valge tn 4 +d005281,OMV Petrom S.A.,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d005282,Städtische Pietät,DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 25 +d005283,Cebeo SA,BEL,BE32B,4460,Grâce-Hollogne,rue de Wallonie 13 +d005284,TUS ThüringerUmweltService GmbH,DEU,DEG01,99086,Erfurt,Magdeburger Allee 34 +d005285,"Secretaría General Técnica de Hacienda, Presupuestos y Asuntos Europeos",ESP,ES705,35007,Las Palmas de Gran Canaria,"C/ Tomás Miller, 38" +d005286,"Európa-Pék Export, Import Kereskedelmi és Szolgáltató Korlátolt Felelősségű Társaság",HUN,HU232,7561,Nagybajom,Zrínyi utca 34. +d005287,Medial d.o.o.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 237b +d005288,Stadt Bau Kultur — Mirek Tobor,DEU,DE212,,München, +d005289,Espoon kaupunki,FIN,FI1B1,FI-02070,Espoo,PL 640 +d005290,"Kemomed, d.o.o., svetovanje, trgovina in trženje",SVN,SI,1231,Ljubljana - Črnuče,Brnčičeva ulica 31 +d005291,Rectorado de la Universidad de Sevilla,ESP,ES618,41004,Sevilla,"C/ San Fernando, 4" +d005292,APH Group RO,ROU,RO123,525400,Târgu Secuiesc,Str. Stadionului nr. 7 +d005293,"Dopravní podnik hl. m. Prahy, akciová společnost",CZE,CZ010,190 00,Praha 9,Sokolovská 42/217 +d005294,"Landesbetrieb Bau- und Liegenschaftsmanagement Sachsen-Anhalt (BLSA), Zentrale Vergabestelle (ZVS)",DEU,DEE03,39114,Magdeburg,"PF 3964 (Tessenowstraße 1, 39114 Magdeburg)" +d005295,Cepheid GmbH,DEU,DEA14,47807,Krefeld,Europark Fichtenhain A 4 +d005296,Salzbrenner media GmbH,DEU,DE245,,Buttenheim, +d005297,O2 Czech Republic a.s.,CZE,CZ,140 22,Praha 4–Michle,Za Brumlovkou 266/2 +d005298,Mestna občina Ljubljana,SVN,SI,1000,Ljubljana,Mestni trg 1 +d005299,Movare AB,SWE,SE232,431 23,Mölndal,Box 211 +d005300,Belaj Fine Art Service GmbH,DEU,DE300,12057,Berlin, +d005301,Arabella Versandbuchhandlung GmbH,DEU,DE212,80937,München, +d005302,"Stadt Mönchengladbach, Dezernat Planen, Bauen, Mobilität, Umwelt – VI/V – Vergabestelle",DEU,DEA15,41236,Mönchengladbach,Markt 11 +d005303,Minimed Solutions S.R.L.,ROU,RO321,011786,București,"Calea Giulești nr. 23, sector 6" +d005304,Sindeu Sébastien,FRA,FRI11,33400,Talance,25 rue Ernest Renan +d005305,Gemeente Voorschoten,NLD,NL,,Voorschoten, +d005306,Phoenix Pharma Gyógyszerkereskedelmi Zártkörűen Működő Részvénytársaság,HUN,HU120,2151,Fót,Keleti Márton út 19. +d005307,Riigi Kaitseinvesteeringute Keskus,EST,EE,11314,Tallinn,Järve tn 34a +d005308,Novum centrum techniki grzewczej,POL,PL,,Krosno, +d005309,"Novum CZech, s.r.o.",CZE,CZ,252 02,Jíloviště,Na Močidlech 242 +d005310,"Pitus storitve, trgovina, gostinstvo, posredništvo, uvoz-izvoz d.o.o.",SVN,SI,2000,Maribor,Ob Dravi 2A +d005311,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d005312,Cancom GmbH,DEU,DE254,,Nürnberg, +d005313,Medtech,FRA,FR,34000,Montpellier,900 rue du Mas de Verchant +d005314,M+E Metallbau GmHb,AUT,AT,,Pasching, +d005315,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d005316,Øystese Elektriske AS,NOR,NO0A2,,Nordheimsund, +d005317,Lietuvos ir Šveicarijos UAB „Hospitex Diagnostics Kaunas“,LTU,LT,LT-47164,Kaunas,Antagynės g. 1 +d005318,"Omega svetovanje, inženiring, razvoj in raziskovanje, d.o.o.",SVN,SI,1000,Ljubljana,Dolinškova ulica 8 +d005319,"Stadt Leipzig, EB Gewandhaus zu Leipzig",DEU,DED51,04109,Leipzig,Augustusplatz 8 +d005320,"Medica, medicinska zastopstva, trgovina, marketing in posredovanje, d.o.o.",SVN,SI,1236,Trzin,Špruha 44 +d005321,SPECTRA VISION SRL,ROU,RO321,020148,Bucuresti,"Strada Aleea Tibles, Nr. 7, Sector: 6" +d005322,Mairie de Villeneuve-Saint-Denis,FRA,FR102,77174,Villeneuve-Saint-Denis,Place de la Mairie +d005323,"Inetum España, S. A.",ESP,ES3,,Madrid, +d005324,Waterschap Rivierenland,NLD,NL,4003 BX,Tiel,de Blomboogerd 1 +d005325,Macofil,ROU,RO412,210001,Târgu Jiu,Str. Bârsești nr. 217 +d005326,Nitech,ROU,RO321,012369,București,"Strada Bucureştii Noi nr. 212A, sector 1" +d005327,Medist Imaging & POC S.R.L.,ROU,RO321,050688,București,"Str. Ion Urdăreanu nr. 34, sector 5" +d005328,Köfunarþjónustan ehf,ISL,IS,105,Reykjavík,Héðinsgötu 1-3 +d005329,Smit-Commerce d.o.o.,HRV,HR,10255,Gornji Stupnik,Gornjostupnička 9b +d005330,"Medicina Analit Consumibles, MAC, S. A.",ESP,ES213,,Sondika (Bizkaia), +d005331,Telge Inköp AB,SWE,SE122,151 27,Södertälje,Box 633 +d005332,"Osakidetza-Servicio Vasco de Salud, Hospital Universitario Cruces",ESP,ES21,,Barakaldo, +d005333,MOOVE GmbH,DEU,DEA23,50999,Köln,Industriestraße 161 — Haus 6 +d005334,Kmetijska zadruga Selnica ob Dravi z.o.o.,SVN,SI,2352,Selnica ob Dravi,Spodnja Selnica 5 +d005335,"Uvaterv Út-, Vasúttervező Zrt.",HUN,HU110,1117,Budapest,Dombóvári út 17–19. B. épület +d005336,Fundatia Pro Sovata,ROU,RO125,545500,Sovata,"Strada Lungă, Nr. 46D" +d005337,Södersjukhuset Aktiebolag,SWE,SE11,118 83,Stockholm,i.u. +d005338,Universität Wien,AUT,AT,1010,Wien,Universitätsring 1 +d005339,"VOC Celje, vzdrževanje in obnova cest d.o.o.",SVN,SI,3000,Celje,Lava 42 +d005340,Leistritz Extrusionstechnik GmbH,DEU,DE254,90459,Nürnberg,Markgrafenstr. 36 +d005341,Études recherches géotechnique,FRA,FR,83500,La Seyne-sur-Mer,243 avenue de Bruxelles +d005342,Województwo Warmińsko Mazurskie – Zarząd Dróg Wojewódzkich w Olsztynie,POL,PL62,10-602,Olsztyn,ul. Pstrowskiego 28 b +d005343,Eurovia Verkehrsbau Union GmbH,DEU,DED51,04420,Markranstädt,Gewerbestraße 10 +d005344,"Gertal — Companhia Geral de Restaurantes e Alimentação, S. A.",PRT,PT,2794-022,Carnaxide,"Rua da Garagem, lote 10" +d005345,Hrvatska elektroprivreda d.d.,HRV,HR,10000,Zagreb,Ulica grada Vukovara 37 +d005346,"Česká republika - Statní pozemkový úřad, Krajský pozemkový úřad pro Jihomoravský kraj",CZE,CZ064,621 00,Brno,Hroznová 17 +d005347,Stadt Kreuztal,DEU,DEA5A,57223,Kreuztal,Siegener Straße 5 +d005348,Sverre W. Monsen AS,NOR,NO0A2,5847,Bergen,Postboks 55 Laksevåg +d005349,Kvinnherad Elektro AS,NOR,NO0A2,,Rosendal, +d005350,Komop d.o.o.,HRV,HR,10090,Zagreb-Podsused,Kovinska 21 +d005351,ZFT Ziegler Feuerwehrgerätetechnik GmbH & Co. KG,DEU,DED43,09241,Mühlau,Neue Straße 1 +d005352,Ethias nv,BEL,BE332,4000,Luik, +d005353,„Mar-Four” Marian Siekierski,POL,PL,95-050,Konstantynów Łódzki,ul. Srebrzyńska 5/7 +d005354,Lohmann & Rauscher,FRA,FRF34,88200,Remiremont,ZA de Choisy +d005355,Carsat MP,FRA,FRJ23,31065,Toulouse Cedex 09,2 rue Georges Vivent +d005356,Konsorcjum Urtica Sp. z o.o. PGF S.A.,POL,PL,54-613,Wrocław,ul. Krzemieniecka 120 +d005357,Comfort System Scandinavia Aktiebolag,SWE,SE211,561 46,Huskvarna,Vistakullevägen 18 +d005358,Mediplus Exim,ROU,RO322,077135,Mogoşoaia,Str. Ciobanului nr. 133 +d005359,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d005360,Rijkswaterstaat Corporate Dienst,NLD,NL,3526 LA,Utrecht,Griffioenlaan 2 +d005361,"Raul, s.r.o.",CZE,CZ01,110 00,Praha–Josefov,Elišky Krásnohorské 12/5 +d005362,Västerviks Bostads AB,SWE,SE213,593 25,Västervik,Box 502 +d005363,Staddteil-Schule Dortmund e. V.,DEU,DEA52,,Dortmund, +d005364,INO grafično podjetje za zaposlovanje invalidov d.o.o.,SVN,SI,3000,Celje,Cesta v Trnovlje 7 +d005365,Organismul Intermediar pentru Programul Operațional Sectorial pentru Dezvoltarea Resurselor Umane Nord-Vest,ROU,RO113,400094,Cluj-Napoca,Str. 21 Decembrie 1989 nr. 58 +d005366,"Empresa de Transformación Agraria, S. A., S. M. E., M. P. (Tragsa)",ESP,ES300,28006,Madrid,"C/ Maldonado, 58" +d005367,NetPort Science Park AB (svb),SWE,SE221,,Karlshamn, +d005368,Deutsche Angestellten-Akademie GmbH,DEU,DEA12,47053,Duisburg,Werthauser Straße 164-166 +d005369,Tuomi Logistiikka Oy,FIN,FI1,FI-33840,Tampere,Särkijärvenkatu 1 +d005370,Alcon,FRA,FR105,92500,Rueil-Malmaison,4 rue Henri-Sainte-Claire-Deville +d005371,"Univerzita Karlova, Lékařská fakulta v Plzni",CZE,CZ032,301 00,Plzeň,Husova 654/3 +d005372,Kungsbacka kommun,SWE,SE231,434 81,Kungsbacka,Kungsbacka kommun +d005373,GIS Aqua Austria GmbH,AUT,AT,3300,Amstetten,Clemens-Holzmeister-Str. 3 +d005374,Evangelische Stiftung Michaelshof,DEU,DE803,18147,Rostock,Fährstr. 25 +d005375,Familjen STHLM AB,SWE,SE,116 33,Stockholm,Bondegatan 21 +d005376,Vrtec Viški gaj,SVN,SI,1000,Ljubljana,Reška ulica 31 +d005377,Flyttningsbyrån - Skövde Stadsbud Aktiebolag,SWE,SE232,541 34,Skövde,Rattvägen 4 +d005378,Tornion Vesi Oy,FIN,FI,FI-95400,Tornio, +d005379,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d005380,Samhall Aktiebolag,SWE,SE213,111 64,Stockholm,"Klarabergsviadukten 90, Hus C Box 27705" +d005381,Fisher&Paykel Healthcare GmbH,DEU,DE,D-73614,Schorndorf,Wiesenstrasse 49 +d005382,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d005383,Stadt Duderstadt,DEU,DE91C,37115,Duderstadt,Worbiser Straße 9 +d005384,OmniVision GmbH,DEU,DE,,Puchheim, +d005385,"Biosonda — Comércio de Material Hospitalar, Lda.",PRT,PT170,2720-198,Amadora,"Rua Doutor Francisco Sousa Tavares, 11-A" +d005386,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d005387,"MAKOM TRGOVINA, d.o.o.",SVN,SI,3320,Velenje,Koroška cesta 64 +d005388,UTE Sercli Paisajismo — Contratas Vilor,ESP,ES616,,Jaén, +d005389,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d005390,Bucher Municpal GmbH,DEU,DE92,30453,Hannover,Schörlingstraße 3 +d005391,Groupement SARL Angeli/Lugarini (mandataire) + Olivier Pozzo Di Borgo Architecture + ISB + SMI + Corse Perspectives + Cabinet Luc Grassini,FRA,FRM,20200,Bastia,immeuble le Cezanne +d005392,Autobahn GmbH des Bundes NL Nordwest,DEU,DEF03,30161,Hannover,Bödekerstraße 1 +d005393,Bock GmbH,DEU,DEG0F,,Ilmenau, +d005394,"ATS Chemnitz Asphalt-, Tief- und Straßenbau GmbH",DEU,DED41,09116,Chemnitz,Weideweg 31 +d005395,S.C. Stofe Buhuși S.A.,ROU,RO211,605100,Buhuși,Str. Libertății nr. 36 +d005396,UAB „Plentprojektas“,LTU,LT,,Vilnius, +d005397,"Kirik Monitores Deportivos, S. Coop. L.",ESP,ES213,,Urduliz, +d005398,Uppsalahem Aktiebolag,SWE,SE121,753 29,Uppsala,Uppsalahem Aktiebolag S:t Persgatan 28 +d005399,Weatherford Atlas GIP S.A.,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2A +d005400,CNAVTS de Paris,FRA,FR,75951,Paris Cedex 19,110 avenue de Flandre +d005401,AO East Europe Sp. z o.o. S.K.A.,POL,PL,03-116,Warszawa,Ul. Czarodzieja 16/4 +d005402,ARST SpA,ITA,ITG2,09122,Cagliari,via Posada 8/10 +d005403,Bunel doo,HRV,HR0,10373,Ivanja Reka,Ivanjorečka cesta 102 +d005404,4d-raumwerk,DEU,DEA56,58456,Witten,Ruhrtal 5 +d005405,Kur- und Touristikunternehmen der Stadt Bad Salzungen (kAöR),DEU,DEG0P,36433,Bad Salzungen,Am Flößrasen 1 +d005406,Wackler Service Group GmbH & Co. KG,DEU,DED41,,Chemnitz, +d005407,AEB Amsterdam,NLD,NL,1045 BA,Amsterdam,Australiëhavenweg 21 +d005408,Sopra Steria I2S,FRA,FRJ23,31770,Colomiers,8 avenue Yves Brunaud +d005409,Département de l'Ain,FRA,FRK21,01006,Bourg-en-Bresse,service de la commande publique — 10 rue Pavé d'Amour — BP 40276 +d005410,Kalmar läns landsting,SWE,SE213,392 44,Kalmar,Sjöbrings väg 4A plan 2 +d005411,Damien Bouiges — atelier Forma Urbis,FRA,FRI12,33710,Teuillac,88 chemin de Peublanc +d005412,Ixsane,FRA,FRE11,59650,Villeneuve-d'Ascq,"parc des Moulins, 23 avenue de la Créativité" +d005413,"Hewlett — Packard Portugal, Lda.",PRT,PTZZZ,2774-528,Paço de Arcos,"Rua dos Malhões, 4" +d005414,Västerås kommun,SWE,SE,721 29,Västerås,"Stadshuset, rum C 128" +d005415,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d005416,Hochschule RheinMain,DEU,DE714,65022,Wiesbaden,Postfach 3251 +d005417,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d005418,Skanderborg Kommune,DNK,DK042,8660,Skanderborg,Skanderborg Fælled 1 +d005419,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d005420,DEF,FRA,FRF22,10600,La Chapelle-Saint-Luc,22 bis rue Jean-Baptiste Colbert +d005421,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d005422,"Poniente Formación e Innovación, S. L., Escuela Taller Juyma, S. L. y Lauama RC, S. L., U. T. E., Ley 18/1982",ESP,ES614,,Granada, +d005423,Občina Rogatec,SVN,SI,3252,Rogatec,Pot k ribniku 4 +d005424,"AENA, S. M. E., S. A.",ESP,ES30,28017,Madrid,"Avenida de la Hispanidad, s/n" +d005425,"Telefónica Soluciones de Informática y Comunicaciones de España, S. A. U.",ESP,ES300,,Madrid, +d005426,Gemeinde Hallwang,AUT,AT,5300,Hallwang,Dorfstraße 45 +d005427,PWC Advisory Pricewaterhousecoopers Advisory SAS,FRA,FR1,,Neuilly-sur-Seine, +d005428,Università degli studi di Bergamo,ITA,ITC46,24129,Bergamo,via Salvecchio 19 +d005429,Stefans offshore MC consulting AB,SWE,SE,542 30,Mariestad,Kajgatan 2D +d005430,Alstom Transport bv,NLD,NL,3526 KT,Utrecht,Vliegend Hertlaan 45 +d005431,"Boston Scientific Česká republika, s.r.o.",CZE,CZ010,150 00,Praha,Karla Engliše 3219 4 +d005432,Mark Medical trgovina in storitve d.o.o.,SVN,SI,6210,Sežana,Partizanska cesta 109 +d005433,Zavod Republike Slovenije za transfuzijsko medicino,SVN,SI,1000,Ljubljana,Šlajmerjeva ulica 6 +d005434,Europharma Ltd,MLT,MT,BKR-9076,Birkirkara [Birkirkara],Catalunya Buildings Psaila Street +d005435,"Hydraplan — Manutenção e Comércio de Veículos, S. A.",PRT,PT17,2615-365,Alverca do Ribatejo,"Rua da Quinta das Cotovias, 2" +d005436,Ayuntamiento de Vitoria-Gasteiz,ESP,ES211,,Vitoria-Gasteiz,"C/ Pintor Teodoro Dublang, 25, bajo, 01008 Vitoria-Gasteiz (Álava-Araba)" +d005437,SNCF,FRA,FR,,Lyon, +d005438,Messer România Gaz S.R.L.,ROU,RO321,024102,București,"Str. Delea Veche nr. 24, sector 2" +d005439,"Landkreis Börde, Zentrale Vergabestelle",DEU,DEE07,39387,Oschersleben (Bode),Triftstr. 9-10 +d005440,Badia Berger architectes,FRA,FR104,75003,Paris,14 rue de Bretagne +d005441,Univerzitetni klinični center Maribor,SVN,SI,2000,Maribor,Ljubljanska ulica 5 +d005442,APSIA,FRA,FR,75009,Paris,27 rue de la Rochefoucauld +d005443,Trelleborgs kommun,SWE,SE224,231 83,Trelleborg,Algatan 13 +d005444,Ilomantsin kunta,FIN,FI1D3,,Ilomantsi, +d005445,"Boston Scientific Česká republika, s.r.o.",CZE,CZ010,150 00,Praha,Karla Engliše 3219 4 +d005446,"Unión Fenosa Gas Comercializadora, S. A.",ESP,ES,28033,Madrid,"Vía de los Poblados, 1" +d005447,DB Netz AG (Bukr 16),DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 11-13 +d005448,VU medisch centrum,NLD,NL,1081 HV,Amsterdam,De Boelelaan 1117 +d005449,OMV Petrom S.A,ROU,RO321,013329,Bucureşti,Str. Coralilor nr. 22 +d005450,Hirsch GmbH,DEU,DE212,81369 München,Euckenstr. 17, +d005451,Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos,LTU,LT,LT-50161,Kaunas,Eivenių g. 2 +d005452,"Teixeira, Pinto & Soares, S. A.",PRT,PT170,4600-758,Amarante,"Rua de Outeiro, 677, Zona Industrial de Telões, 4600-758, Amarante" +d005453,A. Kyllönen Oy,FIN,FI1D8,,Kuhmo, +d005454,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d005455,Le centre hospitalier universitaire Grenoble,FRA,FRK24,38043,Grenoble Cedex 09,CS 10217 +d005456,Niederberger Duisburg GmbH & Co. KG,DEU,DEA12,47269,Duisburg,Am Kiekenbusch 10 +d005457,SH Medical S.R.L.,ROU,RO111,410203,Oradea,Str. Tudor Vladimirescu nr. 89 +d005458,"SIJ, podjetje za proizvodnjo in ekonomske storitve z marketingom, d.o.o.",SVN,SI,1230,Domžale,Krumperška ulica 11 +d005459,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d005460,Kuopion kaupunki,FIN,FI1D2,FI-70101,Kuopio,Tulliportinkatu 31 +d005461,PGE Górnictwo i Energetyka Konwencjonalna S.A.,POL,PL,97-400,Bełchatów,ul. Węglowa 5 +d005462,Contur 2,DEU,DEA2B,51427,Bergisch Gladbach,Neuer Trassweg 29 +d005463,BOMI-LAB d.o.o.,HRV,HR050,10000,Zagreb,Gajeva 35 +d005464,Leblanc Illuminations SAS,FRA,FRG04,72027,Le Mans Cedex 2,6-8 rue Michael Faraday +d005465,"Stadt Halle (Saale), Fachbereich Recht, Team Vergabe Bauleistungen/Bauplanungen",DEU,DEE02,06108,Halle (Saale),Marktplatz 1 +d005466,Distrito de Villa de Vallecas,ESP,ES300,28031,Madrid,"C/ Federico García Lorca, 12" +d005467,Občina Vransko,SVN,SI,3305,Vransko,Vransko 59 +d005468,101 Carefarm GmbH,DEU,DE,,Leverkusen, +d005469,Flughafen Berlin Brandenburg GmbH,DEU,DE406,12529,Berlin,"Flughafen Berlin Brandenburg GmbH, Einkauf" +d005470,Mabonex Slovakia spol. s r.o.,SVK,SK021,921 01,Piešťany,Krajinská cesta č.3 +d005471,Region Kronoberg,SWE,SE212,351 88,Växjö,Upphandlingsenheten +d005472,Région Normandie,FRA,FRD,14035,Caen Cedex 01,"place Reine Mathilde, CS 50523" +d005473,Point P,FRA,FR108,95230,Argenteuil,35 rue de Gode +d005474,S.C. Mark'us Unltd S.R.L.,ROU,RO421,310079,Arad,Str. Pădurii nr. 16 +d005475,AMJ Turku Audio Oy,FIN,FI1C1,,Lieto, +d005476,ESMED GROUP,ROU,RO113,400427,Cluj-Napoca,"Strada Baita, Nr. 7" +d005477,CHUBB France,FRA,FRF11,54320,Maxéville,6 rue Alfred Kastler +d005478,Magyar Nemzeti Bank,HUN,HU11,1054,Budapest,Szabadság tér 8–9. +d005479,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d005480,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d005481,Wedow Bürotechnik,DEU,DE80L,,Grimmen, +d005482,Schlosserei Hackl GmbH,DEU,DE229,94209,Regen, +d005483,Landesbetrieb Liegenschafts- und Baubeutreuung Zentrale Mainz,DEU,DEB35,55116,Mainz,Rheinstraße 4E +d005484,ADI „Fejlodo Udvarhelyszek”,ROU,RO124,535600,Odorheiu Secuiesc,Str. 1 Decembrie 1918 nr. 9 +d005485,ASL FG,ITA,ITF46,71122,Foggia (Fg), +d005486,Comptoir métallurgique de Bretagne,FRA,FR,56539,Quéven, +d005487,Skalleberg Handelsträdgård Aktiebolag,SWE,SE,175 61,Järfälla,Ormbackavägen 67 +d005488,"Abbott Rapid Diagnostics Healthcare, S. L.",ESP,ES511,,L'Hospitalet de Llobregat (Barcelona), +d005489,Paysages d'Avenir,FRA,FRY10,97122,Baie-Mahault,Lot nº 36 immeuble Socogar Jarry +d005490,Generali Italia SpA,ITA,ITH34,,Mogliano Veneto, +d005491,Česká republika - Státní pozemkový úřad,CZE,CZ01,130 00,Praha 3,Husinecká 1024/11a +d005492,Zöller-Kipper GmbH,DEU,DEB35,55130,Mainz,Hans-Zöller-Str. 50-68 +d005493,"Fresenius Medical Care Slovenija, Trgovsko in proizvodno podjetje medicinske opreme d.o.o.",SVN,SI,3000,Celje,Gaji 28 +d005494,Prüfling HKS-Energietechnik GmbH,DEU,DE21H,85521,Ottobrunn,Maria-Merian-Str. 12 +d005495,Electroechipament,ROU,RO422,325300,Bocșa,Str. Bichistin nr. 37 +d005496,Suomen Saaristokuljetus Oy,FIN,FI1B,FI-00391,Helsinki,PL 91 +d005497,Provincie Vlaams-Brabant,BEL,BE242,3010,Leuven,Provincieplein 1 diff --git a/test/stress/data/org-small.csv b/test/stress/data/org-small.csv new file mode 100644 index 0000000..e33f1ee --- /dev/null +++ b/test/stress/data/org-small.csv @@ -0,0 +1,101 @@ +mention_id,legal_name,country_code,nuts_code,post_code,post_name,thoroughfare +d000062,Die Fahrdienste Schulbusse Sonnenschein GmbH & Co.KG,DEU,DE942,27751,Delmenhorst,Nordenhamer Str. 65 +d000010,Spitalul Județean de Urgență Bacău Inc,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000002,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000051,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d000032,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d000016,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000057,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d000069,Augustinum gGmbH,DEU,DE212,801375,München,Stiftsbogen 74 +d000077,Felix Telecom S.R.L.,ROU,RO321,020331,București,Str. Fabrica de Glucoză nr. 11D +d000027,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000100,Oktal Pharma d.o.o.,HRV,HR050,10020,Zagreb,Utinjska 40 +d000071,Wassenberg GmbH,DEU,DEA1D,41515,Grevenbroich,von-Goldammer-Str. 31 +d000031,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d000033,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d000064,Dirección General — Osakidetza,ESP,ES21,01006,Vitoria-Gasteiz,"C/ Álava, 45" +d000059,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d000063,Axis Security S.R.L.,ROU,RO423,330004,Deva,"Str. Sântuhalm nr. 65B, Deva (Hunedoara), 330004" +d000085,Landesbetrieb Bau und Immobilien Hessen Niederlassung Mitte Zentrale Vergabe,DEU,DE7,61231,Bad Nauheim,Dieselstraße 1-7 +d000056,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d000053,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d000050,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d000048,Felix EM S.R.L. Inc,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000086,VĮ Lietuvos automobilių kelių direkcija,LTU,LT,LT-03109,Vilnius,J. Basanavičiaus g. 36 +d000083,S.C. Andrea Forest S.R.L.,ROU,RO125,547510,Saschiz,"Ferma Hameicola nr. 6, înscrisă în CF nr. 52512 (nr. cad. 52512) și CF nr. 3226 (nr. cad. 3226)" +d000079,IKK classic,DEU,DE,01099,Dresden,Tannenstraße 4 b +d000081,DB Netz AG (Bukr 16),DEU,DE712,60327,Frankfurt am Main,Adam-Riese-Straße 11-13 +d000023,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000009,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000022,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000038,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000068,Felix Telecom S.R.L.,ROU,RO321,020331,Bucureşti,Str. Fabrica de Glucoză nr. 11D +d000034,Pluridet Comexim S.R.L.,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d000011,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000067,CEZ Vânzare S.A.,ROU,RO411,200769,Craiova,Str. Severinului nr. 97 +d000080,Lidköpings kommun,SWE,SE232,531 88,Lidköping,Skaragatan 8 +d000018,Helion Security SRL,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000075,OMV Petrom Marketing,ROU,RO321,013329,Bucureşti,"Str. Coralilor nr. 22, sector 1" +d000007,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000042,Wasval S.R.L. Inc,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000082,O2 Czech Republic a.s.,CZE,CZ,140 22,Praha 4–Michle,Za Brumlovkou 266/2 +d000061,Santomed S.R.L.,ROU,RO424,300210,Timișoara,Str. Liviu Rebreanu nr. 25 +d000015,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000043,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000060,Centre hospitalier universitaire de Poitiers Inc,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d000094,UAB „Ignitis“,LTU,LT,,Vilnius, +d000089,Hera SpA,ITA,ITH55,40127,Bologna,viale Carlo Berti Pichat 2/4 +d000066,Baby Business S.R.L.,ROU,RO124,535600,Odorheiu Secuiesc,Str. Budcar nr. 58 +d000037,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000024,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000040,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000041,Wasval SRL,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000019,Helion Security S.R.L. Inc,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000073,AMB Global Kron Consult,ROU,RO122,500256,Brașov,Str. Măcieşului nr. 1 +d000006,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000025,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000008,Spitalul Județean de Urgență Bacău Inc,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000035,Pluridet Comexim SRL,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d000090,"Göteborgs Stad, Lokalförvaltningen",SWE,SE232,402 26,Göteborg,Box 5163 +d000047,Felix EM SRL,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000003,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000052,DB Engineering & Consulting GmbH.,DEU,DEG01,,Erfurt, +d000017,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000039,Wasval S.R.L.,ROU,RO213,700036,Iași,"Str. I. C. Brătianu nr. 8A, et. 2, ap. 5" +d000045,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000046,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000013,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000049,DB Engineering & Consulting GmbH,DEU,DEG01,,Erfurt, +d000092,SUTURA Képviseleti és Kereskedelmi Korlátolt Felelősségű Társaság,HUN,HU,1097,Budapest,Gubacsi út 47. +d000014,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000074,S.C. Nisara Impex S.R.L,ROU,RO122,505600,Săcele,Str. Gen. I. Dragalina nr. 21 A +d000091,TREBOR DRUM CONSTRUCT SRL,ROU,RO111,410265,Oradea,"Strada Erofte Grigore, Nr. 1B" +d000020,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000088,Lietuvos sveikatos mokslų universiteto ligoninė Kauno klinikos,LTU,LT,LT-50161,Kaunas,Eivenių g. 2 +d000044,Felix EM S.R.L.,ROU,RO125,555500,Dumbrăveni,Str. Gării nr. 3 +d000099,Medika d.d.,HRV,HR050,10000,Zagreb,Capraška 1 +d000021,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000001,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000036,Pluridet Comexim S.R.L. Inc,ROU,RO321,052082,București,Str. Dr. Alexandru Locusteanu nr. 2 +d000096,Tinmar Energy S.A.,ROU,RO321,014476,București,Str. Floreasca nr. 246C +d000058,Centre hospitalier universitaire de Poitiers Inc,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d000029,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000054,DB Engineering & Consulting GmbH.,DEU,DEG01,,Erfurt, +d000098,Siemens Financial Services,FRA,FR,93527,Saint-Denis Cedex,40 avenue des Fruitiers +d000084,Weatherford Atlas GIP S.A.,ROU,RO316,100189,Ploiești,Str. Clopoței nr. 2A +d000026,AB „Lietuvos geležinkeliai“,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000072,COMPANIA INDUSTRIALA GRIVITA SA,ROU,RO322,077046,Rudeni,"Strada Rudeni, Nr. 79" +d000093,"Z+M Logistics, spol. s r.o.",CZE,CZ080,702 00,Ostrava,"Gorkého 621/26, Moravská Ostrava" +d000078,"ELZY, spol. s r.o.",CZE,CZ,377 01,Jindřichův Hradec,Jarošovská 433 +d000065,Česká republika - Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d000030,AB „Lietuvos geležinkeliai“ Inc,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000028,AB „Lietuvos geležinkeliai“ Inc,LTU,LT,LT-03603,Vilnius,Mindaugo g. 12 +d000097,OMV Petrom Marketing,ROU,RO321,013329,București,"Str. Coralilor nr. 22, sector 1" +d000004,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000005,Spitalul Județean de Urgență Bacău,ROU,RO211,600114,Bacău,Str. Spiru Haret nr. 2 +d000055,Centre hospitalier universitaire de Poitiers,FRA,FRI34,86021,Poitiers,"2 rue de la Milétrie, CS 90577" +d000076,Costacos Com S.R.L.,ROU,RO122,500108,Brașov,Str. Valea Tei nr. 31A +d000012,Helion Security S.R.L.,ROU,RO111,,Ștei,Str. Andrei Mureșanu nr. AN6 +d000070,Česká republika – Ministerstvo vnitra,CZE,CZ0,170 34,Praha 7,Nad Štolou 936/3 +d000095,VS Vereinigte Spezialmöbelfabriken GmbH & Co. KG,DEU,DE11B,97941,Tauberbischofsheim,Hochhäuser Straße 8 +d000087,"Stadt Chemnitz, Rechtsamt, Zentrale Vergabestelle",DEU,DED41,09111,Chemnitz,Friedensplatz 1 diff --git a/test/stress/stress_test.py b/test/stress/stress_test.py new file mode 100644 index 0000000..96ce807 --- /dev/null +++ b/test/stress/stress_test.py @@ -0,0 +1,522 @@ +#!/usr/bin/env python3 +""" +Unified Stress Test for Entity Resolver + +Standalone stress test runner (not pytest-managed) for performance testing +of the entity resolver with configurable datasets and parameters. + +Usage: + python test/stress/stress_test.py \ + --dataset test/stress/data/org-small.csv \ + --output /tmp/stress_result.json + + python test/stress/stress_test.py \ + --dataset test/stress/data/org-mid.csv \ + --seed 200 \ + --records 500 \ + --config src/config/resolver.yaml \ + --output /tmp/stress_mid.json +""" + +import argparse +import csv +import json +import logging +import sys +import time +import traceback +import tracemalloc +from collections import Counter +from dataclasses import asdict, dataclass +from pathlib import Path +from statistics import mean, stdev + +import duckdb +import yaml + +# Import resolver components +from ere.adapters.duckdb_repositories import ( + DuckDBClusterRepository, + DuckDBMentionRepository, + DuckDBSimilarityRepository, +) +from ere.adapters.duckdb_schema import init_schema +from ere.adapters.splink_linker_impl import SpLinkSimilarityLinker +from ere.models.resolver import Mention +from ere.services.entity_resolution_service import EntityResolver +from ere.services.resolver_config import ResolverConfig + +logger = logging.getLogger(__name__) + + +# ============================================================================= +# Data Models +# ============================================================================= + + +@dataclass +class RequestMetric: + """Per-request latency and context.""" + + record_idx: int + mention_id: str + latency_ms: float + cluster_id: str + n_candidates: int + score: float + + +@dataclass +class ExperimentResult: + """Aggregated stress test results.""" + + name: str + dataset_path: str + n_mentions: int + n_records_stressed: int + n_seed: int + n_clusters: int + mean_latency_ms: float + median_latency_ms: float + p95_latency_ms: float + p99_latency_ms: float + min_latency_ms: float + max_latency_ms: float + stdev_latency_ms: float + peak_memory_mb: float + total_time_sec: float + metrics: list[RequestMetric] + + +# ============================================================================= +# Core Functions +# ============================================================================= + + +def load_mentions(csv_path: str) -> list[Mention]: + """ + Load mentions from CSV file. + + Expected columns: mention_id, legal_name, country_code (and other optional attributes). + """ + mentions = [] + with open(csv_path) as f: + reader = csv.DictReader(f) + for row in reader: + # Use flat dict form; Mention validator handles conversion + mentions.append(Mention(**row)) + return mentions + + +def create_resolver( + entity_fields: list[str], config_path: str +) -> tuple[EntityResolver, dict, duckdb.DuckDBPyConnection]: + """ + Create fresh EntityResolver instance with in-memory DuckDB. + + Returns: + (resolver, raw_config_dict, connection) + """ + # Load config + with open(config_path) as f: + raw_config = yaml.safe_load(f) + + # Create in-memory DB and init schema + con = duckdb.connect(":memory:") + init_schema(con, entity_fields) + + # Wire up repositories and linker + mention_repo = DuckDBMentionRepository(con, entity_fields) + similarity_repo = DuckDBSimilarityRepository(con) + cluster_repo = DuckDBClusterRepository(con) + linker = SpLinkSimilarityLinker(entity_fields, raw_config) + + # Create resolver + resolver_config = ResolverConfig.from_dict(raw_config) + resolver = EntityResolver( + mention_repo, similarity_repo, cluster_repo, linker, resolver_config + ) + + return resolver, raw_config, con + + +def seed_and_train( + resolver: EntityResolver, + mentions: list[Mention], + n_seed: int, + skip_train: bool = False, +): + """ + Seed resolver with first n_seed mentions and optionally trigger training. + + Args: + resolver: EntityResolver instance + mentions: List of mentions to seed with + n_seed: Number of mentions to seed (0 = cold-start, no seeding) + skip_train: If True, skip training (pure cold-start with parameters only) + + This warms up the resolver and establishes initial clusters for the + stress test phase. With skip_train=True, tests cold-start performance + using only the Splink cold-start parameters (no EM training). + """ + if n_seed > 0: + logger.info(f"Seeding with {n_seed} mentions...") + for i in range(min(n_seed, len(mentions))): + mention = mentions[i] + try: + resolver.resolve(mention) + except Exception as e: + logger.warning(f"Seed error at record {i}: {e}") + else: + logger.info("Cold-start: skipping seed phase") + + if not skip_train: + logger.info("Training linker...") + resolver.train() + logger.info("Seeding and training complete") + else: + logger.info("Cold-start: skipping training (using cold-start parameters only)") + + +def stress_loop( + resolver: EntityResolver, + mentions: list[Mention], + start_idx: int, + exit_strategy: str, + exit_value: float | int, +) -> list[RequestMetric]: + """ + Run stress test loop with latency tracking. + + Args: + resolver: EntityResolver instance + mentions: List of mentions to process + start_idx: Starting index in mentions list + exit_strategy: "records" (process N records) or "time" (run for N seconds) + exit_value: Value for exit strategy (record count or seconds) + + Returns: + List of RequestMetric for each resolved mention + """ + metrics = [] + start_time = time.perf_counter() + + if exit_strategy == "records": + n_stress = int(exit_value) + end_idx = min(start_idx + n_stress, len(mentions)) + elif exit_strategy == "time": + end_idx = len(mentions) # Process all, stop by time + timeout_sec = float(exit_value) + else: + raise ValueError(f"Unknown exit_strategy: {exit_strategy}") + + logger.info( + f"Starting stress loop: {exit_strategy}={exit_value}, " + f"processing mentions[{start_idx}:{end_idx}]" + ) + + for i in range(start_idx, end_idx): + mention = mentions[i] + + # Check time-based exit + if exit_strategy == "time": + elapsed = time.perf_counter() - start_time + if elapsed > timeout_sec: + logger.info(f"Time limit reached: {elapsed:.1f}s") + break + + # Time the resolve call + t0 = time.perf_counter() + try: + result = resolver.resolve(mention) + elapsed_ms = (time.perf_counter() - t0) * 1000 + + # Extract metrics + metric = RequestMetric( + record_idx=i, + mention_id=mention.id.value, + latency_ms=elapsed_ms, + cluster_id=result.top.cluster_id.value if result.top else "NONE", + n_candidates=len(result.candidates), + score=result.top.score if result.top else 0.0, + ) + metrics.append(metric) + + if i % 50 == 0: + logger.debug( + f"Record {i}: {elapsed_ms:.1f}ms, " + f"cluster={metric.cluster_id}, " + f"candidates={metric.n_candidates}" + ) + + except Exception as e: + logger.error(f"Stress loop error at record {i}: {e}") + logger.debug(traceback.format_exc()) + + total_time = time.perf_counter() - start_time + logger.info( + f"Stress loop complete: {len(metrics)} records in {total_time:.1f}s " + f"({len(metrics) / total_time:.1f} rec/s)" + ) + + return metrics + + +def run_experiment( + name: str, + dataset_path: str, + config_path: str, + seed_count: int = 200, + exit_strategy: str = "records", + exit_value: int | float = 200, + skip_train: bool = False, +) -> ExperimentResult: + """ + Run full stress test experiment. + + Args: + name: Experiment name + dataset_path: Path to CSV dataset + config_path: Path to resolver config YAML + seed_count: Number of mentions to seed with (0 = cold-start) + exit_strategy: "records" or "time" + exit_value: Record count or seconds (depending on strategy) + skip_train: If True, skip training (cold-start with parameters only) + + Returns: + ExperimentResult with full metrics + """ + logger.info(f"=== Experiment: {name} ===") + + # Load data + logger.info(f"Loading {dataset_path}...") + mentions = load_mentions(dataset_path) + logger.info(f"Loaded {len(mentions)} mentions") + + # Determine entity fields from config + with open(config_path) as f: + raw_config = yaml.safe_load(f) + entity_fields = [ + comp["field"] for comp in raw_config.get("splink", {}).get("comparisons", []) + ] + + # Create resolver + resolver, _, con = create_resolver(entity_fields, config_path) + + try: + # Seed and train (or cold-start) + seed_and_train(resolver, mentions, seed_count, skip_train=skip_train) + + # Run stress loop + tracemalloc.start() + start_idx = seed_count + metrics = stress_loop(resolver, mentions, start_idx, exit_strategy, exit_value) + current, peak = tracemalloc.get_traced_memory() + tracemalloc.stop() + + # Aggregate metrics + if not metrics: + logger.error("No metrics collected!") + return None + + latencies = [m.latency_ms for m in metrics] + latencies_sorted = sorted(latencies) + + # Resolved cluster count + resolved_clusters = Counter(m.cluster_id for m in metrics) + + result = ExperimentResult( + name=name, + dataset_path=str(dataset_path), + n_mentions=len(mentions), + n_records_stressed=len(metrics), + n_seed=seed_count, + n_clusters=len(resolved_clusters), + mean_latency_ms=mean(latencies), + median_latency_ms=latencies_sorted[len(latencies_sorted) // 2], + p95_latency_ms=latencies_sorted[int(0.95 * len(latencies_sorted))], + p99_latency_ms=latencies_sorted[int(0.99 * len(latencies_sorted))], + min_latency_ms=min(latencies), + max_latency_ms=max(latencies), + stdev_latency_ms=stdev(latencies) if len(latencies) > 1 else 0.0, + peak_memory_mb=peak / (1024 * 1024), + total_time_sec=sum(m.latency_ms for m in metrics) / 1000, + metrics=metrics, + ) + + return result + finally: + # Ensure DuckDB connection is properly closed + try: + con.close() + except Exception as e: + logger.warning(f"Error closing DuckDB connection: {e}") + + +# ============================================================================= +# Reporting +# ============================================================================= + + +def print_summary(result: ExperimentResult): + """Print human-readable summary to stdout.""" + print(f"\n{'=' * 70}") + print(f"Experiment: {result.name}") + print(f"{'=' * 70}") + print(f"Dataset: {result.dataset_path}") + print(f"Mentions: {result.n_mentions} total, {result.n_records_stressed} stressed") + print(f"Seeding: {result.n_seed} mentions") + print() + print(f"Resolved clusters: {result.n_clusters}") + print() + print("Latency (ms):") + print(f" Mean: {result.mean_latency_ms:8.2f}") + print(f" Median: {result.median_latency_ms:8.2f}") + print(f" Std: {result.stdev_latency_ms:8.2f}") + print(f" Min: {result.min_latency_ms:8.2f}") + print(f" P95: {result.p95_latency_ms:8.2f}") + print(f" P99: {result.p99_latency_ms:8.2f}") + print(f" Max: {result.max_latency_ms:8.2f}") + print() + print(f"Memory: {result.peak_memory_mb:.1f} MB (peak)") + print(f"Total time: {result.total_time_sec:.1f} sec") + print(f"{'=' * 70}\n") + + +def save_result_json(result: ExperimentResult, output_path: str): + """Save result to JSON file.""" + # Convert metrics to dicts for JSON serialization + result_dict = asdict(result) + result_dict["metrics"] = [asdict(m) for m in result.metrics] + + with open(output_path, "w") as f: + json.dump(result_dict, f, indent=2) + + logger.info(f"Saved result to {output_path}") + + +# ============================================================================= +# CLI +# ============================================================================= + + +def main(): + """Parse CLI arguments and run experiment.""" + parser = argparse.ArgumentParser( + description="Unified stress test for entity resolver" + ) + parser.add_argument( + "--dataset", + required=True, + help="Path to CSV dataset (org-small.csv, org-mid.csv, etc.)", + ) + parser.add_argument( + "--config", + default="src/config/resolver.yaml", + help="Path to resolver config YAML", + ) + parser.add_argument( + "--seed", + type=int, + default=200, + help="Number of mentions to seed before stress loop", + ) + parser.add_argument( + "--records", + type=int, + default=None, + help="Number of records to process (default: all remaining)", + ) + parser.add_argument( + "--time", + type=float, + default=None, + help="Run for N seconds instead of fixed record count", + ) + parser.add_argument( + "--output", + default="/tmp/stress_result.json", + help="Output JSON file path", + ) + parser.add_argument( + "--name", + default=None, + help="Experiment name (default: dataset basename)", + ) + parser.add_argument( + "--no-train", + action="store_true", + help="Skip training; use cold-start parameters only (implies --seed 0)", + ) + parser.add_argument( + "--verbose", + "-v", + action="store_true", + help="Enable debug logging", + ) + + args = parser.parse_args() + + # Setup logging + log_level = logging.DEBUG if args.verbose else logging.INFO + logging.basicConfig( + level=log_level, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + ) + + # Cold-start mode implies seed=0 and skip_train=True + if args.no_train: + args.seed = 0 + skip_train = True + else: + skip_train = False + + # Determine exit strategy + if args.time: + exit_strategy = "time" + exit_value = args.time + elif args.records: + exit_strategy = "records" + exit_value = args.records + else: + # Default: process all remaining records + exit_strategy = "records" + exit_value = 999999 # Effectively unlimited + + # Experiment name + exp_name = args.name or Path(args.dataset).stem + if args.no_train: + exp_name += "_coldstart" + + # Run experiment + try: + result = run_experiment( + name=exp_name, + dataset_path=args.dataset, + config_path=args.config, + seed_count=args.seed, + exit_strategy=exit_strategy, + exit_value=exit_value, + skip_train=skip_train, + ) + + if result: + print_summary(result) + save_result_json(result, args.output) + logger.info(f"✅ Experiment complete") + # Flush output streams before exiting + sys.stdout.flush() + sys.stderr.flush() + return 0 + else: + logger.error("❌ Experiment failed") + return 1 + + except Exception as e: + logger.error(f"❌ Fatal error: {e}") + logger.debug(traceback.format_exc()) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/test/test_data/organizations/group1/661238-2023.ttl b/test/test_data/organizations/group1/661238-2023.ttl new file mode 100644 index 0000000..e34f13a --- /dev/null +++ b/test/test_data/organizations/group1/661238-2023.ttl @@ -0,0 +1,28 @@ +@prefix cccev: . +@prefix epd: . +@prefix epo: . +@prefix locn: . +@prefix org: . +@prefix owl: . +@prefix xsd: . + +epd:id_2023-S-210-661238_ReviewerOrganisation_LLhJHMi9mby8ixbkfyGoWj a org:Organization ; + epo:hasLegalName "Комисия за защита на конкуренцията"@bg ; + epo:hasPrimaryContactPoint epd:id_2023-S-210-661238_ReviewerContactPoint_LLhJHMi9mby8ixbkfyGoWj ; + cccev:registeredAddress epd:id_2023-S-210-661238_ReviewerOrganisationAddress_LLhJHMi9mby8ixbkfyGoWj ; + owl:sameAs , + , + , + epd:id_2023-S-113-353030_ReviewerOrganisation_bdZjimbzCaRXbeYeBmF94j . + +epd:id_2023-S-210-661238_ReviewerContactPoint_LLhJHMi9mby8ixbkfyGoWj a cccev:ContactPoint; + epo:hasFax "+359 29807315"; + epo:hasInternetAddress "http://www.cpc.bg"^^xsd:anyURI; + cccev:email "delovodstvo@cpc.bg"; + cccev:telephone "+359 29356113" . + +epd:id_2023-S-210-661238_ReviewerOrganisationAddress_LLhJHMi9mby8ixbkfyGoWj a locn:Address; + epo:hasCountryCode ; + locn:postCode "1000"; + locn:postName "София"; + locn:thoroughfare "бул. Витоша № 18" . \ No newline at end of file diff --git a/test/test_data/organizations/group1/662860-2023.ttl b/test/test_data/organizations/group1/662860-2023.ttl new file mode 100644 index 0000000..1289de5 --- /dev/null +++ b/test/test_data/organizations/group1/662860-2023.ttl @@ -0,0 +1,28 @@ +@prefix cccev: . +@prefix epd: . +@prefix epo: . +@prefix locn: . +@prefix org: . +@prefix owl: . +@prefix xsd: . + +epd:id_2023-S-210-662860_ReviewerOrganisation_LLhJHMi9mby8ixbkfyGoWj a org:Organization ; + epo:hasLegalName "Комисия за защита на конкуренцията"@bg ; + epo:hasPrimaryContactPoint epd:id_2023-S-210-662860_ReviewerContactPoint_LLhJHMi9mby8ixbkfyGoWj ; + cccev:registeredAddress epd:id_2023-S-210-662860_ReviewerOrganisationAddress_LLhJHMi9mby8ixbkfyGoWj ; + owl:sameAs , + , + , + epd:id_2023-S-113-353030_ReviewerOrganisation_bdZjimbzCaRXbeYeBmF94j . + +epd:id_2023-S-210-662860_ReviewerContactPoint_LLhJHMi9mby8ixbkfyGoWj a cccev:ContactPoint; + epo:hasFax "+359 29807315"; + epo:hasInternetAddress "http://www.cpc.bg"^^xsd:anyURI; + cccev:email "delovodstvo@cpc.bg"; + cccev:telephone "+359 29356113" . + +epd:id_2023-S-210-662860_ReviewerOrganisationAddress_LLhJHMi9mby8ixbkfyGoWj a locn:Address; + epo:hasCountryCode ; + locn:postCode "1000"; + locn:postName "София"; + locn:thoroughfare "бул. Витоша № 18" . \ No newline at end of file diff --git a/test/test_data/organizations/group1/663653-2023.ttl b/test/test_data/organizations/group1/663653-2023.ttl new file mode 100644 index 0000000..98f17b5 --- /dev/null +++ b/test/test_data/organizations/group1/663653-2023.ttl @@ -0,0 +1,28 @@ +@prefix cccev: . +@prefix epd: . +@prefix epo: . +@prefix locn: . +@prefix org: . +@prefix owl: . +@prefix xsd: . + +epd:id_2023-S-210-663653_ReviewerOrganisation_bdZjimbzCaRXbeYeBmF94j a org:Organization ; + epo:hasLegalName "Комисия за защита на конкуренцията"@bg ; + epo:hasPrimaryContactPoint epd:id_2023-S-210-663653_ReviewerContactPoint_bdZjimbzCaRXbeYeBmF94j ; + cccev:registeredAddress epd:id_2023-S-210-663653_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j ; + owl:sameAs , + , + , + epd:id_2023-S-113-353030_ReviewerOrganisation_bdZjimbzCaRXbeYeBmF94j . + +epd:id_2023-S-210-663653_ReviewerContactPoint_bdZjimbzCaRXbeYeBmF94j a cccev:ContactPoint; + epo:hasFax "+359 29807315"; + epo:hasInternetAddress "http://www.cpc.bg"^^xsd:anyURI; + cccev:email "delovodstvo@cpc.bg"; + cccev:telephone "+359 29356113" . + +epd:id_2023-S-210-663653_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j a locn:Address; + epo:hasCountryCode ; + locn:postCode "1000"; + locn:postName "София"; + locn:thoroughfare "бул. Витоша № 18" . \ No newline at end of file diff --git a/test/test_data/organizations/group2/661197-2023.ttl b/test/test_data/organizations/group2/661197-2023.ttl new file mode 100644 index 0000000..2ed1f3c --- /dev/null +++ b/test/test_data/organizations/group2/661197-2023.ttl @@ -0,0 +1,15 @@ +@prefix cccev: . +@prefix epd: . +@prefix epo: . +@prefix locn: . +@prefix org: . +@prefix owl: . + +epd:id_2023-S-210-661197_ReviewerOrganisation_bdZjimbzCaRXbeYeBmF94j a org:Organization ; + epo:hasLegalName "tribunal administratif de Paris"@fr ; + cccev:registeredAddress epd:id_2023-S-210-661197_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j ; + owl:sameAs . + +epd:id_2023-S-210-661197_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j a locn:Address; + epo:hasCountryCode ; + locn:postName "Paris" . \ No newline at end of file diff --git a/test/test_data/organizations/group2/663952-2023.ttl b/test/test_data/organizations/group2/663952-2023.ttl new file mode 100644 index 0000000..934636d --- /dev/null +++ b/test/test_data/organizations/group2/663952-2023.ttl @@ -0,0 +1,22 @@ +@prefix cccev: . +@prefix epd: . +@prefix epo: . +@prefix locn: . +@prefix org: . +@prefix owl: . + +epd:id_2023-S-210-663952_ReviewerOrganisation_bdZjimbzCaRXbeYeBmF94j a org:Organization ; + epo:hasLegalName "tribunal administratif de Paris"@fr ; + epo:hasPrimaryContactPoint epd:id_2023-S-210-663952_ReviewerContactPoint_bdZjimbzCaRXbeYeBmF94j ; + cccev:registeredAddress epd:id_2023-S-210-663952_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j ; + owl:sameAs . + +epd:id_2023-S-210-663952_ReviewerContactPoint_bdZjimbzCaRXbeYeBmF94j a cccev:ContactPoint; + cccev:email "greffe.ta-paris@juradm.fr"; + cccev:telephone "+33 144594400" . + +epd:id_2023-S-210-663952_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j a locn:Address; + epo:hasCountryCode ; + locn:postCode "75181"; + locn:postName "Paris"; + locn:thoroughfare "7 rue de Jouy" . \ No newline at end of file diff --git a/test/test_data/organizations/group2/663952_-2023.ttl b/test/test_data/organizations/group2/663952_-2023.ttl new file mode 100644 index 0000000..b95fd19 --- /dev/null +++ b/test/test_data/organizations/group2/663952_-2023.ttl @@ -0,0 +1,22 @@ +@prefix cccev: . +@prefix epd: . +@prefix epo: . +@prefix locn: . +@prefix org: . +@prefix owl: . + +epd:id_2023-S-210-663952_ReviewerOrganisation_bdZjimbzCaRXbeYeBmF94j a org:Organization ; + epo:hasLegalName "tribunal administratif Paris"@fr ; + epo:hasPrimaryContactPoint epd:id_2023-S-210-663952_ReviewerContactPoint_bdZjimbzCaRXbeYeBmF94j ; + cccev:registeredAddress epd:id_2023-S-210-663952_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j ; + owl:sameAs . + +epd:id_2023-S-210-663952_ReviewerContactPoint_bdZjimbzCaRXbeYeBmF94j a cccev:ContactPoint; + cccev:email "greffe.ta-paris@juradm.fr"; + cccev:telephone "+33 144594400" . + +epd:id_2023-S-210-663952_ReviewerOrganisationAddress_bdZjimbzCaRXbeYeBmF94j a locn:Address; + epo:hasCountryCode ; + locn:postCode "75181"; + locn:postName "Paris"; + locn:thoroughfare "7 rue de Jouy" . \ No newline at end of file diff --git a/test/test_data/procedures/group1/662861-2023.ttl b/test/test_data/procedures/group1/662861-2023.ttl new file mode 100644 index 0000000..e2d149d --- /dev/null +++ b/test/test_data/procedures/group1/662861-2023.ttl @@ -0,0 +1,21 @@ +@prefix epd: . +@prefix epo: . +@prefix xsd: . + +epd:id_2023-S-210-662861_Procedure_faF7Q5dyoGpXu3Ru4RGg73 a epo:Procedure ; + epo:hasDescription "Servicii de exploatare forestiera"@ro ; + epo:hasID epd:id_2023-S-210-662861_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasLegalBasis ; + epo:hasProcedureType ; + epo:hasProcurementScopeDividedIntoLot epd:id_2023-S-210-662861_Lot_DgNm7RuiSQ47VBTvdrHsRv ; + epo:hasPurpose epd:id_2023-S-210-662861_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasTitle "Servicii de exploatare forestiera Negociere 10 - 2023 dssv"@ro ; + epo:isCoveredByGPA false ; + epo:isSubjectToProcedureSpecificTerm epd:id_2023-S-210-662861_DirectAwardTerm_C5nS5y4XErvUqzRNMARW8r . + +epd:id_2023-S-210-662861_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 a epo:Identifier; + epo:hasIdentifierValue "10_2023" . + +epd:id_2023-S-210-662861_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 a epo:Purpose; + epo:hasContractNatureType ; + epo:hasMainClassification . diff --git a/test/test_data/procedures/group1/663131-2023.ttl b/test/test_data/procedures/group1/663131-2023.ttl new file mode 100644 index 0000000..ce99aa3 --- /dev/null +++ b/test/test_data/procedures/group1/663131-2023.ttl @@ -0,0 +1,21 @@ +@prefix epd: . +@prefix epo: . +@prefix xsd: . + +epd:id_2023-S-210-663131_Procedure_faF7Q5dyoGpXu3Ru4RGg73 a epo:Procedure ; + epo:hasDescription "Servicii de exploatare forestiera"@ro ; + epo:hasID epd:id_2023-S-210-663131_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasLegalBasis ; + epo:hasProcedureType ; + epo:hasProcurementScopeDividedIntoLot epd:id_2023-S-210-663131_Lot_DgNm7RuiSQ47VBTvdrHsRv ; + epo:hasPurpose epd:id_2023-S-210-663131_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasTitle "Servicii de exploatare forestiera Negociere 10 - 2023 dssv"@ro ; + epo:isCoveredByGPA false ; + epo:isSubjectToProcedureSpecificTerm epd:id_2023-S-210-663131_DirectAwardTerm_C5nS5y4XErvUqzRNMARW8r . + +epd:id_2023-S-210-663131_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 a epo:Identifier; + epo:hasIdentifierValue "10_2023" . + +epd:id_2023-S-210-663131_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 a epo:Purpose; + epo:hasContractNatureType ; + epo:hasMainClassification . \ No newline at end of file diff --git a/test/test_data/procedures/group1/664733-2023.ttl b/test/test_data/procedures/group1/664733-2023.ttl new file mode 100644 index 0000000..987d59f --- /dev/null +++ b/test/test_data/procedures/group1/664733-2023.ttl @@ -0,0 +1,17 @@ +@prefix epd: . +@prefix epo: . +@prefix xsd: . + +epd:id_2023-S-210-664733_Procedure_faF7Q5dyoGpXu3Ru4RGg73 a epo:Procedure ; + epo:hasDescription "Servicii de exploatare forestiera"@ro ; + epo:hasID epd:id_2023-S-210-664733_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasLegalBasis ; + epo:hasProcedureType ; + epo:hasProcurementScopeDividedIntoLot epd:id_2023-S-210-664733_Lot_DgNm7RuiSQ47VBTvdrHsRv ; + epo:hasPurpose epd:id_2023-S-210-664733_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasTitle "Servicii de exploatare forestiera Negociere 10 - 2023 dssv"@ro ; + epo:isCoveredByGPA false ; + epo:isSubjectToProcedureSpecificTerm epd:id_2023-S-210-664733_DirectAwardTerm_C5nS5y4XErvUqzRNMARW8r . + +epd:id_2023-S-210-664733_ContractIdentifier_Q2stfyFrZKsVi566NWBwe8 a epo:Identifier; + epo:hasIdentifierValue "26623" . \ No newline at end of file diff --git a/test/test_data/procedures/group2/661196-2023.ttl b/test/test_data/procedures/group2/661196-2023.ttl new file mode 100644 index 0000000..6c3a412 --- /dev/null +++ b/test/test_data/procedures/group2/661196-2023.ttl @@ -0,0 +1,23 @@ +@prefix epd: . +@prefix epo: . +@prefix xsd: . + +epd:id_2023-S-210-661196_Procedure_faF7Q5dyoGpXu3Ru4RGg73 a epo:Procedure ; + epo:hasAdditionalInformation "Zadavateli není známo, zda se jedná o malý či střední podnik."@cs ; + epo:hasDescription "Předmětem plnění veřejné zakázky na uzavření Rámcové dohody je poskytování služeb na zpracování projektová dokumentace všech požadovaných projektových stupňů staveb pozemních komunikací Na základě Rámcové dohody bude zadavatel jejím účastníkům zadávat jednotlivé dílčí zakázky na služby spočívající v provádění konkrétních projektových prací pozemních komunikací včetně příslušenství (např. osvětlení, protihlukové stěny, SSÚD, apod.), včetně výkonu inženýrské činnosti, a to dle aktuálních potřeb zadavatele."@cs ; + epo:hasID epd:id_2023-S-210-661196_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasLegalBasis ; + epo:hasProcedureType ; + epo:hasProcurementScopeDividedIntoLot epd:id_2023-S-210-661196_Lot_DgNm7RuiSQ47VBTvdrHsRv ; + epo:hasPurpose epd:id_2023-S-210-661196_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasTitle "Rámcová dohoda na projektové práce pro provoz a údržbu pozemních komunikací 2022-B"@cs ; + epo:isCoveredByGPA true ; + epo:isSubjectToProcedureSpecificTerm epd:id_2023-S-210-661196_FrameworkAgreementTerm_C5nS5y4XErvUqzRNMARW8r ; + epo:usesTechnique epd:id_2023-S-210-661196_FrameworkAgreementTechniqueUsage_C5nS5y4XErvUqzRNMARW8r . + +epd:id_2023-S-210-661196_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 a epo:Identifier; + epo:hasIdentifierValue "01PU-005722" . + +epd:id_2023-S-210-661196_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 a epo:Purpose; + epo:hasContractNatureType ; + epo:hasMainClassification . \ No newline at end of file diff --git a/test/test_data/procedures/group2/663262-2023.ttl b/test/test_data/procedures/group2/663262-2023.ttl new file mode 100644 index 0000000..75f24ab --- /dev/null +++ b/test/test_data/procedures/group2/663262-2023.ttl @@ -0,0 +1,23 @@ +@prefix epd: . +@prefix epo: . +@prefix xsd: . + +epd:id_2023-S-210-663262_Procedure_faF7Q5dyoGpXu3Ru4RGg73 a epo:Procedure ; + epo:hasAdditionalInformation "Zadavateli není známo, zda se jedná o malý či střední podnik."@cs ; + epo:hasDescription "Předmětem plnění veřejné zakázky na uzavření rámcové dohody, která bude v rámci zadávacího řízení uzavřena na dobu trvání 48 měsíců se šesti účastníky, je poskytování služeb dle zadávací dokumentace a jejích příloh. Na základě rámcové dohody bude zadavatel jejím účastníkům zadávat jednotlivé dílčí zakázky na služby spočívající v provádění stavebního dozoru na stavbách pozemních komunikací, včetně výkonu koordinátora BOZP, včetně související technické pomoci, a to dle aktuálních potřeb zadavatele."@cs ; + epo:hasID epd:id_2023-S-210-663262_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasLegalBasis ; + epo:hasProcedureType ; + epo:hasProcurementScopeDividedIntoLot epd:id_2023-S-210-663262_Lot_DgNm7RuiSQ47VBTvdrHsRv ; + epo:hasPurpose epd:id_2023-S-210-663262_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 ; + epo:hasTitle "Rámcová dohoda na výkon stavebního dozoru a koordinátora BOZP pro malé stavby-2022"@cs ; + epo:isCoveredByGPA true ; + epo:isSubjectToProcedureSpecificTerm epd:id_2023-S-210-663262_FrameworkAgreementTerm_C5nS5y4XErvUqzRNMARW8r ; + epo:usesTechnique epd:id_2023-S-210-663262_FrameworkAgreementTechniqueUsage_C5nS5y4XErvUqzRNMARW8r . + +epd:id_2023-S-210-663262_ProcedureIdentifier_faF7Q5dyoGpXu3Ru4RGg73 a epo:Identifier; + epo:hasIdentifierValue "01PU-005734" . + +epd:id_2023-S-210-663262_ProcedurePurpose_faF7Q5dyoGpXu3Ru4RGg73 a epo:Purpose; + epo:hasContractNatureType ; + epo:hasMainClassification . \ No newline at end of file diff --git a/test/unit/__init__.py b/test/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/adapters/__init__.py b/test/unit/adapters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/adapters/stubs.py b/test/unit/adapters/stubs.py new file mode 100644 index 0000000..d2054bc --- /dev/null +++ b/test/unit/adapters/stubs.py @@ -0,0 +1,226 @@ +"""In-memory stub implementations of service ports for testing.""" + +from typing import Protocol, runtime_checkable + +from erspec.models.core import EntityMention + +from ere.adapters.rdf_mapper_port import RDFMapper +from ere.models.resolver import ( + ClusterId, + ClusterMembership, + Mention, + MentionId, + MentionLink, +) + + +# Import repos and linker from their actual modules to avoid circular imports +def _get_repository_types(): + """Lazy import to avoid circular dependency with services.__init__.""" + from ere.adapters import repositories + + return repositories + + +def _get_linker_type(): + """Lazy import to avoid circular dependency.""" + from ere.services import linker + + return linker + + +# Define base classes as protocols to avoid circular import + + +@runtime_checkable +class MentionRepository(Protocol): + """Protocol for mention repository.""" + + def save(self, mention: Mention) -> None: ... + def load_all(self) -> list[Mention]: ... + def count(self) -> int: ... + + +@runtime_checkable +class SimilarityRepository(Protocol): + """Protocol for similarity repository.""" + + def save_all(self, links: list[MentionLink]) -> None: ... + def count(self) -> int: ... + def find_for(self, mention_id: MentionId) -> list[MentionLink]: ... + + +@runtime_checkable +class ClusterRepository(Protocol): + """Protocol for cluster repository.""" + + def save(self, membership: ClusterMembership) -> None: ... + def find_cluster_of(self, mention_id: MentionId) -> ClusterId: ... + def count(self) -> int: ... + def get_all_memberships(self) -> dict[ClusterId, list[MentionId]]: ... + + +@runtime_checkable +class SimilarityLinker(Protocol): + """Protocol for similarity linker.""" + + def find_matches(self, mention: Mention) -> list[MentionLink]: ... + def register_mention(self, mention: Mention) -> None: ... + def train(self) -> None: ... + + +class InMemoryMentionRepository(MentionRepository): + """In-memory mention repository backed by a dict.""" + + def __init__(self): + self._mentions: dict[MentionId, Mention] = {} + + def save(self, mention: Mention) -> None: + self._mentions[mention.id] = mention + + def load_all(self) -> list[Mention]: + return list(self._mentions.values()) + + def find_by_id(self, mention_id: MentionId) -> Mention | None: + return self._mentions.get(mention_id) + + def count(self) -> int: + return len(self._mentions) + + +class InMemorySimilarityRepository(SimilarityRepository): + """In-memory similarity repository backed by a list.""" + + def __init__(self): + self._links: list[MentionLink] = [] + + def save_all(self, links: list[MentionLink]) -> None: + self._links.extend(links) + + def count(self) -> int: + return len(self._links) + + def find_for(self, mention_id: MentionId) -> list[MentionLink]: + """Find all links involving the given mention (either side).""" + return [ + link for link in self._links if mention_id in (link.left_id, link.right_id) + ] + + +class InMemoryClusterRepository(ClusterRepository): + """In-memory cluster repository backed by a dict.""" + + def __init__(self): + self._memberships: dict[MentionId, ClusterId] = {} + + def save(self, membership: ClusterMembership) -> None: + self._memberships[membership.mention_id] = membership.cluster_id + + def find_cluster_of(self, mention_id: MentionId) -> ClusterId: + if mention_id not in self._memberships: + raise KeyError(f"No cluster assignment for mention {mention_id}") + return self._memberships[mention_id] + + def count(self) -> int: + # Count distinct clusters, not membership entries + return len(set(self._memberships.values())) + + def get_all_memberships(self) -> dict[ClusterId, list[MentionId]]: + """Group memberships by cluster ID.""" + memberships: dict[ClusterId, list[MentionId]] = {} + for mention_id, cluster_id in self._memberships.items(): + if cluster_id not in memberships: + memberships[cluster_id] = [] + memberships[cluster_id].append(mention_id) + + # Sort member lists for determinism + for cluster_id, members in memberships.items(): + members.sort(key=lambda m: m.value) + + return memberships + + +class FixedSimilarityLinker(SimilarityLinker): + """ + In-memory linker for testing. + + Pre-configured with a similarity map keyed by frozenset of mention IDs. + Simulates Splink without actually training or scoring. + """ + + def __init__(self, similarity_map: dict[frozenset[str], float]): + """ + Initialize with a pre-configured similarity map. + + Args: + similarity_map: Dict keyed by frozenset({id1, id2}) with float scores. + Example: {frozenset(["m1", "m2"]): 0.95, ...} + """ + self._similarity_map = similarity_map + self._registered_mentions: dict[MentionId, Mention] = {} + + def find_matches(self, mention: Mention) -> list[MentionLink]: + """ + Find matches for a mention by looking up scores in the similarity map. + + Returns all links where this mention's ID (as a string) appears in the + frozenset key and the score is non-zero (simulating match_weight_threshold). + """ + links = [] + mention_id_str = mention.id.value + + for pair_set, score in self._similarity_map.items(): + pair_list = list(pair_set) + if len(pair_list) != 2: + continue + + id1_str, id2_str = pair_list[0], pair_list[1] + + if mention_id_str == id1_str: + other_id_str = id2_str + elif mention_id_str == id2_str: + other_id_str = id1_str + else: + continue + + # Check if other mention has been registered + other_id = MentionId(value=other_id_str) + if other_id in self._registered_mentions: + links.append( + MentionLink(left_id=mention.id, right_id=other_id, score=score) + ) + + return links + + def register_mention(self, mention: Mention) -> None: + """Add a mention to the search space.""" + self._registered_mentions[mention.id] = mention + + def train(self) -> None: + """No-op for fixed linker (scores are pre-configured).""" + pass + + +class StubRDFMapper(RDFMapper): + """ + RDFMapper stub for unit testing. + + Returns a pre-configured Mention without performing any RDF parsing. + Optionally raises a configured exception to test error paths. + """ + + def __init__( + self, + mention_to_return: Mention = None, + error: Exception = None, + ): + self._mention = mention_to_return or Mention( + id=MentionId(value="stub-mention-id"), + attributes={"legal_name": "Stub Corp", "country_code": "US"}, + ) + self._error = error + + def map_entity_mention_to_domain(self, entity_mention: EntityMention) -> Mention: + if self._error is not None: + raise self._error + return self._mention diff --git a/test/unit/adapters/test_adapter_factories.py b/test/unit/adapters/test_adapter_factories.py new file mode 100644 index 0000000..e339df4 --- /dev/null +++ b/test/unit/adapters/test_adapter_factories.py @@ -0,0 +1,18 @@ +"""Unit tests for adapters.factories: RDFMapper construction.""" + +from pathlib import Path + +from ere.adapters.factories import build_rdf_mapper +from ere.adapters.rdf_mapper_port import RDFMapper + +TEST_RDF_MAPPING = Path(__file__).parent.parent.parent / "resources" / "rdf_mapping.yaml" + + +def test_build_rdf_mapper_with_explicit_path_returns_mapper(): + mapper = build_rdf_mapper(rdf_mapping_path=TEST_RDF_MAPPING) + assert isinstance(mapper, RDFMapper) + + +def test_build_rdf_mapper_without_path_uses_default(): + mapper = build_rdf_mapper() + assert isinstance(mapper, RDFMapper) diff --git a/test/unit/adapters/test_duckdb_adapters.py b/test/unit/adapters/test_duckdb_adapters.py new file mode 100644 index 0000000..fa6cb4b --- /dev/null +++ b/test/unit/adapters/test_duckdb_adapters.py @@ -0,0 +1,272 @@ +"""Integration tests for DuckDB adapters (resolver layer + DuckDB).""" + +import pytest +import duckdb + +# Import from submodules directly to avoid circular imports in __init__ +from ere.adapters.duckdb_repositories import ( + DuckDBClusterRepository, + DuckDBMentionRepository, + DuckDBSimilarityRepository, +) +from ere.adapters.duckdb_schema import init_schema +from ere.models.resolver import ( + ClusterId, + Mention, + MentionId, +) +from ere.services.entity_resolution_service import EntityResolver +from ere.services.resolver_config import DuckDBConfig, ResolverConfig +from .stubs import FixedSimilarityLinker + +# Avoid importing from ere.services.__init__ which has circular import +# The services are imported directly from their modules above + + +@pytest.fixture +def entity_fields(): + """Standard entity fields for tests.""" + return ["legal_name", "country_code"] + + +@pytest.fixture +def con(entity_fields): + """In-memory DuckDB connection with initialized schema.""" + c = duckdb.connect(":memory:") + init_schema(c, entity_fields) + return c + + +@pytest.fixture +def config(): + """Default config for tests.""" + return ResolverConfig( + threshold=0.8, + match_weight_threshold=-10, + top_n=100, + cache_strategy="tf_incremental", + auto_train_threshold=0, + entity_fields=["legal_name", "country_code"], + duckdb=DuckDBConfig(type="in-memory", path=":memory:"), + ) + + +@pytest.fixture +def service(con, entity_fields, config): + """Create a resolver with DuckDB adapters.""" + mention_repo = DuckDBMentionRepository(con, entity_fields) + similarity_repo = DuckDBSimilarityRepository(con) + cluster_repo = DuckDBClusterRepository(con) + linker = FixedSimilarityLinker(similarity_map={}) + + return EntityResolver( + mention_repo=mention_repo, + similarity_repo=similarity_repo, + cluster_repo=cluster_repo, + linker=linker, + config=config, + ) + + +# =============================================================================== +# Integration tests +# =============================================================================== + + +def test_resolve_first_mention_persists_to_db(service, con): + """ + Resolve one mention; assert mentions table has 1 row and clusters table + has 1 row; assert state returns mention_count=1, cluster_count=1. + """ + mention = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme Corp", "country_code": "US"}, + ) + + result = service.resolve(mention) + + # Check database persistence + mention_count = con.execute("SELECT COUNT(*) FROM mentions").fetchone()[0] + assert mention_count == 1 + + cluster_count = con.execute( + "SELECT COUNT(DISTINCT cluster_id) FROM clusters" + ).fetchone()[0] + assert cluster_count == 1 + + # Check state + state = service.state() + assert state.mention_count == 1 + assert state.cluster_count == 1 + + # Verify result + assert result.top.cluster_id.value == "m1" + assert result.top.score == 0.0 + + +def test_resolve_strong_match_joins_cluster_in_db(service, con): + """ + Resolve m1, then m2 with score=0.95; assert clusters table shows both + in cluster "m1"; assert state cluster_count=1. + """ + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + + # Set up linker to return high score + service._linker._similarity_map = {frozenset(["m1", "m2"]): 0.95} + + service.resolve(m1) + result2 = service.resolve(m2) + + # Check state + state = service.state() + assert state.mention_count == 2 + assert state.cluster_count == 1 # Both in same cluster + + # m2 should join m1's cluster + assert result2.top.cluster_id.value == "m1" + assert result2.top.score == pytest.approx(0.95, abs=0.01) + + +def test_resolve_weak_match_creates_separate_cluster(service, con): + """ + Resolve m1, then m2 with score=0.5 (below threshold 0.8); + assert two separate clusters created. + + Note: match_weight_threshold filters which links are stored. Even if a + match score is below the clustering threshold, it may still be stored if + it's above match_weight_threshold. But clustering assignment uses the + clustering threshold parameter. + """ + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Similar but different", "country_code": "US"}, + ) + + # Linker returns score below clustering threshold (0.8) + # but above match_weight_threshold (-10), so link is stored + service._linker._similarity_map = {frozenset(["m1", "m2"]): 0.5} + + service.resolve(m1) + result2 = service.resolve(m2) + + # With score 0.5 < threshold 0.8, m2 should create its own cluster + # But the link is still stored in similarities (for genCand output) + state = service.state() + assert state.mention_count == 2 + assert state.cluster_count == 2 # Separate clusters due to threshold + + # m2 is assigned to cluster "m2" (own cluster) + # genCand returns candidates sorted by score + # Top candidate will be m1 (score 0.5 via link) not m2 (score 0.0 own cluster) + assert len(result2.candidates) >= 2 + # m2's own cluster should be in the candidates (as lower-scoring option) + cluster_ids = [c.cluster_id.value for c in result2.candidates] + assert "m2" in cluster_ids + + +def test_resolve_no_match_creates_singleton_cluster(service, con): + """ + Resolve m1, then m2 with no similarity score; m2 creates singleton cluster. + """ + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Completely Different", "country_code": "UK"}, + ) + + # No similarity map entry = no match + service.resolve(m1) + result2 = service.resolve(m2) + + # Check state + state = service.state() + assert state.mention_count == 2 + assert state.cluster_count == 2 + + # m2 is its own cluster (singleton) + assert result2.top.cluster_id.value == "m2" + + +def test_state_returns_correct_counts(service, con): + """Verify that service.state() returns accurate counts.""" + m1 = Mention( + id=MentionId(value="m1"), attributes={"legal_name": "A", "country_code": "US"} + ) + m2 = Mention( + id=MentionId(value="m2"), attributes={"legal_name": "B", "country_code": "US"} + ) + + service._linker._similarity_map = {frozenset(["m1", "m2"]): 0.9} + + service.resolve(m1) + service.resolve(m2) + + state = service.state() + assert state.mention_count == 2 + assert state.cluster_count == 1 + assert state.similarity_count > 0 + + +def test_cluster_membership_mapping(service, con): + """Verify cluster_membership dict is correctly structured.""" + m1 = Mention( + id=MentionId(value="m1"), attributes={"legal_name": "A", "country_code": "US"} + ) + m2 = Mention( + id=MentionId(value="m2"), attributes={"legal_name": "B", "country_code": "US"} + ) + + service._linker._similarity_map = {frozenset(["m1", "m2"]): 0.9} + + service.resolve(m1) + service.resolve(m2) + + state = service.state() + memberships = state.cluster_membership + + # Should have one cluster with both mentions + assert len(memberships) == 1 + cluster_id = list(memberships.keys())[0] + assert len(memberships[cluster_id]) == 2 + assert MentionId(value="m1") in memberships[cluster_id] + assert MentionId(value="m2") in memberships[cluster_id] + + +def test_mention_repository_load_all_returns_persisted_mentions(con, entity_fields): + """load_all should return all mentions previously saved.""" + repo = DuckDBMentionRepository(con, entity_fields) + m1 = Mention(id=MentionId(value="la1"), attributes={"legal_name": "Alpha", "country_code": "DE"}) + m2 = Mention(id=MentionId(value="la2"), attributes={"legal_name": "Beta", "country_code": "FR"}) + + repo.save(m1) + repo.save(m2) + + loaded = repo.load_all() + + assert len(loaded) == 2 + ids = {m.id.value for m in loaded} + assert ids == {"la1", "la2"} + + +def test_similarity_repository_save_all_empty_is_noop(con): + """save_all with an empty list should not raise and not write any rows.""" + repo = DuckDBSimilarityRepository(con) + + repo.save_all([]) # must not raise + + count = con.execute("SELECT COUNT(*) FROM similarities").fetchone()[0] + assert count == 0 diff --git a/test/unit/adapters/test_redis_client.py b/test/unit/adapters/test_redis_client.py new file mode 100644 index 0000000..901d028 --- /dev/null +++ b/test/unit/adapters/test_redis_client.py @@ -0,0 +1,101 @@ +"""Unit tests for ere.adapters.redis_client.RedisConnectionConfig.""" + +from unittest.mock import MagicMock, patch + +from ere.adapters.redis_client import RedisConnectionConfig + + +class TestFromEnvDefaults: + def test_defaults_when_no_env_vars(self, monkeypatch): + for key in ("REDIS_HOST", "REDIS_PORT", "REDIS_DB", "REDIS_PASSWORD", "REDIS_TLS"): + monkeypatch.delenv(key, raising=False) + + cfg = RedisConnectionConfig.from_env() + + assert cfg.host == "localhost" + assert cfg.port == 6379 + assert cfg.db == 0 + assert cfg.password is None + assert cfg.tls is False + + def test_reads_redis_tls_true(self, monkeypatch): + monkeypatch.setenv("REDIS_TLS", "true") + + cfg = RedisConnectionConfig.from_env() + + assert cfg.tls is True + + def test_reads_redis_tls_case_insensitive(self, monkeypatch): + monkeypatch.setenv("REDIS_TLS", "True") + + cfg = RedisConnectionConfig.from_env() + + assert cfg.tls is True + + def test_reads_host_port_db(self, monkeypatch): + monkeypatch.setenv("REDIS_HOST", "redis.example.com") + monkeypatch.setenv("REDIS_PORT", "6380") + monkeypatch.setenv("REDIS_DB", "2") + + cfg = RedisConnectionConfig.from_env() + + assert cfg.host == "redis.example.com" + assert cfg.port == 6380 + assert cfg.db == 2 + + +class TestCreateClient: + def test_ssl_false_by_default(self, monkeypatch): + monkeypatch.delenv("REDIS_TLS", raising=False) + cfg = RedisConnectionConfig.from_env() + + with patch("ere.adapters.redis_client.redis.Redis") as mock_redis_cls: + mock_redis_cls.return_value = MagicMock() + cfg.create_client() + + _, kwargs = mock_redis_cls.call_args + assert kwargs["ssl"] is False + + def test_ssl_true_when_tls_enabled(self, monkeypatch): + monkeypatch.setenv("REDIS_TLS", "true") + cfg = RedisConnectionConfig.from_env() + + with patch("ere.adapters.redis_client.redis.Redis") as mock_redis_cls: + mock_redis_cls.return_value = MagicMock() + cfg.create_client() + + _, kwargs = mock_redis_cls.call_args + assert kwargs["ssl"] is True + + def test_decode_responses_is_false(self, monkeypatch): + monkeypatch.delenv("REDIS_TLS", raising=False) + cfg = RedisConnectionConfig.from_env() + + with patch("ere.adapters.redis_client.redis.Redis") as mock_redis_cls: + mock_redis_cls.return_value = MagicMock() + cfg.create_client() + + _, kwargs = mock_redis_cls.call_args + assert kwargs["decode_responses"] is False + + def test_password_none_when_unset(self, monkeypatch): + monkeypatch.delenv("REDIS_PASSWORD", raising=False) + cfg = RedisConnectionConfig.from_env() + + with patch("ere.adapters.redis_client.redis.Redis") as mock_redis_cls: + mock_redis_cls.return_value = MagicMock() + cfg.create_client() + + _, kwargs = mock_redis_cls.call_args + assert kwargs["password"] is None + + def test_password_passed_to_redis_client(self, monkeypatch): + monkeypatch.setenv("REDIS_PASSWORD", "s3cr3t") + cfg = RedisConnectionConfig.from_env() + + with patch("ere.adapters.redis_client.redis.Redis") as mock_redis_cls: + mock_redis_cls.return_value = MagicMock() + cfg.create_client() + + _, kwargs = mock_redis_cls.call_args + assert kwargs["password"] == "s3cr3t" \ No newline at end of file diff --git a/test/unit/adapters/test_utils.py b/test/unit/adapters/test_utils.py new file mode 100644 index 0000000..80fb431 --- /dev/null +++ b/test/unit/adapters/test_utils.py @@ -0,0 +1,74 @@ +"""Unit tests for adapters.utils: message parsing utilities.""" + +import json +from datetime import datetime, timezone + +import pytest +from erspec.models.core import EntityMention, EntityMentionIdentifier +from erspec.models.ere import ( + EREErrorResponse, + EntityMentionResolutionRequest, + EntityMentionResolutionResponse, +) +from linkml_runtime.dumpers import JSONDumper + +from ere.adapters.utils import ( + get_message_object, + get_request_from_message, + get_response_from_message, +) + +_dumper = JSONDumper() + + +def _make_request(request_id: str = "utils-test-001") -> EntityMentionResolutionRequest: + return EntityMentionResolutionRequest( + entity_mention=EntityMention( + identifiedBy=EntityMentionIdentifier( + request_id=request_id, + source_id="utils-test-src", + entity_type="http://test.org/Org", + ), + content_type="text/turtle", + content="<>", + ), + ere_request_id=request_id, + timestamp=datetime.now(timezone.utc).isoformat(), + ) + + +def _serialise(obj) -> bytes: + return _dumper.dumps(obj).encode("utf-8") + + +def test_get_request_from_message_returns_request(): + raw = _serialise(_make_request("req-parse-01")) + result = get_request_from_message(raw) + assert isinstance(result, EntityMentionResolutionRequest) + assert result.ere_request_id == "req-parse-01" + + +def test_get_response_from_message_returns_error_response(): + response = EREErrorResponse( + ere_request_id="resp-parse-01", + error_type="TestError", + error_title="Test", + error_detail="detail", + timestamp=datetime.now(timezone.utc).isoformat(), + ) + raw = _serialise(response) + result = get_response_from_message(raw) + assert isinstance(result, EREErrorResponse) + assert result.ere_request_id == "resp-parse-01" + + +def test_get_message_object_raises_on_missing_type(): + raw = json.dumps({"ere_request_id": "no-type"}).encode("utf-8") + with pytest.raises(ValueError, match="message without 'type' field"): + get_message_object(raw, {}) + + +def test_get_message_object_raises_on_unsupported_type(): + raw = json.dumps({"type": "UnknownClass", "ere_request_id": "x"}).encode("utf-8") + with pytest.raises(ValueError, match='unsupported message class: "UnknownClass"'): + get_message_object(raw, {}) diff --git a/test/unit/entrypoints/__init__.py b/test/unit/entrypoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/entrypoints/test_queue_worker.py b/test/unit/entrypoints/test_queue_worker.py new file mode 100644 index 0000000..b55f143 --- /dev/null +++ b/test/unit/entrypoints/test_queue_worker.py @@ -0,0 +1,124 @@ +"""Unit tests for RedisQueueWorker entrypoint (mocked Redis and service).""" + +import json +from datetime import datetime, timezone +from unittest.mock import MagicMock + +import pytest +from erspec.models.core import EntityMention, EntityMentionIdentifier +from erspec.models.ere import ( + EREErrorResponse, + EntityMentionResolutionRequest, + EntityMentionResolutionResponse, +) +from linkml_runtime.dumpers import JSONDumper + +from ere.entrypoints.queue_worker import RedisQueueWorker + +_dumper = JSONDumper() + + +def _make_request(request_id: str = "qw-test-001") -> EntityMentionResolutionRequest: + return EntityMentionResolutionRequest( + entity_mention=EntityMention( + identifiedBy=EntityMentionIdentifier( + request_id=request_id, + source_id="qw-src", + entity_type="http://test.org/Org", + ), + content_type="text/turtle", + content="<>", + ), + ere_request_id=request_id, + timestamp=datetime.now(timezone.utc).isoformat(), + ) + + +def _make_response(request_id: str = "qw-test-001") -> EntityMentionResolutionResponse: + return EntityMentionResolutionResponse( + entity_mention_id=EntityMentionIdentifier( + request_id=request_id, + source_id="qw-src", + entity_type="http://test.org/Org", + ), + candidates=[], + ere_request_id=request_id, + timestamp=datetime.now(timezone.utc).isoformat(), + ) + + +@pytest.fixture +def mock_redis(): + return MagicMock() + + +@pytest.fixture +def mock_service(): + return MagicMock() + + +@pytest.fixture +def worker(mock_redis, mock_service) -> RedisQueueWorker: + return RedisQueueWorker( + redis_client=mock_redis, + entity_resolution_service=mock_service, + request_queue="ere_requests", + response_queue="ere_responses", + queue_timeout=1, + ) + + +def test_process_single_message_returns_false_on_timeout(worker, mock_redis): + mock_redis.brpop.return_value = None + + result = worker.process_single_message() + + assert result is False + + +def test_process_single_message_returns_true_on_success(worker, mock_redis, mock_service): + request = _make_request("qw-happy") + raw_msg = _dumper.dumps(request).encode("utf-8") + mock_redis.brpop.return_value = ("ere_requests", raw_msg) + mock_service.process_request.return_value = _make_response("qw-happy") + + result = worker.process_single_message() + + assert result is True + mock_service.process_request.assert_called_once() + mock_redis.lpush.assert_called_once() + + +def test_process_single_message_sends_error_response_on_parse_failure( + worker, mock_redis, mock_service +): + mock_redis.brpop.return_value = ("ere_requests", b"not valid json at all") + + result = worker.process_single_message() + + assert result is True + mock_redis.lpush.assert_called_once() + pushed_payload = mock_redis.lpush.call_args[0][1] + pushed_json = json.loads(pushed_payload) + assert pushed_json.get("error_type") == "ProcessingError" + + +def test_send_response_logs_error_on_redis_failure(worker, mock_redis): + mock_redis.lpush.side_effect = ConnectionError("redis down") + response = EREErrorResponse( + ere_request_id="err-resp", + error_type="TestError", + error_title="Test", + error_detail="detail", + timestamp=datetime.now(timezone.utc).isoformat(), + ) + worker._send_response(response) # must not raise + + +def test_build_error_response_returns_ere_error_response(): + response = RedisQueueWorker._build_error_response("something broke", "req-err") + + assert isinstance(response, EREErrorResponse) + assert response.ere_request_id == "req-err" + assert response.error_type == "ProcessingError" + assert "something broke" in response.error_detail diff --git a/test/unit/services/__init__.py b/test/unit/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/services/test_entity_resolution_service.py b/test/unit/services/test_entity_resolution_service.py new file mode 100644 index 0000000..617cd42 --- /dev/null +++ b/test/unit/services/test_entity_resolution_service.py @@ -0,0 +1,601 @@ +"""Unit tests for EntityResolver and EntityResolutionService (no DuckDB, no Splink).""" + +import pytest +from datetime import datetime, timezone + +from erspec.models.core import EntityMention, EntityMentionIdentifier +from erspec.models.ere import ( + EREErrorResponse, + EntityMentionResolutionRequest, + EntityMentionResolutionResponse, +) + +from ere.models.resolver import ( + ClusterId, + Mention, + MentionId, + MentionLink, +) +from ere.services.entity_resolution_service import ( + EntityResolutionService, + EntityResolver, + resolve_entity_mention, +) +from ere.services.resolver_config import DuckDBConfig, ResolverConfig +from test.unit.adapters.stubs import ( + FixedSimilarityLinker, + InMemoryClusterRepository, + InMemoryMentionRepository, + InMemorySimilarityRepository, + StubRDFMapper, +) + + +@pytest.fixture +def config() -> ResolverConfig: + """Default config for tests.""" + return ResolverConfig( + threshold=0.8, + match_weight_threshold=-10, + top_n=100, + cache_strategy="tf_incremental", + entity_fields=["legal_name", "country_code"], + duckdb=DuckDBConfig(type="in-memory", path=":memory:"), + ) + + +@pytest.fixture +def service(config: ResolverConfig) -> EntityResolver: + """Create a resolver with in-memory stubs.""" + mention_repo = InMemoryMentionRepository() + similarity_repo = InMemorySimilarityRepository() + cluster_repo = InMemoryClusterRepository() + linker = FixedSimilarityLinker(similarity_map={}) + + return EntityResolver( + mention_repo=mention_repo, + similarity_repo=similarity_repo, + cluster_repo=cluster_repo, + linker=linker, + config=config, + ) + + +# =============================================================================== +# Core algorithm tests +# =============================================================================== + + +def test_first_mention_is_singleton(service): + """Resolving the first mention should create a singleton cluster.""" + mention = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme Corp", "country_code": "US"}, + ) + + result = service.resolve(mention) + + # Result should have one candidate: the mention's own cluster + assert len(result.candidates) == 1 + assert result.top.cluster_id.value == "m1" + assert result.top.score == 0.0 + + # State should reflect the mention + state = service.state() + assert state.mention_count == 1 + assert state.cluster_count == 1 + assert "m1" in [m.value for m in state.cluster_membership[ClusterId(value="m1")]] + + +def test_strong_match_joins_cluster(service): + """A mention matching >= threshold should join the best match's cluster.""" + # Resolve m1 first + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + result1 = service.resolve(m1) + assert result1.top.cluster_id.value == "m1" + + # Now resolve m2 with strong match to m1 + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Acme Corp", "country_code": "US"}, + ) + + # Set up the linker to return a strong match (m1, m2, 0.95) + service._linker = FixedSimilarityLinker( + similarity_map={frozenset(["m1", "m2"]): 0.95} + ) + service._linker.register_mention(m1) + + result2 = service.resolve(m2) + + # m2 should join m1's cluster (cluster "m1") + assert result2.top.cluster_id.value == "m1" + assert result2.top.score == pytest.approx(0.95, abs=0.01) + + # State should show both in cluster m1 + state = service.state() + assert state.mention_count == 2 + assert state.cluster_count == 1 # Still one cluster + cluster_m1 = state.cluster_membership[ClusterId(value="m1")] + assert len(cluster_m1) == 2 + assert set(m.value for m in cluster_m1) == {"m1", "m2"} + + +def test_below_threshold_becomes_singleton(service): + """A mention with only weak matches (< threshold) should become singleton cluster assignment.""" + # Resolve m1 first + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + service.resolve(m1) + + # Resolve m2 with weak match to m1 + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "ACME Inc", "country_code": "US"}, + ) + + # Set up weak match (0.7 < threshold 0.8) + service._linker = FixedSimilarityLinker( + similarity_map={frozenset(["m1", "m2"]): 0.7} + ) + service._linker.register_mention(m1) + + result2 = service.resolve(m2) + + # m2 should be assigned to its own cluster (cluster "m2"), + # but genCand still includes m1's cluster (via the below-threshold link) + assert ( + result2.top.cluster_id.value == "m1" + ) # Still top by score, but own cluster also present + assert result2.top.score == pytest.approx(0.7, abs=0.01) + + # Verify the new invariant: own cluster is always included + assert len(result2.candidates) == 2 + assert result2.candidates[1].cluster_id.value == "m2" + assert result2.candidates[1].score == 0.0 + + # State should show two clusters (m2 was assigned to its own cluster "m2") + state = service.state() + assert state.mention_count == 2 + assert state.cluster_count == 2 # Two separate clusters + assert set(state.cluster_membership.keys()) == { + ClusterId(value="m1"), + ClusterId(value="m2"), + } + + +def test_gen_cand_includes_below_threshold_links(service): + """ + If a mention has a below-threshold link to a cluster, that cluster + should appear in the candidates list. + + This tests the bridge case: a mention may not join a cluster (score < THR) + but that cluster should still appear in genCand output. + """ + # Resolve m1 and m3 in cluster 1, m3 in cluster 3 + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m3 = Mention( + id=MentionId(value="m3"), + attributes={"legal_name": "Globex", "country_code": "US"}, + ) + service.resolve(m1) + service.resolve(m3) # m3 forms its own cluster + + # Resolve m2 with: + # - strong link (0.85) to m1 (cluster "m1") -> joins cluster "m1" + # - weak link (0.7) to m3 (cluster "m3") -> below threshold + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Acme Corp", "country_code": "US"}, + ) + + service._linker = FixedSimilarityLinker( + similarity_map={ + frozenset(["m1", "m2"]): 0.85, # strong + frozenset(["m2", "m3"]): 0.7, # weak + } + ) + service._linker.register_mention(m1) + service._linker.register_mention(m3) + + result = service.resolve(m2) + + # Result should include both clusters + cluster_ids = {c.cluster_id.value for c in result.candidates} + assert cluster_ids == {"m1", "m3"} + + # m1 should be first (higher score) + assert result.top.cluster_id.value == "m1" + assert result.top.score == pytest.approx(0.85, abs=0.01) + + +def test_gen_cand_groups_by_cluster(service): + """ + If a mention has multiple links to members of the same cluster, + genCand should group them and use the max similarity as the cluster score. + """ + # Cluster 1: m1, m2 + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Acme Corp", "country_code": "US"}, + ) + service.resolve(m1) + service._linker = FixedSimilarityLinker({frozenset(["m1", "m2"]): 0.95}) + service._linker.register_mention(m1) + service.resolve(m2) + + # m3 has weak links to both m1 (0.75) and m2 (0.85) in the same cluster + m3 = Mention( + id=MentionId(value="m3"), + attributes={"legal_name": "Acme Industries", "country_code": "US"}, + ) + + service._linker = FixedSimilarityLinker( + similarity_map={ + frozenset(["m1", "m2"]): 0.95, + frozenset(["m1", "m3"]): 0.75, # to m1 + frozenset(["m2", "m3"]): 0.85, # to m2, same cluster + } + ) + service._linker.register_mention(m1) + service._linker.register_mention(m2) + + result = service.resolve(m3) + + # Result should have one candidate: cluster m1 with max score (0.85) + assert len(result.candidates) == 1 + assert result.top.cluster_id.value == "m1" + assert result.top.score == pytest.approx(0.85, abs=0.01) + + +# =============================================================================== +# Training and state management +# =============================================================================== + + +def test_train_can_be_called_anytime(service): + """train() should succeed even with very few mentions (uses cold-start defaults).""" + # Add just 1 mention + mention = Mention( + id=MentionId(value="m1"), + attributes={ + "legal_name": "Company 1", + "country_code": "US", + }, + ) + service.resolve(mention) + + # train() should succeed (linker is a no-op stub, uses cold-start) + service.train() # Should not raise + + +def test_auto_training_triggers_at_threshold(service): + """ + Auto-training should trigger non-blocking when mention count reaches threshold. + + We use a spy wrapper to count train() calls on the linker. + """ + # Create config with low threshold (3 mentions) + config = ResolverConfig( + threshold=0.8, + match_weight_threshold=-10, + top_n=100, + cache_strategy="tf_incremental", + auto_train_threshold=3, + entity_fields=["legal_name", "country_code"], + duckdb=DuckDBConfig(type="in-memory", path=":memory:"), + ) + + mention_repo = InMemoryMentionRepository() + similarity_repo = InMemorySimilarityRepository() + cluster_repo = InMemoryClusterRepository() + + # Wrap linker with a call counter + base_linker = FixedSimilarityLinker(similarity_map={}) + call_count = {"train": 0} + original_train = base_linker.train + + def counting_train(): + call_count["train"] += 1 + return original_train() + + base_linker.train = counting_train + + service = EntityResolver( + mention_repo=mention_repo, + similarity_repo=similarity_repo, + cluster_repo=cluster_repo, + linker=base_linker, + config=config, + ) + + # Resolve 3 mentions: at the 3rd, training should trigger + for i in range(3): + mention = Mention( + id=MentionId(value=f"m{i}"), + attributes={ + "legal_name": f"Company {i}", + "country_code": "US", + }, + ) + service.resolve(mention) + service._linker.register_mention(mention) + + # After resolving the 3rd mention, train should have been called once + assert call_count["train"] == 1 + + +def test_state_reflects_mentions(service): + """State should reflect all resolved mentions.""" + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Acme Corp", "country_code": "US"}, + ) + + service.resolve(m1) + state1 = service.state() + assert state1.mention_count == 1 + + service._linker = FixedSimilarityLinker({frozenset(["m1", "m2"]): 0.95}) + service._linker.register_mention(m1) + service.resolve(m2) + state2 = service.state() + assert state2.mention_count == 2 + + +def test_state_reflects_clusters(service): + """State should reflect cluster membership.""" + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + service.resolve(m1) + + state = service.state() + assert state.cluster_count == 1 + assert ClusterId(value="m1") in state.cluster_membership + assert state.cluster_membership[ClusterId(value="m1")] == [MentionId(value="m1")] + + +def test_state_reflects_similarities(service): + """State should reflect all stored similarities.""" + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Acme Corp", "country_code": "US"}, + ) + + service.resolve(m1) + + state1 = service.state() + assert state1.similarity_count == 0 + + service._linker = FixedSimilarityLinker({frozenset(["m1", "m2"]): 0.95}) + service._linker.register_mention(m1) + service.resolve(m2) + + state2 = service.state() + # One similarity link: (m1, m2, 0.95) + assert state2.similarity_count == 1 + + +# =============================================================================== +# Edge cases and invariants +# =============================================================================== + + +def test_resolution_result_never_empty(service): + """Every resolve() call should return non-empty ResolutionResult.""" + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + result = service.resolve(m1) + + assert len(result.candidates) >= 1 + + +def test_resolution_result_always_top_n_pruned(service): + """Results should be pruned to top_n.""" + # Set a small top_n + config_small = ResolverConfig( + threshold=0.5, + match_weight_threshold=-10, + top_n=2, # Small limit + entity_fields=["legal_name", "country_code"], + duckdb=DuckDBConfig(type="in-memory", path=":memory:"), + ) + + mention_repo = InMemoryMentionRepository() + similarity_repo = InMemorySimilarityRepository() + cluster_repo = InMemoryClusterRepository() + + # Set up linker to return links to 5 different clusters + linker = FixedSimilarityLinker( + similarity_map={ + frozenset(["m1", "m2"]): 0.9, + frozenset(["m1", "m3"]): 0.8, + frozenset(["m1", "m4"]): 0.7, + frozenset(["m1", "m5"]): 0.6, + frozenset(["m1", "m6"]): 0.5, + } + ) + + service = EntityResolver( + mention_repo=mention_repo, + similarity_repo=similarity_repo, + cluster_repo=cluster_repo, + linker=linker, + config=config_small, + ) + + # Add 5 mentions to different clusters + for i in range(2, 7): + mention = Mention( + id=MentionId(value=f"m{i}"), + attributes={"legal_name": f"Company {i}", "country_code": "US"}, + ) + service.resolve(mention) + + # Register all existing mentions with linker + for mention in service._mention_repo.load_all(): + linker.register_mention(mention) + + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Company 1", "country_code": "US"}, + ) + result = service.resolve(m1) + + # Result should be pruned to top_n (2) + assert len(result.candidates) <= config_small.top_n + + +def test_multiple_independent_clusters(service): + """Mentions with no links should form independent clusters.""" + m1 = Mention( + id=MentionId(value="m1"), + attributes={"legal_name": "Acme", "country_code": "US"}, + ) + m2 = Mention( + id=MentionId(value="m2"), + attributes={"legal_name": "Globex", "country_code": "US"}, + ) + m3 = Mention( + id=MentionId(value="m3"), + attributes={"legal_name": "Initech", "country_code": "US"}, + ) + + # No links between any of them + service._linker = FixedSimilarityLinker(similarity_map={}) + + service.resolve(m1) + service._linker.register_mention(m1) + service.resolve(m2) + service._linker.register_mention(m2) + service.resolve(m3) + + state = service.state() + assert state.cluster_count == 3 + assert state.mention_count == 3 + + +# =============================================================================== +# resolve_entity_mention guard tests +# =============================================================================== + + +def test_resolve_entity_mention_raises_when_resolver_is_none(): + mention = EntityMention( + identifiedBy=EntityMentionIdentifier( + request_id="m1", + source_id="src", + entity_type="http://test.org/Org", + ), + content_type="text/turtle", + content="<>", + ) + with pytest.raises(ValueError, match="resolver must be provided"): + resolve_entity_mention(mention, resolver=None, mapper=StubRDFMapper()) + + +def test_resolve_entity_mention_raises_when_mapper_is_none(service): + mention = EntityMention( + identifiedBy=EntityMentionIdentifier( + request_id="m1", + source_id="src", + entity_type="http://test.org/Org", + ), + content_type="text/turtle", + content="<>", + ) + with pytest.raises(ValueError, match="mapper must be provided"): + resolve_entity_mention(mention, resolver=service, mapper=None) + + +# =============================================================================== +# EntityResolutionService tests +# =============================================================================== + + +@pytest.fixture +def stub_mapper() -> StubRDFMapper: + return StubRDFMapper() + + +@pytest.fixture +def resolution_service(service: EntityResolver, stub_mapper: StubRDFMapper) -> EntityResolutionService: + return EntityResolutionService(resolver=service, mapper=stub_mapper) + + +def _make_request(request_id: str = "req-001") -> EntityMentionResolutionRequest: + return EntityMentionResolutionRequest( + entity_mention=EntityMention( + identifiedBy=EntityMentionIdentifier( + request_id=request_id, + source_id="test-src", + entity_type="http://test.org/Org", + ), + content_type="text/turtle", + content="<>", + ), + ere_request_id=request_id, + timestamp=datetime.now(timezone.utc).isoformat(), + ) + + +def test_process_request_unsupported_type_returns_error_response(resolution_service): + class UnknownRequest: + ere_request_id = "unknown-001" + + response = resolution_service.process_request(UnknownRequest()) + + assert isinstance(response, EREErrorResponse) + assert response.error_type == "UnsupportedRequestType" + + +def test_process_request_happy_path_returns_resolution_response(resolution_service): + request = _make_request("req-happy") + + response = resolution_service.process_request(request) + + assert isinstance(response, EntityMentionResolutionResponse) + assert response.ere_request_id == "req-happy" + assert len(response.candidates) >= 1 + + +def test_process_request_mapper_error_returns_error_response(service: EntityResolver): + failing_mapper = StubRDFMapper(error=ValueError("RDF parse failure")) + svc = EntityResolutionService(resolver=service, mapper=failing_mapper) + + response = svc.process_request(_make_request("req-fail")) + + assert isinstance(response, EREErrorResponse) + assert response.error_type == "ValueError" + assert "RDF parse failure" in response.error_detail + + +def test_call_delegates_to_process_request(resolution_service): + request = _make_request("req-call") + response = resolution_service(request) + assert isinstance(response, EntityMentionResolutionResponse) + assert response.ere_request_id == "req-call" diff --git a/test/unit/services/test_services_factories.py b/test/unit/services/test_services_factories.py new file mode 100644 index 0000000..46398d8 --- /dev/null +++ b/test/unit/services/test_services_factories.py @@ -0,0 +1,67 @@ +"""Unit tests for services.factories: construction of resolver and service.""" + +from pathlib import Path + +import pytest +import yaml + +from ere.services.entity_resolution_service import EntityResolutionService, EntityResolver +from ere.services.factories import build_entity_resolution_service, build_entity_resolver +from test.unit.adapters.stubs import StubRDFMapper + +TEST_RESOLVER_CONFIG = Path(__file__).parent.parent.parent / "resources" / "resolver.yaml" + + +def test_build_entity_resolver_returns_entity_resolver(): + resolver = build_entity_resolver(resolver_config_path=TEST_RESOLVER_CONFIG) + assert isinstance(resolver, EntityResolver) + + +def test_build_entity_resolver_uses_default_config_when_no_path_given(): + resolver = build_entity_resolver() + assert isinstance(resolver, EntityResolver) + + +def test_build_entity_resolver_with_explicit_entity_fields(): + resolver = build_entity_resolver( + entity_fields=["legal_name"], + resolver_config_path=TEST_RESOLVER_CONFIG, + ) + assert isinstance(resolver, EntityResolver) + + +def test_build_entity_resolver_with_persistent_duckdb(tmp_path): + db_file = str(tmp_path / "test.duckdb") + with open(TEST_RESOLVER_CONFIG, encoding="utf-8") as f: + raw = yaml.safe_load(f) + raw["duckdb"] = {"type": "persistent", "path": db_file} + config = tmp_path / "persistent.yaml" + config.write_text(yaml.dump(raw), encoding="utf-8") + + resolver = build_entity_resolver(resolver_config_path=config, duckdb_path=db_file) + assert isinstance(resolver, EntityResolver) + + +def test_build_entity_resolver_raises_on_invalid_duckdb_type(tmp_path): + bad_config = tmp_path / "bad.yaml" + bad_config.write_text( + "threshold: 0.8\n" + "match_weight_threshold: -10\n" + "top_n: 10\n" + "entity_fields: [legal_name]\n" + "duckdb:\n" + " type: invalid_type\n" + " path: ':memory:'\n", + encoding="utf-8", + ) + with pytest.raises(ValueError, match="Invalid duckdb type"): + build_entity_resolver(resolver_config_path=bad_config) + + +def test_build_entity_resolution_service_returns_service(): + resolver = build_entity_resolver(resolver_config_path=TEST_RESOLVER_CONFIG) + mapper = StubRDFMapper() + + service = build_entity_resolution_service(resolver, mapper) + + assert isinstance(service, EntityResolutionService) diff --git a/test/unit/test_models.py b/test/unit/test_models.py new file mode 100644 index 0000000..d984596 --- /dev/null +++ b/test/unit/test_models.py @@ -0,0 +1,111 @@ +"""Unit tests for domain model edge cases (error paths and utility methods).""" + +import pytest +from unittest.mock import MagicMock, patch + +from ere.models.resolver import ClusterId, MentionId +from ere.models.resolver.cluster import CandidateCluster, ResolutionResult +from ere.models.resolver.similarity import MentionLink + + +# ============================================================================ +# MentionLink +# ============================================================================ + + +def test_mention_link_rejects_same_left_and_right_id(): + m = MentionId(value="x") + with pytest.raises(ValueError, match="left_id and right_id must differ"): + MentionLink(left_id=m, right_id=m, score=0.9) + + +def test_mention_link_other_returns_right_when_from_is_left(): + left = MentionId(value="a") + right = MentionId(value="b") + link = MentionLink(left_id=left, right_id=right, score=0.5) + assert link.other(left) == right + + +def test_mention_link_other_returns_left_when_from_is_right(): + left = MentionId(value="a") + right = MentionId(value="b") + link = MentionLink(left_id=left, right_id=right, score=0.5) + assert link.other(right) == left + + +def test_mention_link_other_raises_when_id_not_in_link(): + left = MentionId(value="a") + right = MentionId(value="b") + unknown = MentionId(value="z") + link = MentionLink(left_id=left, right_id=right, score=0.5) + with pytest.raises(ValueError): + link.other(unknown) + + +# ============================================================================ +# ResolutionResult / CandidateCluster +# ============================================================================ + + +def test_resolution_result_rejects_empty_candidates(): + with pytest.raises(ValueError, match="must be non-empty"): + ResolutionResult(candidates=()) + + +def test_candidate_cluster_as_tuple_returns_id_and_score(): + c = CandidateCluster(cluster_id=ClusterId(value="c1"), score=0.75) + assert c.as_tuple() == ("c1", 0.75) + + +def test_resolution_result_as_tuples_returns_list(): + candidates = ( + CandidateCluster(cluster_id=ClusterId(value="c1"), score=0.9), + CandidateCluster(cluster_id=ClusterId(value="c2"), score=0.6), + ) + result = ResolutionResult(candidates=candidates) + assert result.as_tuples() == [("c1", 0.9), ("c2", 0.6)] + + +# ============================================================================ +# app.main() failure paths +# ============================================================================ + + +def test_main_exits_when_redis_connection_fails(monkeypatch): + monkeypatch.setattr("sys.argv", ["ere"]) + with patch("redis.Redis") as mock_redis_cls, \ + patch("ere.entrypoints.app.configure_logging"): + mock_redis_cls.return_value.ping.side_effect = ConnectionError("no redis") + with pytest.raises(SystemExit) as exc: + from ere.entrypoints.app import main + main() + assert exc.value.code == 1 + + +def test_main_exits_when_service_build_fails(monkeypatch): + monkeypatch.setattr("sys.argv", ["ere"]) + with patch("redis.Redis") as mock_redis_cls, \ + patch("ere.entrypoints.app.configure_logging"), \ + patch("ere.entrypoints.app.build_entity_resolver", side_effect=RuntimeError("build fail")): + mock_redis_cls.return_value.ping.return_value = True + with pytest.raises(SystemExit) as exc: + from ere.entrypoints.app import main + main() + assert exc.value.code == 1 + + +def test_main_runs_loop_until_keyboard_interrupt(monkeypatch): + monkeypatch.setattr("sys.argv", ["ere"]) + mock_resolver = MagicMock() + mock_resolver._mention_repo._con = MagicMock() + + with patch("redis.Redis") as mock_redis_cls, \ + patch("ere.entrypoints.app.configure_logging"), \ + patch("ere.entrypoints.app.build_entity_resolver", return_value=mock_resolver), \ + patch("ere.entrypoints.app.build_rdf_mapper", return_value=MagicMock()), \ + patch("ere.entrypoints.app.build_entity_resolution_service", return_value=MagicMock()), \ + patch("ere.entrypoints.app.RedisQueueWorker") as mock_worker_cls: + mock_redis_cls.return_value.ping.return_value = True + mock_worker_cls.return_value.process_single_message.side_effect = KeyboardInterrupt() + from ere.entrypoints.app import main + main() # must return cleanly (KeyboardInterrupt caught internally) diff --git a/test/unit/utils/__init__.py b/test/unit/utils/__init__.py new file mode 100644 index 0000000..04dba96 --- /dev/null +++ b/test/unit/utils/__init__.py @@ -0,0 +1 @@ +# pylint: disable=disallowed-name # mirrors src/ere/utils/ package structure diff --git a/test/unit/utils/test_logging.py b/test/unit/utils/test_logging.py new file mode 100644 index 0000000..f84762c --- /dev/null +++ b/test/unit/utils/test_logging.py @@ -0,0 +1,52 @@ +"""Unit tests for utils.logging: log-level setup and TRACE level.""" + +import logging +from unittest.mock import patch + +from ere.utils.logging import TRACE_LEVEL_NUM, configure_logging + + +def test_configure_logging_passes_warning_level_to_basicconfig(): + with patch("logging.basicConfig") as mock_bc: + configure_logging("WARNING") + mock_bc.assert_called_once() + assert mock_bc.call_args[1]["level"] == logging.WARNING + + +def test_configure_logging_passes_trace_level_to_basicconfig(): + with patch("logging.basicConfig") as mock_bc: + configure_logging("TRACE") + mock_bc.assert_called_once() + assert mock_bc.call_args[1]["level"] == TRACE_LEVEL_NUM + + +def test_configure_logging_reads_env_var(monkeypatch): + monkeypatch.setenv("ERE_LOG_LEVEL", "ERROR") + with patch("logging.basicConfig") as mock_bc: + configure_logging() + assert mock_bc.call_args[1]["level"] == logging.ERROR + + +def test_configure_logging_defaults_to_info(monkeypatch): + monkeypatch.delenv("ERE_LOG_LEVEL", raising=False) + with patch("logging.basicConfig") as mock_bc: + configure_logging() + assert mock_bc.call_args[1]["level"] == logging.INFO + + +def test_trace_method_exists_on_logger(): + log = logging.getLogger("test.trace") + assert callable(getattr(log, "trace", None)) + + +def test_trace_method_logs_when_enabled(caplog): + log = logging.getLogger("test.trace.enabled") + with caplog.at_level(TRACE_LEVEL_NUM, logger="test.trace.enabled"): + log.trace("trace message sent") + assert "trace message sent" in caplog.text + + +def test_trace_method_does_not_log_when_disabled(): + log = logging.getLogger("test.trace.silent") + log.setLevel(logging.INFO) + log.trace("this should not explode") diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..f70414f --- /dev/null +++ b/tox.ini @@ -0,0 +1,125 @@ +# tox configuration for CI/CD environment orchestration +# ===================================================== +# tox manages isolated Python environments for reproducible, dependency-locked test runs. +# +# Three-environment model (matches Cosmic Python / Clean Code principles): +# py312 - Unit tests + coverage analysis +# architecture - Layer contract validation (import-linter) +# clean-code - Code quality checks (pylint + radon + xenon) +# +# Use: tox -e py312,architecture,clean-code (in CI) +# For local development, use: make test-unit (faster, uses your venv) + +[tox] +isolated_build = True +envlist = py312, architecture, clean-code +skip_missing_interpreters = True +package_root = src + +[testenv] +description = Base environment configuration +passenv = + HOME + PYTHONPATH + PYTHON* + REDIS_HOST + REDIS_PORT + REDIS_PASSWORD +setenv = + PYTHONPATH = {toxinidir}/src +allowlist_externals = + poetry +commands_pre = + poetry -C {toxinidir}/src sync + +#============================================================================= +# py312: Unit Tests + Coverage +#============================================================================= + +[testenv:py312] +description = Run unit tests with coverage analysis +commands = + pytest test -m "not integration" \ + --cov=src/ere \ + --cov-report=term \ + --cov-report=term-missing:skip-covered \ + --cov-report=xml:{toxinidir}/coverage.xml \ + -v \ + {posargs} + +[coverage:run] +branch = True +source = src/ere +relative_files = True +omit = src/demo/* + +[coverage:report] +precision = 2 +show_missing = True +skip_empty = True +sort = Cover +exclude_lines = + pragma: no cover + def __repr__ + if self\.debug + raise AssertionError + raise NotImplementedError + if __name__ == .__main__.: + +# Fail if coverage is below 80% +fail_under = 80 + +[coverage:xml] +output = coverage.xml +# Note: actual output path is set explicitly via --cov-report=xml:{toxinidir}/coverage.xml + +#============================================================================= +# pytest: Shared Configuration +#============================================================================= + +[pytest] +testpaths = test +python_files = test_*.py +python_functions = test_* +addopts = -v --strict-markers +markers = + slow: marks tests as slow (deselect with '-m "not slow"') + integration: marks tests as integration tests + +#============================================================================= +# architecture: Layer Contract Validation (Cosmic Python) +#============================================================================= + +[testenv:architecture] +description = Validate architectural boundaries (import-linter / Cosmic Python) +deps = import-linter>=2.3 +commands = + lint-imports + +#============================================================================= +# clean-code: Code Quality (SOLID Principles) +#============================================================================= + +[testenv:clean-code] +description = Code quality checks: pylint (style) + radon (complexity) + xenon (enforcement) +deps = + pylint>=3.3.4 + radon>=6.0.1 + xenon>=0.9.3 +commands = + # Pylint: Check code style, naming conventions, SOLID principles + pylint --rcfile=.pylintrc src/ere/ test/ + + # Radon: Cyclomatic Complexity - show report + radon cc src/ere/ -a --total-average --show-complexity + + # Radon: Maintainability Index - higher is better (A=best, C=worst) + radon mi src/ere/ --show --sort + + # Xenon: Enforce complexity thresholds and fail if exceeded + # A = 1-5 (simple), B = 6-10 (manageable), C = 11-20 (complex) + xenon src/ere/ \ + --max-absolute C \ + --max-modules C \ + --max-average B \ + --exclude "*test*,*__pycache__*"