diff --git a/node/.env.example b/node/.env.example new file mode 100644 index 0000000..7568cbf --- /dev/null +++ b/node/.env.example @@ -0,0 +1,4 @@ +# Webhook configuration for the Factorio signal watcher + +INGEST_BASE_URL=http://localhost:3000 +API_TOKEN=password \ No newline at end of file diff --git a/node/.env.local b/node/.env.local new file mode 100644 index 0000000..4017130 --- /dev/null +++ b/node/.env.local @@ -0,0 +1,4 @@ +# Webhook configuration for the Factorio signal watcher + +INGEST_BASE_URL=http://localhost:3000 +API_TOKEN=change-me \ No newline at end of file diff --git a/node/package.json b/node/package.json index 2d03a5c..799fa2d 100644 --- a/node/package.json +++ b/node/package.json @@ -1,4 +1,5 @@ { + "type": "module", "dependencies": { "adm-zip": "^0.5.17" } diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/web/AGENTS.md b/web/AGENTS.md new file mode 100644 index 0000000..8bd0e39 --- /dev/null +++ b/web/AGENTS.md @@ -0,0 +1,5 @@ + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + diff --git a/web/CLAUDE.md b/web/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/web/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/web/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/web/app/api/alerts/[id]/route.ts b/web/app/api/alerts/[id]/route.ts new file mode 100644 index 0000000..1f2339b --- /dev/null +++ b/web/app/api/alerts/[id]/route.ts @@ -0,0 +1,32 @@ +import { NextRequest, NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; + +export const PUT = withAuth(async (req: NextRequest, { params }) => { + const { id } = await params; + const body = await req.json(); + const { item_key, item_key_is_regex, combinator, signal_type, condition, threshold, active } = body; + + const result = await pool.query( + `UPDATE alerts SET + item_key = COALESCE($1, item_key), + item_key_is_regex = COALESCE($2, item_key_is_regex), + combinator = $3, + signal_type = COALESCE($4, signal_type), + condition = COALESCE($5, condition), + threshold = COALESCE($6, threshold), + active = COALESCE($7, active) + WHERE id = $8 + RETURNING *`, + [item_key, item_key_is_regex, combinator, signal_type, condition, threshold, active, id], + ); + if (result.rowCount === 0) return NextResponse.json({ error: 'Not found' }, { status: 404 }); + return NextResponse.json(result.rows[0]); +}); + +export const DELETE = withAuth(async (_req: NextRequest, { params }) => { + const { id } = await params; + const result = await pool.query('DELETE FROM alerts WHERE id = $1', [id]); + if (result.rowCount === 0) return NextResponse.json({ error: 'Not found' }, { status: 404 }); + return NextResponse.json({ ok: true }); +}); \ No newline at end of file diff --git a/web/app/api/alerts/check/route.ts b/web/app/api/alerts/check/route.ts new file mode 100644 index 0000000..ac08790 --- /dev/null +++ b/web/app/api/alerts/check/route.ts @@ -0,0 +1,62 @@ +import { NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; +import { getServerLocaleMap } from '@/lib/localeServer'; +import { resolveName } from '@/lib/localization'; +import type { AlertConfig, TriggeredAlert } from '@/lib/types'; + +export const GET = withAuth(async () => { + const alertsResult = await pool.query( + `SELECT id, item_key, item_key_is_regex, combinator, signal_type, condition, threshold + FROM alerts WHERE active = true`, + ); + if (alertsResult.rows.length === 0) return NextResponse.json([]); + + const latestResult = await pool.query<{ + combinator: string; item_key: string; green: number; red: number; + }>( + `SELECT DISTINCT ON (combinator, item_key) combinator, item_key, green, red + FROM signals + ORDER BY combinator, item_key, real_time DESC`, + ); + + const localeMap = getServerLocaleMap(); + + const latestMap = new Map( + latestResult.rows.map(r => [`${r.combinator}::${r.item_key}`, r]), + ); + + const triggered: TriggeredAlert[] = []; + + for (const alert of alertsResult.rows) { + for (const [key, vals] of latestMap) { + const [combinator, item_key] = key.split('::'); + + let itemMatch: boolean; + if (alert.item_key_is_regex) { + try { + const re = new RegExp(alert.item_key, 'i'); + // Test against raw key and localized name + itemMatch = re.test(item_key) || re.test(resolveName(item_key, localeMap)); + } catch { + itemMatch = false; + } + } else { + itemMatch = item_key === alert.item_key; + } + + if (!itemMatch || (alert.combinator && combinator !== alert.combinator)) continue; + + const value = alert.signal_type === 'green' ? vals.green : vals.red; + const fired = alert.condition === 'above' ? value > alert.threshold : value < alert.threshold; + if (fired) triggered.push({ + ...alert, + current_value: value, + combinator_match: combinator, + matched_item_key: item_key, + }); + } + } + + return NextResponse.json(triggered); +}); \ No newline at end of file diff --git a/web/app/api/alerts/route.ts b/web/app/api/alerts/route.ts new file mode 100644 index 0000000..98a7387 --- /dev/null +++ b/web/app/api/alerts/route.ts @@ -0,0 +1,30 @@ +import { NextRequest, NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; + +export const GET = withAuth(async () => { + const result = await pool.query('SELECT * FROM alerts ORDER BY created_at DESC'); + return NextResponse.json(result.rows); +}); + +export const POST = withAuth(async (req: NextRequest) => { + const body = await req.json(); + const { + item_key, item_key_is_regex = false, + combinator = null, signal_type = 'green', condition, threshold, + } = body; + + if (!item_key || !condition || threshold === undefined) { + return NextResponse.json( + { error: 'item_key, condition, threshold required' }, + { status: 400 }, + ); + } + + const result = await pool.query( + `INSERT INTO alerts (item_key, item_key_is_regex, combinator, signal_type, condition, threshold) + VALUES ($1,$2,$3,$4,$5,$6) RETURNING *`, + [item_key, item_key_is_regex, combinator, signal_type, condition, threshold], + ); + return NextResponse.json(result.rows[0], { status: 201 }); +}); \ No newline at end of file diff --git a/web/app/api/charts/[id]/route.ts b/web/app/api/charts/[id]/route.ts new file mode 100644 index 0000000..322ac02 --- /dev/null +++ b/web/app/api/charts/[id]/route.ts @@ -0,0 +1,64 @@ +import { NextRequest, NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; + +export const PUT = withAuth(async (req: NextRequest, { params }) => { + const { id } = await params; + const body = await req.json(); + const { + title, pos_x, pos_y, width, height, + signal_type, chart_type, viz_type, + filter_items_regex, y_scale, + series_limit, order_by, + } = body; + + const hasFilterCombinators = 'filter_combinators' in body; + const hasFilterItems = 'filter_items' in body; + const hasFilterItemsExclude = 'filter_items_exclude' in body; + const hasYMin = 'y_min' in body; + const hasYMax = 'y_max' in body; + + const result = await pool.query( + `UPDATE charts SET + title = COALESCE($1, title), + pos_x = COALESCE($2, pos_x), + pos_y = COALESCE($3, pos_y), + width = COALESCE($4, width), + height = COALESCE($5, height), + signal_type = COALESCE($6, signal_type), + chart_type = COALESCE($7, chart_type), + viz_type = COALESCE($8, viz_type), + filter_combinators = CASE WHEN $9::boolean THEN $10::text[] ELSE filter_combinators END, + filter_items = CASE WHEN $11::boolean THEN $12::text[] ELSE filter_items END, + filter_items_exclude = CASE WHEN $13::boolean THEN $14::text[] ELSE filter_items_exclude END, + filter_items_regex = COALESCE($15, filter_items_regex), + y_min = CASE WHEN $16::boolean THEN $17::double precision ELSE y_min END, + y_max = CASE WHEN $18::boolean THEN $19::double precision ELSE y_max END, + y_scale = COALESCE($20, y_scale), + series_limit = COALESCE($21, series_limit), + order_by = COALESCE($22, order_by) + WHERE id = $23 + RETURNING *`, + [ + title, pos_x, pos_y, width, height, signal_type, chart_type, viz_type, + hasFilterCombinators, body.filter_combinators ?? null, + hasFilterItems, body.filter_items ?? null, + hasFilterItemsExclude, body.filter_items_exclude ?? null, + filter_items_regex, + hasYMin, body.y_min ?? null, + hasYMax, body.y_max ?? null, + y_scale, + series_limit, order_by, + id, + ], + ); + if (result.rowCount === 0) return NextResponse.json({ error: 'Not found' }, { status: 404 }); + return NextResponse.json(result.rows[0]); +}); + +export const DELETE = withAuth(async (_req: NextRequest, { params }) => { + const { id } = await params; + const result = await pool.query('DELETE FROM charts WHERE id = $1', [id]); + if (result.rowCount === 0) return NextResponse.json({ error: 'Not found' }, { status: 404 }); + return NextResponse.json({ ok: true }); +}); \ No newline at end of file diff --git a/web/app/api/charts/route.ts b/web/app/api/charts/route.ts new file mode 100644 index 0000000..167bf0f --- /dev/null +++ b/web/app/api/charts/route.ts @@ -0,0 +1,36 @@ +import { NextRequest, NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; + +export const GET = withAuth(async () => { + const result = await pool.query('SELECT * FROM charts ORDER BY pos_y ASC, pos_x ASC'); + return NextResponse.json(result.rows); +}); + +export const POST = withAuth(async (req: NextRequest) => { + const body = await req.json(); + const { + title, + pos_x = 0, pos_y = 0, width = 2, height = 4, + signal_type = 'both', chart_type = 'signals', viz_type = 'line', + filter_combinators = null, filter_items = null, + filter_items_exclude = null, filter_items_regex = false, + y_min = null, y_max = null, y_scale = 'linear', + series_limit = 20, order_by = 'time', + } = body; + + if (!title) return NextResponse.json({ error: 'title required' }, { status: 400 }); + + const result = await pool.query( + `INSERT INTO charts + (title,pos_x,pos_y,width,height,signal_type,chart_type,viz_type, + filter_combinators,filter_items,filter_items_exclude,filter_items_regex, + y_min,y_max,y_scale,series_limit,order_by) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) + RETURNING *`, + [title,pos_x,pos_y,width,height,signal_type,chart_type,viz_type, + filter_combinators,filter_items,filter_items_exclude,filter_items_regex, + y_min,y_max,y_scale,series_limit,order_by], + ); + return NextResponse.json(result.rows[0], { status: 201 }); +}); \ No newline at end of file diff --git a/web/app/api/ingest/[combinator]/route.ts b/web/app/api/ingest/[combinator]/route.ts new file mode 100644 index 0000000..f59e282 --- /dev/null +++ b/web/app/api/ingest/[combinator]/route.ts @@ -0,0 +1,71 @@ +import { NextRequest, NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; + +interface CircuitNetwork { + green: Record; + red: Record; +} + +interface IngestBody { + game_tick: number; + circuit_network: CircuitNetwork; + logistic_network: Record; +} + +export const POST = withAuth(async (req: NextRequest, { params }) => { + const { combinator } = await params; + + const mtimeHeader = req.headers.get('x-file-mtime'); + const realTime = mtimeHeader ? new Date(parseInt(mtimeHeader, 10)) : new Date(); + + let body: IngestBody; + try { + body = await req.json(); + } catch { + return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }); + } + + const { game_tick, circuit_network, logistic_network } = body; + if (typeof game_tick !== 'number') { + return NextResponse.json({ error: 'Missing game_tick' }, { status: 400 }); + } + + const green = circuit_network?.green ?? {}; + const red = circuit_network?.red ?? {}; + const logistic = logistic_network ?? {}; + const allKeys = new Set([...Object.keys(green), ...Object.keys(red), ...Object.keys(logistic)]); + + if (allKeys.size === 0) return NextResponse.json({ ok: true, rows: 0 }); + + const client = await pool.connect(); + try { + await client.query('BEGIN'); + + const values: unknown[] = []; + const placeholders: string[] = []; + let idx = 1; + for (const key of allKeys) { + placeholders.push(`($${idx++},$${idx++},$${idx++},$${idx++},$${idx++},$${idx++},$${idx++})`); + values.push(realTime, game_tick, combinator, key, green[key] ?? 0, red[key] ?? 0, logistic[key] ?? null); + } + + await client.query( + `INSERT INTO signals (real_time, game_tick, combinator, item_key, green, red, logistic) + VALUES ${placeholders.join(', ')}`, + values, + ); + await client.query( + `INSERT INTO tick_timing (real_time, game_tick, combinator) VALUES ($1,$2,$3)`, + [realTime, game_tick, combinator], + ); + + await client.query('COMMIT'); + return NextResponse.json({ ok: true, rows: allKeys.size }); + } catch (err) { + await client.query('ROLLBACK'); + throw err; // re-throw — withAuth handler catches and returns 500 + } finally { + client.release(); + } +}); \ No newline at end of file diff --git a/web/app/api/sessions/route.ts b/web/app/api/sessions/route.ts new file mode 100644 index 0000000..a602d38 --- /dev/null +++ b/web/app/api/sessions/route.ts @@ -0,0 +1,11 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { getSessionBoundaries } from '@/lib/sessions'; +import { withAuth } from '@/lib/apiHelpers'; + +export const GET = withAuth(async (req: NextRequest) => { + const p = req.nextUrl.searchParams; + const from = p.get('from') ? new Date(p.get('from')!) : new Date(Date.now() - 86_400_000); + const to = p.get('to') ? new Date(p.get('to')!) : new Date(); + const boundaries = await getSessionBoundaries(from, to); + return NextResponse.json(boundaries); +}); \ No newline at end of file diff --git a/web/app/api/signals/route.ts b/web/app/api/signals/route.ts new file mode 100644 index 0000000..196f9d5 --- /dev/null +++ b/web/app/api/signals/route.ts @@ -0,0 +1,191 @@ +import { NextRequest, NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; +import { getServerLocaleMap } from '@/lib/localeServer'; +import { matchKeys } from '@/lib/localization'; + +export const GET = withAuth(async (req: NextRequest) => { + const p = req.nextUrl.searchParams; + const combinators = p.getAll('combinator'); + const itemsWhitelist = p.getAll('item'); + const itemsBlacklist = p.getAll('exclude'); + const signalType = p.get('signal') ?? 'both'; + const from = p.get('from'); + const to = p.get('to'); + const useRegex = p.get('regex') === 'true'; + const orderBy = p.get('order_by') ?? 'time'; + const limit = p.get('limit') ? parseInt(p.get('limit')!, 10) : null; + + const conditions: string[] = []; + const values: unknown[] = []; + let i = 1; + + if (combinators.length > 0) { + conditions.push(`combinator = ANY($${i++})`); + values.push(combinators); + } + + if (itemsWhitelist.length > 0) { + if (useRegex) { + const localeMap = getServerLocaleMap(); + // Each pattern is expanded to matching keys (tested against key AND localized name). + // Union all patterns — if a pattern matches nothing, it contributes no keys. + const keys = [...new Set(itemsWhitelist.flatMap(p => matchKeys(p, localeMap)))]; + if (keys.length === 0) return NextResponse.json([]); + conditions.push(`item_key = ANY($${i++})`); + values.push(keys); + } else { + conditions.push(`item_key = ANY($${i++})`); + values.push(itemsWhitelist); + } + } + + if (itemsBlacklist.length > 0) { + if (useRegex) { + const localeMap = getServerLocaleMap(); + const keys = [...new Set(itemsBlacklist.flatMap(p => matchKeys(p, localeMap)))]; + // If blacklist pattern matches nothing, nothing to exclude — skip condition + if (keys.length > 0) { + conditions.push(`item_key != ALL($${i++})`); + values.push(keys); + } + } else { + conditions.push(`item_key != ALL($${i++})`); + values.push(itemsBlacklist); + } + } + + if (from) { conditions.push(`real_time >= $${i++}`); values.push(new Date(from)); } + if (to) { conditions.push(`real_time <= $${i++}`); values.push(new Date(to)); } + + const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''; + + const valueCol = signalType === 'red' ? 'red' : 'green'; + const selectCols = + signalType === 'green' ? 'real_time, game_tick, combinator, item_key, green' + : signalType === 'red' ? 'real_time, game_tick, combinator, item_key, red' + : 'real_time, game_tick, combinator, item_key, green, red'; + + if ((orderBy === 'delta_asc' || orderBy === 'delta_desc') && limit !== null) { + const baseConditions: string[] = []; + const baseValues: unknown[] = []; + let j = 1; + + if (combinators.length > 0) { + baseConditions.push(`combinator = ANY($${j++})`); + baseValues.push(combinators); + } + if (itemsWhitelist.length > 0) { + if (useRegex) { + const localeMap = getServerLocaleMap(); + const keys = [...new Set(itemsWhitelist.flatMap(p => matchKeys(p, localeMap)))]; + if (keys.length === 0) return NextResponse.json([]); + baseConditions.push(`item_key = ANY($${j++})`); + baseValues.push(keys); + } else { + baseConditions.push(`item_key = ANY($${j++})`); + baseValues.push(itemsWhitelist); + } + } + if (itemsBlacklist.length > 0) { + if (useRegex) { + const localeMap = getServerLocaleMap(); + const keys = [...new Set(itemsBlacklist.flatMap(p => matchKeys(p, localeMap)))]; + if (keys.length > 0) { + baseConditions.push(`item_key != ALL($${j++})`); + baseValues.push(keys); + } + } else { + baseConditions.push(`item_key != ALL($${j++})`); + baseValues.push(itemsBlacklist); + } + } + + const baseWhere = baseConditions.length > 0 ? `WHERE ${baseConditions.join(' AND ')}` : ''; + const baseWhereAnd = baseConditions.length > 0 ? `AND ${baseConditions.join(' AND ')}` : ''; + + const deltaQuery = ` + WITH snap_now AS ( + SELECT DISTINCT ON (combinator, item_key) + combinator, item_key, ${valueCol} AS val, real_time AS ref_time + FROM signals + ${baseWhere} + ORDER BY combinator, item_key, real_time DESC + ), + snap_then AS ( + SELECT DISTINCT ON (s.combinator, s.item_key) + s.combinator, s.item_key, s.${valueCol} AS val + FROM signals s + JOIN snap_now n USING (combinator, item_key) + WHERE s.real_time <= n.ref_time - INTERVAL '10 minutes' + ${baseWhereAnd} + ORDER BY s.combinator, s.item_key, s.real_time DESC + ), + deltas AS ( + SELECT + snap_now.combinator, + snap_now.item_key, + (snap_now.val - COALESCE(snap_then.val, snap_now.val)) AS delta + FROM snap_now + LEFT JOIN snap_then USING (combinator, item_key) + ) + SELECT combinator, item_key, delta + FROM deltas + ORDER BY delta ${orderBy === 'delta_asc' ? 'ASC' : 'DESC'} + LIMIT $${j} + `; + + const deltaResult = await pool.query<{ combinator: string; item_key: string; delta: number }>( + deltaQuery, + [...baseValues, limit], + ); + + const top = deltaResult.rows; + if (top.length === 0) return NextResponse.json([]); + + const seriesConditions = top.map((_, idx) => + `(combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1})`, + ); + const fullWhere = `${where ? where + ' AND' : 'WHERE'} (${seriesConditions.join(' OR ')})`; + const result = await pool.query( + `SELECT ${selectCols} FROM signals ${fullWhere} ORDER BY real_time ASC`, + [...values, ...top.flatMap(r => [r.combinator, r.item_key])], + ); + return NextResponse.json(result.rows); + } + + if ((orderBy === 'value_asc' || orderBy === 'value_desc' || orderBy === 'abs_desc') && limit !== null) { + const latestVals = await pool.query<{ combinator: string; item_key: string; val: number }>( + `SELECT DISTINCT ON (combinator, item_key) + combinator, item_key, ${valueCol} AS val + FROM signals ${where} + ORDER BY combinator, item_key, real_time DESC`, + values, + ); + + let sorted = latestVals.rows; + if (orderBy === 'value_asc') sorted = [...sorted].sort((a, b) => a.val - b.val); + if (orderBy === 'value_desc') sorted = [...sorted].sort((a, b) => b.val - a.val); + if (orderBy === 'abs_desc') sorted = [...sorted].sort((a, b) => Math.abs(b.val) - Math.abs(a.val)); + + const top = sorted.slice(0, limit); + if (top.length === 0) return NextResponse.json([]); + + const seriesConditions = top.map((_, idx) => + `(combinator = $${i + idx * 2} AND item_key = $${i + idx * 2 + 1})`, + ); + const fullWhere = `${where ? where + ' AND' : 'WHERE'} (${seriesConditions.join(' OR ')})`; + const result = await pool.query( + `SELECT ${selectCols} FROM signals ${fullWhere} ORDER BY real_time ASC`, + [...values, ...top.flatMap(r => [r.combinator, r.item_key])], + ); + return NextResponse.json(result.rows); + } + + const rowLimit = orderBy === 'time' && limit ? `LIMIT ${limit}` : ''; + const result = await pool.query( + `SELECT ${selectCols} FROM signals ${where} ORDER BY real_time ASC ${rowLimit}`, + values, + ); + return NextResponse.json(result.rows); +}); \ No newline at end of file diff --git a/web/app/api/ups/route.ts b/web/app/api/ups/route.ts new file mode 100644 index 0000000..f2b24f5 --- /dev/null +++ b/web/app/api/ups/route.ts @@ -0,0 +1,59 @@ +import { NextRequest, NextResponse } from 'next/server'; +import pool from '@/lib/db'; +import { withAuth } from '@/lib/apiHelpers'; + +export const GET = withAuth(async (req: NextRequest) => { + const p = req.nextUrl.searchParams; + const combinator = p.get('combinator'); + const from = p.get('from') ? new Date(p.get('from')!) : new Date(Date.now() - 86_400_000); + const to = p.get('to') ? new Date(p.get('to')!) : new Date(); + + const conditions = ['real_time BETWEEN $1 AND $2']; + const values: unknown[] = [from, to]; + + if (combinator) { + conditions.push('combinator = $3'); + values.push(combinator); + } + + const result = await pool.query<{ + real_time: Date; game_tick: string; combinator: string; + }>( + `SELECT real_time, game_tick, combinator + FROM tick_timing + WHERE ${conditions.join(' AND ')} + ORDER BY real_time ASC`, + values, + ); + + const rows = result.rows; + if (rows.length < 2) return NextResponse.json([]); + + const byCombi = new Map(); + for (const row of rows) { + const arr = byCombi.get(row.combinator) ?? []; + arr.push(row); + byCombi.set(row.combinator, arr); + } + + const points: { real_time: string; game_tick: number; combinator: string; ups: number }[] = []; + + for (const [combi, combiRows] of byCombi) { + for (let i = 1; i < combiRows.length; i++) { + const prev = combiRows[i - 1]; + const curr = combiRows[i]; + const deltaRealMs = curr.real_time.getTime() - prev.real_time.getTime(); + const deltaTicks = parseInt(curr.game_tick, 10) - parseInt(prev.game_tick, 10); + // Skip session gaps and bad data + if (deltaRealMs > 30 * 60 * 1000 || deltaRealMs <= 0 || deltaTicks <= 0) continue; + points.push({ + real_time: curr.real_time.toISOString(), + game_tick: parseInt(curr.game_tick, 10), + combinator: combi, + ups: Math.round((deltaTicks / deltaRealMs) * 1000 * 10) / 10, + }); + } + } + + return NextResponse.json(points); +}); \ No newline at end of file diff --git a/web/app/favicon.ico b/web/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/web/app/favicon.ico differ diff --git a/web/app/globals.css b/web/app/globals.css new file mode 100644 index 0000000..f581895 --- /dev/null +++ b/web/app/globals.css @@ -0,0 +1,17 @@ +@import "tailwindcss"; + +:root { + --background: #111827; + --foreground: #f9fafb; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); +} + +body { + background: var(--background); + color: var(--foreground); + font-family: ui-sans-serif, system-ui, sans-serif; +} \ No newline at end of file diff --git a/web/app/layout.tsx b/web/app/layout.tsx new file mode 100644 index 0000000..8b14640 --- /dev/null +++ b/web/app/layout.tsx @@ -0,0 +1,17 @@ +import type { Metadata } from "next"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "Factorio Dashboard", + description: "Factorio signal monitor", +}; + +export default function RootLayout({ + children, +}: Readonly<{ children: React.ReactNode }>) { + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/web/app/page.tsx b/web/app/page.tsx new file mode 100644 index 0000000..de9cbf1 --- /dev/null +++ b/web/app/page.tsx @@ -0,0 +1,94 @@ +'use client'; + +import { useEffect, useState, Suspense } from 'react'; +import { useSearchParams } from 'next/navigation'; +import { AppProvider, useApp } from '@/lib/context'; +import { setToken, fetchAlerts } from '@/lib/api'; +import { getLocaleMap } from '@/lib/localization'; +import type { AlertConfig } from '@/lib/types'; +import type { LocaleMap } from '@/lib/localization'; +import TimeRangeSelector from '@/components/TimeRangeSelector'; +import AlertPanel from '@/components/AlertPanel'; +import Dashboard from '@/components/Dashboard'; + +function AppShell({ alerts }: { alerts: AlertConfig[] }) { + const { triggeredAlerts } = useApp(); + const [alertPanelOpen, setAlertPanelOpen] = useState(false); + + return ( +
+
+ Factorio Dashboard +
+ + +
+
+ +
+ +
+ + setAlertPanelOpen(false)} /> +
+ ); +} + +function DashboardApp() { + const searchParams = useSearchParams(); + const token = searchParams.get('token') ?? ''; + + const [ready, setReady] = useState(false); + const [alerts, setAlerts] = useState([]); + const [localeMap, setLocaleMap] = useState(new Map()); + + useEffect(() => { + if (!token) return; + setToken(token); + Promise.all([getLocaleMap(), fetchAlerts()]).then(([lm, al]) => { + setLocaleMap(lm); + setAlerts(al); + setReady(true); + }); + }, [token]); + + if (!token) { + return ( +
+ Missing ?token= in URL +
+ ); + } + + if (!ready) { + return ( +
+ Loading… +
+ ); + } + + return ( + + + + ); +} + +export default function Page() { + return ( + + + + ); +} \ No newline at end of file diff --git a/web/components/AlertPanel.tsx b/web/components/AlertPanel.tsx new file mode 100644 index 0000000..47b57a0 --- /dev/null +++ b/web/components/AlertPanel.tsx @@ -0,0 +1,244 @@ +'use client'; + +import { useState, useEffect, useRef } from 'react'; +import { useApp } from '@/lib/context'; +import { fetchAlerts, createAlert, updateAlert, deleteAlert } from '@/lib/api'; +import { resolveName, resolveKey } from '@/lib/localization'; +import type { AlertConfig } from '@/lib/types'; + +interface Props { + open: boolean; + onClose: () => void; +} + +const inputCls = 'w-full bg-gray-800 border border-gray-600 rounded px-2 py-1 text-sm text-white focus:outline-none focus:border-indigo-500'; +const selectCls = 'flex-1 bg-gray-800 border border-gray-600 rounded px-2 py-1 text-sm text-white focus:outline-none'; + +interface AlertFormState { + itemKey: string; + itemKeyIsRegex: boolean; + combinator: string; + signalType: 'green' | 'red'; + condition: 'above' | 'below'; + threshold: string; +} + +function emptyForm(): AlertFormState { + return { itemKey: '', itemKeyIsRegex: false, combinator: '', signalType: 'green', condition: 'below', threshold: '0' }; +} + +function alertToForm(a: AlertConfig): AlertFormState { + return { + itemKey: a.item_key, + itemKeyIsRegex: a.item_key_is_regex, + combinator: a.combinator ?? '', + signalType: a.signal_type, + condition: a.condition, + threshold: String(a.threshold), + }; +} + +function Tooltip({ text }: { text: string }) { + return ( + + + + {text} + + + ); +} + +function AlertForm({ + value, onChange, onSubmit, onCancel, submitLabel, +}: { + value: AlertFormState; + onChange: (s: AlertFormState) => void; + onSubmit: () => void; + onCancel?: () => void; + submitLabel: string; +}) { + return ( +
+ onChange({ ...value, itemKey: e.target.value })} + placeholder={value.itemKeyIsRegex ? 'iron-.*|Iron Plate' : 'Iron Plate or item-key'} + className={inputCls} + /> + + onChange({ ...value, combinator: e.target.value })} + placeholder="combinator (empty = all)" className={inputCls} /> +
+ + +
+ onChange({ ...value, threshold: e.target.value })} + placeholder="threshold" className={inputCls} /> +
+ + {onCancel && ( + + )} +
+
+ ); +} + +export default function AlertPanel({ open, onClose }: Props) { + const { triggeredAlerts, refreshAlerts, localeMap, reverseMap } = useApp(); + const [alerts, setAlerts] = useState([]); + const [newForm, setNewForm] = useState(emptyForm()); + const [editingId, setEditingId] = useState(null); + const [editForm, setEditForm] = useState(emptyForm()); + const prevTriggeredCount = useRef(0); + + useEffect(() => { + if (open) fetchAlerts().then(setAlerts); + }, [open]); + + useEffect(() => { + if (triggeredAlerts.length > prevTriggeredCount.current) { + try { + const ctx = new AudioContext(); + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.connect(gain); + gain.connect(ctx.destination); + osc.frequency.value = 880; + gain.gain.setValueAtTime(0.3, ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.4); + osc.start(); + osc.stop(ctx.currentTime + 0.4); + } catch { /* AudioContext blocked */ } + } + prevTriggeredCount.current = triggeredAlerts.length; + }, [triggeredAlerts.length]); + + /** Resolves item key input — skips resolution for regex mode. */ + function normalizeItemKey(form: AlertFormState): string { + if (form.itemKeyIsRegex) return form.itemKey.trim(); + return resolveKey(form.itemKey.trim(), reverseMap); + } + + async function handleCreate() { + if (!newForm.itemKey.trim()) return; + const created = await createAlert({ + item_key: normalizeItemKey(newForm), + item_key_is_regex: newForm.itemKeyIsRegex, + combinator: newForm.combinator.trim() || null, + signal_type: newForm.signalType, + condition: newForm.condition, + threshold: parseInt(newForm.threshold, 10), + }); + setAlerts(a => [created, ...a]); + setNewForm(emptyForm()); + await refreshAlerts(); + } + + async function handleEdit(id: string) { + if (!editForm.itemKey.trim()) return; + const updated = await updateAlert(id, { + item_key: normalizeItemKey(editForm), + item_key_is_regex: editForm.itemKeyIsRegex, + combinator: editForm.combinator.trim() || null, + signal_type: editForm.signalType, + condition: editForm.condition, + threshold: parseInt(editForm.threshold, 10), + }); + setAlerts(a => a.map(x => x.id === id ? updated : x)); + setEditingId(null); + await refreshAlerts(); + } + + async function handleDelete(id: string) { + await deleteAlert(id); + setAlerts(a => a.filter(x => x.id !== id)); + await refreshAlerts(); + } + + function startEdit(alert: AlertConfig) { + setEditingId(alert.id); + setEditForm(alertToForm(alert)); + } + + return ( +
+
+ Alerts + +
+ + {triggeredAlerts.length > 0 && ( +
+

🔴 TRIGGERED ({triggeredAlerts.length})

+ {triggeredAlerts.map((a, i) => ( +
+ {resolveName(a.matched_item_key, localeMap)} + ({a.combinator_match}) + [{a.signal_type}] + = {a.current_value} {a.condition} {a.threshold} + {a.item_key_is_regex && a.matched_item_key !== a.item_key && ( + + )} +
+ ))} +
+ )} + +
+

New Alert

+ +
+ +
+ {alerts.length === 0 &&

No alerts configured.

} + {alerts.map(a => ( +
+ {editingId === a.id ? ( + handleEdit(a.id)} + onCancel={() => setEditingId(null)} + submitLabel="Save" + /> + ) : ( +
+
+ {resolveName(a.item_key, localeMap)} + {a.item_key_is_regex && ( + + )} + {a.combinator && @ {a.combinator}} +
+ [{a.signal_type}] + {' '}{a.condition} {a.threshold} +
+
+ + +
+
+ )} +
+ ))} +
+
+ ); +} \ No newline at end of file diff --git a/web/components/ChartCard/CardShell.tsx b/web/components/ChartCard/CardShell.tsx new file mode 100644 index 0000000..5de90db --- /dev/null +++ b/web/components/ChartCard/CardShell.tsx @@ -0,0 +1,55 @@ +import React from 'react'; + +interface HeaderProps { + title: string; + onEdit: () => void; + onDelete: () => void; +} + +export function Header({ title, onEdit, onDelete }: HeaderProps) { + return ( +
+ {title} +
+ + +
+
+ ); +} + +export function EmptyState() { + return ( +
No data
+ ); +} + +interface CardShellProps extends HeaderProps { + empty: boolean; + children: React.ReactNode; + /** Ref to the div where the uPlot legend will be mounted */ + legendContainerRef?: React.RefObject; +} + +export function CardShell({ title, onEdit, onDelete, empty, children, legendContainerRef }: CardShellProps) { + return ( +
+
+ {empty ? ( + + ) : ( + <> + {/* Plot fills remaining space */} +
+ {children} +
+ {/* Legend scrolls independently, capped at 25% card height */} +
+ + )} +
+ ); +} \ No newline at end of file diff --git a/web/components/ChartCard/DividerCard.tsx b/web/components/ChartCard/DividerCard.tsx new file mode 100644 index 0000000..267486f --- /dev/null +++ b/web/components/ChartCard/DividerCard.tsx @@ -0,0 +1,18 @@ +interface Props { + title: string; + onEdit: () => void; + onDelete: () => void; +} + +export default function DividerCard({ title, onEdit, onDelete }: Props) { + return ( +
+ {title} +
+
+ + +
+
+ ); +} \ No newline at end of file diff --git a/web/components/ChartCard/SignalsChart.tsx b/web/components/ChartCard/SignalsChart.tsx new file mode 100644 index 0000000..ed1e3a7 --- /dev/null +++ b/web/components/ChartCard/SignalsChart.tsx @@ -0,0 +1,64 @@ +'use client'; + +import 'uplot/dist/uPlot.min.css'; +import uPlot from 'uplot'; +import { useApp } from '@/lib/context'; +import { resolveName } from '@/lib/localization'; +import { CardShell } from './CardShell'; +import { makeYScale, makeAnnotationHooks, makeSignalsSeries, makeSignalsAxes, CURSOR_NO_DRAG } from './plotHelpers'; +import { buildSeriesData } from './seriesData'; +import { usePlot } from './usePlot'; +import type { AlertConfig, ChartConfig, SessionBoundary, SignalRow } from '@/lib/types'; +import type { TimeMode } from '@/lib/types'; + +interface Props { + config: ChartConfig; + rows: SignalRow[]; + sessions: SessionBoundary[]; + alerts: AlertConfig[]; + timeMode: TimeMode; + onEdit: () => void; + onDelete: () => void; +} + +export default function SignalsChart({ config, rows, sessions, alerts, timeMode, onEdit, onDelete }: Props) { + const { localeMap } = useApp(); + + const { containerRef, legendRef } = usePlot( + (el, w, h, lRef) => { + const data = buildSeriesData(rows, config.signal_type, timeMode); + if (!data) return null; + + const { keys, allXs, data: seriesData } = data; + const sessionXs = sessions.map(s => timeMode === 'tick' ? s.game_tick : new Date(s.real_time).getTime() / 1000); + const alertThresholds = alerts + .filter(a => config.signal_type === 'both' || config.signal_type === a.signal_type) + .map(a => a.threshold); + + return new uPlot({ + width: w, + height: h, + cursor: CURSOR_NO_DRAG, + legend: { + mount: (_u, legendEl) => { + if (lRef.current) lRef.current.appendChild(legendEl); + }, + }, + series: makeSignalsSeries(keys, timeMode, key => resolveName(key, localeMap)), + axes: makeSignalsAxes(timeMode), + scales: { + x: { time: false }, + y: makeYScale(config.y_min ?? null, config.y_max ?? null, config.y_scale), + }, + hooks: makeAnnotationHooks(sessionXs, alertThresholds), + }, [allXs, ...seriesData], el); + }, + [rows, sessions, alerts, config, timeMode, localeMap], + ); + + return ( + +
} className="w-full h-full" /> + + ); +} \ No newline at end of file diff --git a/web/components/ChartCard/TableViz.tsx b/web/components/ChartCard/TableViz.tsx new file mode 100644 index 0000000..14875ba --- /dev/null +++ b/web/components/ChartCard/TableViz.tsx @@ -0,0 +1,59 @@ +import { useApp } from '@/lib/context'; +import { resolveName } from '@/lib/localization'; +import { CardShell } from './CardShell'; +import type { ChartConfig, SignalRow } from '@/lib/types'; + +interface Props { + config: ChartConfig; + rows: SignalRow[]; + onEdit: () => void; + onDelete: () => void; +} + +export default function TableViz({ config, rows, onEdit, onDelete }: Props) { + const { localeMap } = useApp(); + + const latest = new Map(); + for (const row of rows) { + latest.set(`${row.combinator}::${row.item_key}`, { green: row.green, red: row.red }); + } + const tableRows = [...latest.entries()].sort((a, b) => (a[1].green ?? 0) - (b[1].green ?? 0)); + + return ( + +
+ + + + + + {config.signal_type !== 'red' && } + {config.signal_type !== 'green' && } + + + + {tableRows.map(([key, vals]) => { + const [combinator, item_key] = key.split('::'); + return ( + + + + {config.signal_type !== 'red' && ( + + )} + {config.signal_type !== 'green' && ( + + )} + + ); + })} + +
ItemCombinatorGreenRed (NP)
{resolveName(item_key, localeMap)}{combinator} + {vals.green?.toLocaleString() ?? '--'} + + {vals.red?.toLocaleString() ?? '--'} +
+
+
+ ); +} \ No newline at end of file diff --git a/web/components/ChartCard/UpsChart.tsx b/web/components/ChartCard/UpsChart.tsx new file mode 100644 index 0000000..e2d4ad0 --- /dev/null +++ b/web/components/ChartCard/UpsChart.tsx @@ -0,0 +1,67 @@ +'use client'; + +import 'uplot/dist/uPlot.min.css'; +import uPlot from 'uplot'; +import { CardShell } from './CardShell'; +import { AXIS_BASE, CURSOR_NO_DRAG, makeYScale } from './plotHelpers'; +import { usePlot } from './usePlot'; +import type { ChartConfig, UpsRow } from '@/lib/types'; +import type { TimeMode } from '@/lib/types'; + +interface Props { + config: ChartConfig; + upsRows: UpsRow[]; + timeMode: TimeMode; + onEdit: () => void; + onDelete: () => void; +} + +export default function UpsChart({ config, upsRows, timeMode, onEdit, onDelete }: Props) { + const { containerRef, legendRef } = usePlot( + (el, w, h, lRef) => { + if (upsRows.length < 2) return null; + + const sorted = [...upsRows].sort((a, b) => + timeMode === 'tick' + ? a.game_tick - b.game_tick + : new Date(a.real_time).getTime() - new Date(b.real_time).getTime(), + ); + const xs = sorted.map(r => timeMode === 'tick' ? r.game_tick : new Date(r.real_time).getTime() / 1000); + const ys = sorted.map(r => r.ups); + + const xAxis: uPlot.Axis = { + ...AXIS_BASE, + ...(timeMode === 'real' && { + values: (_u, vals) => vals.map(v => v == null ? '' : new Date(v * 1000).toLocaleTimeString()), + }), + }; + + return new uPlot({ + width: w, + height: h, + cursor: CURSOR_NO_DRAG, + legend: { + mount: (_u, legendEl) => { + if (lRef.current) lRef.current.appendChild(legendEl); + }, + }, + series: [ + { label: timeMode === 'tick' ? 'Tick' : 'Time' }, + { label: 'UPS', stroke: '#4ade80', width: 1.5 }, + ], + axes: [xAxis, { ...AXIS_BASE }], + scales: { + x: { time: false }, + y: makeYScale(config.y_min ?? null, config.y_max ?? null, config.y_scale), + }, + }, [xs, ys], el); + }, + [upsRows, config.y_min, config.y_max, config.y_scale, timeMode], + ); + + return ( + +
} className="w-full h-full" /> + + ); +} \ No newline at end of file diff --git a/web/components/ChartCard/index.tsx b/web/components/ChartCard/index.tsx new file mode 100644 index 0000000..41b9f42 --- /dev/null +++ b/web/components/ChartCard/index.tsx @@ -0,0 +1,25 @@ +import type { AlertConfig, ChartConfig, SessionBoundary, SignalRow, UpsRow } from '@/lib/types'; +import type { TimeMode } from '@/lib/types'; +import UpsChart from './UpsChart'; +import SignalsChart from './SignalsChart'; +import TableViz from './TableViz'; +import DividerCard from './DividerCard'; + +export interface ChartCardProps { + config: ChartConfig; + rows: SignalRow[]; + upsRows: UpsRow[]; + sessions: SessionBoundary[]; + alerts: AlertConfig[]; + timeMode: TimeMode; + onEdit: () => void; + onDelete: () => void; +} + +export default function ChartCard(props: ChartCardProps) { + const { config } = props; + if (config.chart_type === 'divider') return ; + if (config.chart_type === 'ups') return ; + if (config.viz_type === 'table') return ; + return ; +} \ No newline at end of file diff --git a/web/components/ChartCard/plotHelpers.ts b/web/components/ChartCard/plotHelpers.ts new file mode 100644 index 0000000..84d4bd0 --- /dev/null +++ b/web/components/ChartCard/plotHelpers.ts @@ -0,0 +1,178 @@ +import uPlot from 'uplot'; +import type { ChartConfig } from '@/lib/types'; + +// --- Color helpers --- + +function djb2(s: string): number { + let h = 5381; + for (let i = 0; i < s.length; i++) h = (h * 33) ^ s.charCodeAt(i); + return h >>> 0; +} + +function hslColor(key: string): string { + const hue = djb2(key) % 360; + return `hsl(${hue},70%,60%)`; +} + +const SEMANTIC_GREEN = '#4ade80'; +const SEMANTIC_RED = '#f87171'; + +export interface SeriesStyle { + color: string; + dash: number[] | undefined; +} + +export function getSeriesStyle( + key: string, + uCombs: number, + uItems: number, + uSigs: number, +): SeriesStyle { + const [combinator, item_key, sig] = key.split('::'); + + if (uCombs === 1 && uItems === 1) { + return { color: sig === 'green' ? SEMANTIC_GREEN : SEMANTIC_RED, dash: undefined }; + } + if (uItems > 1) { + return { color: hslColor(item_key), dash: uSigs > 1 && sig === 'red' ? [4, 2] : undefined }; + } + return { color: hslColor(combinator), dash: uSigs > 1 && sig === 'red' ? [4, 2] : undefined }; +} + +/** + * Builds a human-readable series label. + * @param displayName Pre-resolved localized name for the item. + */ +export function getSeriesLabel( + key: string, + uCombs: number, + uItems: number, + uSigs: number, + displayName: string, +): string { + const [combinator, , sig] = key.split('::'); + if (uCombs === 1 && uItems === 1) return sig; + const parts: string[] = []; + if (uItems > 1) parts.push(displayName); + if (uCombs > 1) parts.push(`(${combinator})`); + if (uSigs > 1) parts.push(`[${sig}]`); + return parts.join(' '); +} + +// --- Axis / scale helpers --- + +export const AXIS_BASE: uPlot.Axis = { + stroke: '#9ca3af', + ticks: { stroke: '#374151' }, + grid: { stroke: '#1f2937' }, +}; + +export const CURSOR_NO_DRAG: uPlot.Cursor = { + drag: { x: false, y: false }, +}; + +/** + * Builds a uPlot y-scale. + * 'log' uses arcsinh distribution (distr:4) — handles negatives, zero, positives. + */ +export function makeYScale( + yMin: number | null, + yMax: number | null, + yScale: ChartConfig['y_scale'] = 'linear', +): uPlot.Scale { + if (yScale === 'log') { + return { + distr: 4, + asinh: 1, + ...(yMin !== null || yMax !== null ? { + range: (_u, dataMin, dataMax) => [yMin ?? dataMin, yMax ?? dataMax], + } : {}), + }; + } + + if (yMin === null && yMax === null) return { dir: 1 }; + return { + dir: 1, + range: (_u, dataMin, dataMax) => { + const lo = yMin ?? (dataMin ?? 0); + const hi = yMax ?? (dataMax ?? 1); + if (lo === hi) return [lo - 1, hi + 1]; + const pad = (yMin == null || yMax == null) ? Math.abs(hi - lo) * 0.05 : 0; + return [lo - pad, hi + pad]; + }, + }; +} + +export function makeAnnotationHooks( + sessionXs: number[], + alertThresholds: number[], +): uPlot.Options['hooks'] { + return { + draw: [(u) => { + const { ctx, bbox } = u; + ctx.save(); + + ctx.strokeStyle = 'rgba(251,191,36,0.6)'; + ctx.lineWidth = 1; + ctx.setLineDash([4, 4]); + for (const sx of sessionXs) { + const cx = Math.round(u.valToPos(sx, 'x', true)); + ctx.beginPath(); ctx.moveTo(cx, bbox.top); ctx.lineTo(cx, bbox.top + bbox.height); ctx.stroke(); + } + + ctx.strokeStyle = 'rgba(248,113,113,0.7)'; + ctx.setLineDash([6, 3]); + for (const t of alertThresholds) { + const cy = Math.round(u.valToPos(t, 'y', true)); + ctx.beginPath(); ctx.moveTo(bbox.left, cy); ctx.lineTo(bbox.left + bbox.width, cy); ctx.stroke(); + } + + ctx.restore(); + }], + }; +} + +export function makeSignalsSeries( + keys: string[], + timeMode: 'real' | 'tick', + resolveName: (key: string) => string, +): uPlot.Series[] { + const uCombs = new Set(keys.map(k => k.split('::')[0])).size; + const uItems = new Set(keys.map(k => k.split('::')[1])).size; + const uSigs = new Set(keys.map(k => k.split('::')[2])).size; + + const xSeries: uPlot.Series = { + label: timeMode === 'tick' ? 'Tick' : 'Time', + ...(timeMode === 'real' && { + value: (_u: uPlot, v: number | null) => + v == null ? '--' : new Date(v * 1000).toLocaleTimeString(), + }), + }; + + return [ + xSeries, + ...keys.map(k => { + const [, item_key] = k.split('::'); + const { color, dash } = getSeriesStyle(k, uCombs, uItems, uSigs); + return { + label: getSeriesLabel(k, uCombs, uItems, uSigs, resolveName(item_key)), + stroke: color, + width: 1.5, + dash, + }; + }), + ]; +} + +export function makeSignalsAxes(timeMode: 'real' | 'tick'): uPlot.Axis[] { + return [ + { + ...AXIS_BASE, + ...(timeMode === 'real' && { + values: (_u: uPlot, vals: (number | null)[]) => + vals.map(v => v == null ? '' : new Date(v * 1000).toLocaleTimeString()), + }), + }, + { ...AXIS_BASE }, + ]; +} \ No newline at end of file diff --git a/web/components/ChartCard/seriesData.ts b/web/components/ChartCard/seriesData.ts new file mode 100644 index 0000000..6f1a4b4 --- /dev/null +++ b/web/components/ChartCard/seriesData.ts @@ -0,0 +1,43 @@ +import type { SignalRow, ChartConfig } from '@/lib/types'; +import type { TimeMode } from '@/lib/types'; + +const MAX_SERIES = 80; + +export interface SeriesData { + keys: string[]; + allXs: number[]; + data: (number | undefined)[][]; +} + +export function buildSeriesData( + rows: SignalRow[], + signalType: ChartConfig['signal_type'], + timeMode: TimeMode, +): SeriesData | null { + const seriesMap = new Map>(); + + for (const row of rows) { + for (const [sig, val] of [['green', row.green], ['red', row.red]] as ['green' | 'red', number | undefined][]) { + if (signalType !== 'both' && signalType !== sig) continue; + if (val === undefined) continue; + const key = `${row.combinator}::${row.item_key}::${sig}`; + const x = timeMode === 'tick' + ? parseInt(row.game_tick, 10) + : new Date(row.real_time).getTime() / 1000; + if (!seriesMap.has(key)) seriesMap.set(key, new Map()); + seriesMap.get(key)!.set(x, val); + } + } + + if (seriesMap.size === 0) return null; + + const keys = [...seriesMap.keys()].slice(0, MAX_SERIES); + const allXs = [...new Set(keys.flatMap(k => [...seriesMap.get(k)!.keys()]))].sort((a, b) => a - b); + + const data = keys.map(k => { + const m = seriesMap.get(k)!; + return allXs.map(x => m.get(x)); // undefined = gap + }); + + return { keys, allXs, data }; +} \ No newline at end of file diff --git a/web/components/ChartCard/usePlot.ts b/web/components/ChartCard/usePlot.ts new file mode 100644 index 0000000..d5838d6 --- /dev/null +++ b/web/components/ChartCard/usePlot.ts @@ -0,0 +1,80 @@ +import { useCallback, useEffect, useRef } from 'react'; +import uPlot from 'uplot'; + +export type BuildFn = ( + el: HTMLDivElement, + w: number, + h: number, + legendRef: React.RefObject, +) => uPlot | null; + +/** Converts a data index to the pixel x position uPlot expects for setCursor */ +function idxToPixel(plot: uPlot, idx: number): number { + const x = plot.data[0]?.[idx]; + if (x == null) return -10; + return plot.valToPos(x, 'x'); +} + +/** + * Manages full uPlot lifecycle: + * - builds/rebuilds on dep change or resize + * - mounts legend into legendRef container + * - pins cursor to last data point on init (legend shows latest values) + * - restores last-point legend on mouseleave + */ +export function usePlot( + build: BuildFn, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + deps: any[], +): { containerRef: React.RefObject; legendRef: React.RefObject } { + const containerRef = useRef(null); + const legendRef = useRef(null!); + const plotRef = useRef(null); + const lastIdxRef = useRef(0); + + const rebuild = useCallback(() => { + const el = containerRef.current; + if (!el) return; + const w = el.clientWidth, h = el.clientHeight; + if (w < 10 || h < 10) return; + + plotRef.current?.destroy(); + if (legendRef.current) legendRef.current.innerHTML = ''; + + const plot = build(el, w, h, legendRef); + plotRef.current = plot; + + if (plot) { + const lastIdx = Math.max(0, (plot.data[0]?.length ?? 1) - 1); + lastIdxRef.current = lastIdx; + + // Pin legend to latest data point + plot.setCursor({ left: idxToPixel(plot, lastIdx), top: -10 }); + + // Defer mouseleave — prevents React hydration events firing before lastIdxRef set + requestAnimationFrame(() => { + plot.over.addEventListener('mouseleave', () => { + const p = plotRef.current; + if (!p) return; + p.setCursor({ left: idxToPixel(p, lastIdxRef.current), top: -10 }); + }); + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, deps); + + useEffect(() => { + rebuild(); + return () => { plotRef.current?.destroy(); plotRef.current = null; }; + }, [rebuild]); + + useEffect(() => { + const el = containerRef.current; + if (!el) return; + const ro = new ResizeObserver(rebuild); + ro.observe(el); + return () => ro.disconnect(); + }, [rebuild]); + + return { containerRef, legendRef }; +} \ No newline at end of file diff --git a/web/components/ChartEditor.tsx b/web/components/ChartEditor.tsx new file mode 100644 index 0000000..db526c1 --- /dev/null +++ b/web/components/ChartEditor.tsx @@ -0,0 +1,201 @@ +'use client'; + +import { useState } from 'react'; +import { useApp } from '@/lib/context'; +import { resolveKey } from '@/lib/localization'; +import type { ChartConfig } from '@/lib/types'; + +type DraftChart = Omit; + +interface Props { + initial?: ChartConfig; + onSave: (draft: DraftChart) => void; + onClose: () => void; +} + +const inputCls = + 'w-full bg-gray-800 border border-gray-600 rounded px-3 py-1.5 text-white text-sm focus:outline-none focus:border-indigo-500'; + +/** + * Normalizes a comma-separated list of user tokens (localized names or raw keys) + * to raw item_keys. Unknown tokens are kept as-is. + */ +function normalizeList(raw: string, reverseMap: Map): string[] | null { + const arr = raw.split(',').map(x => x.trim()).filter(Boolean); + if (arr.length === 0) return null; + return arr.map(t => resolveKey(t, reverseMap)); +} + +export default function ChartEditor({ initial, onSave, onClose }: Props) { + const { reverseMap } = useApp(); + + const [title, setTitle] = useState(initial?.title ?? ''); + const [chartType, setChartType] = useState(initial?.chart_type ?? 'signals'); + const [vizType, setVizType] = useState(initial?.viz_type ?? 'line'); + const [signalType, setSignalType] = useState(initial?.signal_type ?? 'both'); + const [combinators, setCombinators] = useState((initial?.filter_combinators ?? []).join(', ')); + const [whitelist, setWhitelist] = useState((initial?.filter_items ?? []).join(', ')); + const [blacklist, setBlacklist] = useState((initial?.filter_items_exclude ?? []).join(', ')); + const [useRegex, setUseRegex] = useState(initial?.filter_items_regex ?? false); + const [orderBy, setOrderBy] = useState(initial?.order_by ?? 'time'); + const [seriesLimit, setSeriesLimit] = useState(initial?.series_limit ?? 20); + const [yMin, setYMin] = useState(initial?.y_min?.toString() ?? ''); + const [yMax, setYMax] = useState(initial?.y_max?.toString() ?? ''); + const [yScale, setYScale] = useState(initial?.y_scale ?? 'linear'); + const [width, setWidth] = useState(initial?.width ?? 2); + const [height, setHeight] = useState(initial?.height ?? 4); + + function splitCombinators(): string[] | null { + const arr = combinators.split(',').map(x => x.trim()).filter(Boolean); + return arr.length > 0 ? arr : null; + } + + function handleSave() { + if (!title.trim()) return; + + // Regex mode: store pattern exactly as typed — server expands via matchKeys at query time. + // Non-regex mode: resolve each comma-token (localized name or raw key) to raw key. + const filter_items = useRegex + ? (whitelist.trim() ? [whitelist.trim()] : null) + : normalizeList(whitelist, reverseMap); + const filter_items_exclude = useRegex + ? (blacklist.trim() ? [blacklist.trim()] : null) + : normalizeList(blacklist, reverseMap); + + onSave({ + title: title.trim(), + chart_type: chartType, + viz_type: chartType === 'divider' ? 'line' : vizType, + signal_type: signalType, + pos_x: initial?.pos_x ?? 0, + pos_y: initial?.pos_y ?? 0, + width, height, + filter_combinators: chartType === 'divider' ? null : splitCombinators(), + filter_items: chartType === 'divider' ? null : filter_items, + filter_items_exclude: chartType === 'divider' ? null : filter_items_exclude, + filter_items_regex: useRegex, + order_by: orderBy, + series_limit: seriesLimit, + y_min: yMin !== '' ? parseFloat(yMin) : null, + y_max: yMax !== '' ? parseFloat(yMax) : null, + y_scale: yScale, + }); + } + + const isSignals = chartType === 'signals'; + const isDivider = chartType === 'divider'; + + return ( +
+
e.stopPropagation()} + > +

+ {initial ? 'Edit Chart' : 'New Chart'} +

+ + + setTitle(e.target.value)} className={`${inputCls} mb-3`} /> + + + + + {!isDivider && <> + + + } + + {isSignals && <> + + + + + + + + setSeriesLimit(Number(e.target.value))} + className={`${inputCls} mb-3`} /> + + + setCombinators(e.target.value)} + placeholder="nauvis, nauvis-orbit" className={`${inputCls} mb-3`} /> + +
+ + +
+ setWhitelist(e.target.value)} + placeholder={useRegex ? 'wissen.*|Iron Plate' : 'Iron Plate, copper-plate'} + className={`${inputCls} mb-1`} /> +

Whitelist — localized names or item keys accepted (empty = all)

+ setBlacklist(e.target.value)} + placeholder={useRegex ? 'Holz|stone' : 'Wood, stone'} + className={`${inputCls} mb-1`} /> +

Blacklist — localized names or item keys accepted

+ } + + {!isDivider && <> +
+
+ + setYMin(e.target.value)} + placeholder="auto" className={inputCls} /> +
+
+ + setYMax(e.target.value)} + placeholder="auto" className={inputCls} /> +
+
+ + + + } + +
+
+ + setWidth(Number(e.target.value))} className={inputCls} /> +
+
+ + setHeight(Number(e.target.value))} className={inputCls} /> +
+
+ +
+ + +
+
+
+ ); +} \ No newline at end of file diff --git a/web/components/Dashboard.tsx b/web/components/Dashboard.tsx new file mode 100644 index 0000000..50deb89 --- /dev/null +++ b/web/components/Dashboard.tsx @@ -0,0 +1,193 @@ +'use client'; + +import { useState, useEffect, useRef, useCallback } from 'react'; +import GridLayout from 'react-grid-layout'; +import type { Layout, LayoutItem } from 'react-grid-layout'; +import 'react-grid-layout/css/styles.css'; +import 'react-resizable/css/styles.css'; +import { useApp } from '@/lib/context'; +import { fetchCharts, createChart, updateChart, deleteChart, fetchSignals, fetchSessions, fetchUps } from '@/lib/api'; +import type { ChartConfig, SignalRow, UpsRow, SessionBoundary, AlertConfig } from '@/lib/types'; +import ChartCard from './ChartCard'; +import ChartEditor from './ChartEditor'; + +const COLS = 6; +const ROW_HEIGHT = 80; + +interface Props { + alerts: AlertConfig[]; +} + +export default function Dashboard({ alerts }: Props) { + const { timeRange, timeMode, getFromTo } = useApp(); + const [charts, setCharts] = useState([]); + const [signalData, setSignalData] = useState>(new Map()); + const [upsData, setUpsData] = useState>(new Map()); + const [sessions, setSessions] = useState([]); + const [editingChart, setEditingChart] = useState(null); + const [creatingChart, setCreatingChart] = useState(false); + const [containerWidth, setContainerWidth] = useState(1200); + + const containerRef = useRef(null); + const chartsRef = useRef([]); + const refreshingRef = useRef(false); + const layoutSaveTimer = useRef | null>(null); + + useEffect(() => { chartsRef.current = charts; }, [charts]); + useEffect(() => { fetchCharts().then(setCharts); }, []); + + const refreshData = useCallback(async () => { + if (refreshingRef.current) return; + const current = chartsRef.current; + if (current.length === 0) return; + + refreshingRef.current = true; + try { + const { from, to } = getFromTo(); + const signalCharts = current.filter(c => c.chart_type === 'signals'); + const upsCharts = current.filter(c => c.chart_type === 'ups'); + + if (signalCharts.length === 0 && upsCharts.length === 0) return; + + const [newSessions, ...results] = await Promise.all([ + fetchSessions(from, to), + ...signalCharts.map(c => fetchSignals({ + combinator: c.filter_combinators ?? undefined, + item: c.filter_items ?? undefined, + exclude: c.filter_items_exclude ?? undefined, + signal: c.signal_type, + time_mode: timeMode, + from, to, + regex: c.filter_items_regex || undefined, + ...(c.order_by !== 'time' ? { order_by: c.order_by, limit: c.series_limit } : {}), + })), + ...upsCharts.map(c => fetchUps({ combinator: c.filter_combinators?.[0], from, to })), + ]); + + setSessions(newSessions as SessionBoundary[]); + + const sigMap = new Map(); + signalCharts.forEach((c, i) => sigMap.set(c.id, results[i] as SignalRow[])); + setSignalData(sigMap); + + const upsMap = new Map(); + upsCharts.forEach((c, i) => upsMap.set(c.id, results[signalCharts.length + i] as UpsRow[])); + setUpsData(upsMap); + } finally { + refreshingRef.current = false; + } + }, [getFromTo, timeMode]); + + useEffect(() => { + if (charts.length > 0) refreshData(); + }, [charts, timeRange, timeMode, refreshData]); + + useEffect(() => { + const id = setInterval(refreshData, 30_000); + return () => clearInterval(id); + }, [refreshData]); + + useEffect(() => { + const el = containerRef.current; + if (!el) return; + setContainerWidth(el.clientWidth); + const ro = new ResizeObserver(() => setContainerWidth(el.clientWidth)); + ro.observe(el); + return () => ro.disconnect(); + }, []); + + async function handleCreate(draft: Omit) { + const created = await createChart(draft); + setCharts(cs => [...cs, created]); + setCreatingChart(false); + } + + async function handleUpdate(id: string, draft: Omit) { + const updated = await updateChart(id, draft); + setCharts(cs => cs.map(c => c.id === id ? updated : c)); + setEditingChart(null); + } + + async function handleDelete(id: string) { + await deleteChart(id); + setCharts(cs => cs.filter(c => c.id !== id)); + } + + function handleLayoutChange(layout: Layout) { + const items = layout as readonly LayoutItem[]; + const changed = items.filter(item => { + const chart = chartsRef.current.find(c => c.id === item.i); + return chart && ( + chart.pos_x !== item.x || chart.pos_y !== item.y || + chart.width !== item.w || chart.height !== item.h + ); + }); + if (changed.length === 0) return; + + setCharts(cs => cs.map(c => { + const l = changed.find(item => item.i === c.id); + return l ? { ...c, pos_x: l.x, pos_y: l.y, width: l.w, height: l.h } : c; + })); + + if (layoutSaveTimer.current) clearTimeout(layoutSaveTimer.current); + layoutSaveTimer.current = setTimeout(() => { + changed.forEach(item => + updateChart(item.i, { pos_x: item.x, pos_y: item.y, width: item.w, height: item.h }), + ); + }, 500); + } + + const layout: Layout = charts.map(c => ({ + i: c.id, x: c.pos_x, y: c.pos_y, w: c.width, h: c.height, + minW: 1, + minH: c.chart_type === 'divider' ? 1 : 2, + })); + + return ( +
+ + {charts.map(c => ( +
+ + !c.filter_combinators || !a.combinator || + c.filter_combinators.includes(a.combinator), + )} + timeMode={timeMode} + onEdit={() => setEditingChart(c)} + onDelete={() => handleDelete(c.id)} + /> +
+ ))} +
+ + + + {creatingChart && ( + setCreatingChart(false)} /> + )} + {editingChart && ( + handleUpdate(editingChart.id, draft)} + onClose={() => setEditingChart(null)} + /> + )} +
+ ); +} \ No newline at end of file diff --git a/web/components/TimeRangeSelector.tsx b/web/components/TimeRangeSelector.tsx new file mode 100644 index 0000000..0f12469 --- /dev/null +++ b/web/components/TimeRangeSelector.tsx @@ -0,0 +1,46 @@ +'use client'; + +import { useApp } from '@/lib/context'; +import type { TimeRange, TimeMode } from '@/lib/types'; + +const RANGES: TimeRange[] = ['30m', '1h', '6h', '24h', '7d', '30d']; + +export default function TimeRangeSelector() { + const { timeRange, setTimeRange, timeMode, setTimeMode } = useApp(); + + return ( +
+
+ {RANGES.map(r => ( + + ))} +
+ +
+ {(['real', 'tick'] as TimeMode[]).map(m => ( + + ))} +
+
+ ); +} \ No newline at end of file diff --git a/web/docker-compose.yml b/web/docker-compose.yml new file mode 100644 index 0000000..6dd2cbf --- /dev/null +++ b/web/docker-compose.yml @@ -0,0 +1,16 @@ +services: + db: + image: timescale/timescaledb:latest-pg16 + restart: unless-stopped + environment: + POSTGRES_USER: factorio + POSTGRES_PASSWORD: factorio + POSTGRES_DB: factorio + ports: + - "5432:5432" + volumes: + - db_data:/var/lib/postgresql/data + - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro + +volumes: + db_data: \ No newline at end of file diff --git a/web/lib/api.ts b/web/lib/api.ts new file mode 100644 index 0000000..7534422 --- /dev/null +++ b/web/lib/api.ts @@ -0,0 +1,65 @@ +import type { ChartConfig, AlertConfig, TriggeredAlert, SignalRow, SessionBoundary, UpsRow, TimeMode } from './types'; + +let _token = ''; +export function setToken(token: string) { _token = token; } + +function url(path: string, params: Record = {}) { + const u = new URL(path, typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000'); + u.searchParams.set('token', _token); + for (const [k, v] of Object.entries(params)) { + if (v === undefined) continue; + if (Array.isArray(v)) v.forEach(val => u.searchParams.append(k, String(val))); + else u.searchParams.set(k, String(v)); + } + return u.toString(); +} + +async function get(path: string, params?: Record): Promise { + const res = await fetch(url(path, params)); + if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); + return res.json(); +} + +async function mutate(method: string, path: string, body?: unknown): Promise { + const res = await fetch(url(path), { + method, + headers: { 'Content-Type': 'application/json' }, + body: body !== undefined ? JSON.stringify(body) : undefined, + }); + if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); + return res.json(); +} + +export function fetchSignals(params: { + combinator?: string[]; + item?: string[]; + exclude?: string[]; + signal?: string; + time_mode?: TimeMode; + from?: string; + to?: string; + regex?: boolean; + order_by?: string; + limit?: number; +}): Promise { + return get('/api/signals', params as Record); +} + +export function fetchUps(params: { combinator?: string; from?: string; to?: string }): Promise { + return get('/api/ups', params); +} + +export function fetchSessions(from: string, to: string): Promise { + return get('/api/sessions', { from, to }); +} + +export function fetchCharts(): Promise { return get('/api/charts'); } +export function createChart(body: Omit): Promise { return mutate('POST', '/api/charts', body); } +export function updateChart(id: string, body: Partial): Promise { return mutate('PUT', `/api/charts/${id}`, body); } +export function deleteChart(id: string): Promise<{ ok: boolean }> { return mutate('DELETE', `/api/charts/${id}`); } + +export function fetchAlerts(): Promise { return get('/api/alerts'); } +export function createAlert(body: Omit): Promise { return mutate('POST', '/api/alerts', body); } +export function updateAlert(id: string, body: Partial): Promise { return mutate('PUT', `/api/alerts/${id}`, body); } +export function deleteAlert(id: string): Promise<{ ok: boolean }> { return mutate('DELETE', `/api/alerts/${id}`); } +export function checkAlerts(): Promise { return get('/api/alerts/check'); } \ No newline at end of file diff --git a/web/lib/apiHelpers.ts b/web/lib/apiHelpers.ts new file mode 100644 index 0000000..4124744 --- /dev/null +++ b/web/lib/apiHelpers.ts @@ -0,0 +1,26 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { isAuthorized, unauthorized } from './auth'; + +type RouteContext = { params: Promise> }; +type Handler = (req: NextRequest, ctx: RouteContext) => Promise; + +/** + * Wraps a route handler with auth checking and unified error handling. + * + * @example + * export const GET = withAuth(async (req) => { + * const rows = await pool.query('...'); + * return NextResponse.json(rows); + * }); + */ +export function withAuth(handler: Handler): Handler { + return async (req, ctx) => { + if (!isAuthorized(req)) return unauthorized(); + try { + return await handler(req, ctx); + } catch (err) { + console.error(err); + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); + } + }; +} \ No newline at end of file diff --git a/web/lib/auth.ts b/web/lib/auth.ts new file mode 100644 index 0000000..bd6df87 --- /dev/null +++ b/web/lib/auth.ts @@ -0,0 +1,22 @@ +import { NextRequest, NextResponse } from 'next/server'; + +/** + * Returns true if the request carries a valid API token. + * Accepts token via `?token=` query param or `Authorization: Bearer ` header. + */ +export function isAuthorized(req: NextRequest): boolean { + const expected = process.env.API_TOKEN; + if (!expected) return false; + + const queryToken = req.nextUrl.searchParams.get('token'); + if (queryToken === expected) return true; + + const authHeader = req.headers.get('authorization'); + if (authHeader === `Bearer ${expected}`) return true; + + return false; +} + +export function unauthorized(): NextResponse { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); +} \ No newline at end of file diff --git a/web/lib/context.tsx b/web/lib/context.tsx new file mode 100644 index 0000000..81f3b89 --- /dev/null +++ b/web/lib/context.tsx @@ -0,0 +1,83 @@ +'use client'; + +import React, { + createContext, + useCallback, + useContext, + useEffect, + useState, +} from 'react'; +import type { TimeRange, TimeMode, TriggeredAlert } from './types'; +import { TIME_RANGE_MS } from './types'; +import { checkAlerts } from './api'; +import { buildReverseMap } from './localization'; +import type { LocaleMap, ReverseMap } from './localization'; + +interface AppContextValue { + timeRange: TimeRange; + setTimeRange: (r: TimeRange) => void; + timeMode: TimeMode; + setTimeMode: (m: TimeMode) => void; + triggeredAlerts: TriggeredAlert[]; + refreshAlerts: () => Promise; + getFromTo: () => { from: string; to: string }; + localeMap: LocaleMap; + reverseMap: ReverseMap; +} + +const AppContext = createContext(null); + +export function AppProvider({ + token: _token, + localeMap, + children, +}: { + token: string; + localeMap: LocaleMap; + children: React.ReactNode; +}) { + const [timeRange, setTimeRange] = useState('6h'); + const [timeMode, setTimeMode] = useState('real'); + const [triggeredAlerts, setTriggeredAlerts] = useState([]); + + const reverseMap = buildReverseMap(localeMap); + + const getFromTo = useCallback(() => { + const to = new Date(); + const from = new Date(to.getTime() - TIME_RANGE_MS[timeRange]); + return { from: from.toISOString(), to: to.toISOString() }; + }, [timeRange]); + + const refreshAlerts = useCallback(async () => { + setTriggeredAlerts(await checkAlerts()); + }, []); + + useEffect(() => { + let cancelled = false; + const poll = () => checkAlerts().then(a => { if (!cancelled) setTriggeredAlerts(a); }); + poll(); + const id = setInterval(poll, 30_000); + return () => { cancelled = true; clearInterval(id); }; + }, []); + + return ( + + {children} + + ); +} + +/** Must be used within {@link AppProvider}. */ +export function useApp() { + const ctx = useContext(AppContext); + if (!ctx) throw new Error('useApp must be used within AppProvider'); + return ctx; +} \ No newline at end of file diff --git a/web/lib/db.ts b/web/lib/db.ts new file mode 100644 index 0000000..884c942 --- /dev/null +++ b/web/lib/db.ts @@ -0,0 +1,14 @@ +import { Pool } from 'pg'; + +declare global { + // eslint-disable-next-line no-var + var __pgPool: Pool | undefined; +} + +const pool = globalThis.__pgPool ?? new Pool({ connectionString: process.env.DATABASE_URL }); + +if (process.env.NODE_ENV !== 'production') { + globalThis.__pgPool = pool; +} + +export default pool; \ No newline at end of file diff --git a/web/lib/localeServer.ts b/web/lib/localeServer.ts new file mode 100644 index 0000000..1ad2cce --- /dev/null +++ b/web/lib/localeServer.ts @@ -0,0 +1,29 @@ +import fs from 'fs'; +import path from 'path'; +import { parseCsv } from './localization'; +import type { LocaleMap } from './localization'; + +declare global { var __serverLocaleCache: LocaleMap | undefined; } + +/** + * Loads and merges EN + DE locale CSVs from the public directory. + * Cached for the lifetime of the server process. + * Server-only — never import from client components. + */ +export function getServerLocaleMap(): LocaleMap { + if (globalThis.__serverLocaleCache) return globalThis.__serverLocaleCache; + + const pub = path.join(process.cwd(), 'public'); + + function load(filename: string): LocaleMap { + try { + return parseCsv(fs.readFileSync(path.join(pub, filename), 'utf8')); + } catch { + return new Map(); + } + } + + const merged: LocaleMap = new Map([...load('factorio_english_items.csv'), ...load('factorio_german_items.csv')]); + globalThis.__serverLocaleCache = merged; + return merged; +} \ No newline at end of file diff --git a/web/lib/localization.ts b/web/lib/localization.ts new file mode 100644 index 0000000..dc912ac --- /dev/null +++ b/web/lib/localization.ts @@ -0,0 +1,103 @@ +export type LocaleMap = Map; +export type ReverseMap = Map; + +/** Parses a 3-column CSV (section, item_key, localized_name). */ +export function parseCsv(text: string): LocaleMap { + const map: LocaleMap = new Map(); + const lines = text.split(/\r?\n/).slice(1); + for (const line of lines) { + if (!line.trim()) continue; + const cols = splitCsvLine(line); + if (cols.length >= 3) map.set(cols[1], cols[2]); + } + return map; +} + +function splitCsvLine(line: string): string[] { + const cols: string[] = []; + let cur = ''; + let inQuote = false; + for (let i = 0; i < line.length; i++) { + const ch = line[i]; + if (ch === '"') { + if (inQuote && line[i + 1] === '"') { cur += '"'; i++; } + else inQuote = !inQuote; + } else if (ch === ',' && !inQuote) { + cols.push(cur); + cur = ''; + } else { + cur += ch; + } + } + cols.push(cur); + return cols; +} + +declare global { var __localeCache: LocaleMap | undefined; } + +async function loadCsv(path: string): Promise { + try { + const res = await fetch(path); + return res.ok ? parseCsv(await res.text()) : new Map(); + } catch { + return new Map(); + } +} + +/** + * Fetches and merges DE + EN locale CSVs. + * Result is cached for the lifetime of the page. + */ +export async function getLocaleMap(): Promise { + if (globalThis.__localeCache) return globalThis.__localeCache; + const [en, de] = await Promise.all([ + loadCsv('/factorio_english_items.csv'), + loadCsv('/factorio_german_items.csv'), + ]); + const merged: LocaleMap = new Map([...en, ...de]); + globalThis.__localeCache = merged; + return merged; +} + +/** Resolves an `item_key` to its localized display name, falling back to the key itself. */ +export function resolveName(key: string, map: LocaleMap): string { + return map.get(key) ?? key; +} + +/** + * Builds a reverse lookup: lowercased localized name → item_key. + * Used for normalizing user input back to raw keys. + */ +export function buildReverseMap(map: LocaleMap): ReverseMap { + const rev: ReverseMap = new Map(); + for (const [key, name] of map) { + rev.set(name.toLowerCase(), key); + } + return rev; +} + +/** + * Resolves a single user-typed token (localized name or raw key) to a raw item_key. + * Falls back to the input itself if no match is found. + */ +export function resolveKey(input: string, rev: ReverseMap): string { + return rev.get(input.toLowerCase()) ?? input; +} + +/** + * Applies a regex pattern against both raw item_keys and localized names, + * returning the union of all matching raw item_keys. + */ +export function matchKeys(pattern: string, map: LocaleMap): string[] { + let re: RegExp; + try { + re = new RegExp(pattern, 'i'); + } catch { + return []; + } + const result = new Set(); + for (const [key, name] of map) { + if (re.test(key) || re.test(name)) result.add(key); + } + return [...result]; +} \ No newline at end of file diff --git a/web/lib/sessions.ts b/web/lib/sessions.ts new file mode 100644 index 0000000..f88a080 --- /dev/null +++ b/web/lib/sessions.ts @@ -0,0 +1,38 @@ +import pool from '@/lib/db'; +import type { SessionBoundary } from '@/lib/types'; + +/** + * Returns session-start timestamps where any gap > 30 min exists + * in the global tick_timing timeline. + */ +export async function getSessionBoundaries( + from: Date, + to: Date, +): Promise { + const result = await pool.query<{ real_time: Date; game_tick: string }>( + `SELECT real_time, game_tick + FROM tick_timing + WHERE real_time BETWEEN $1 AND $2 + ORDER BY real_time ASC`, + [from, to], + ); + + const rows = result.rows; + if (rows.length === 0) return []; + + const boundaries: SessionBoundary[] = [{ + real_time: rows[0].real_time.toISOString(), + game_tick: parseInt(rows[0].game_tick, 10), + }]; + + for (let i = 1; i < rows.length; i++) { + if (rows[i].real_time.getTime() - rows[i - 1].real_time.getTime() > 30 * 60 * 1000) { + boundaries.push({ + real_time: rows[i].real_time.toISOString(), + game_tick: parseInt(rows[i].game_tick, 10), + }); + } + } + + return boundaries; +} \ No newline at end of file diff --git a/web/lib/types.ts b/web/lib/types.ts new file mode 100644 index 0000000..6080524 --- /dev/null +++ b/web/lib/types.ts @@ -0,0 +1,71 @@ +export interface ChartConfig { + id: string; + title: string; + pos_x: number; + pos_y: number; + width: number; + height: number; + signal_type: 'green' | 'red' | 'both'; + chart_type: 'signals' | 'ups' | 'divider'; + viz_type: 'line' | 'table'; + filter_combinators: string[] | null; + filter_items: string[] | null; + filter_items_exclude: string[] | null; + filter_items_regex: boolean; + y_min: number | null; + y_max: number | null; + y_scale: 'linear' | 'log'; + series_limit: number; + order_by: 'time' | 'value_asc' | 'value_desc' | 'abs_desc' | 'delta_asc' | 'delta_desc'; +} + +export interface AlertConfig { + id: string; + item_key: string; + item_key_is_regex: boolean; + combinator: string | null; + signal_type: 'green' | 'red'; + condition: 'above' | 'below'; + threshold: number; + active: boolean; +} + +export interface TriggeredAlert extends AlertConfig { + current_value: number; + combinator_match: string; + /** Actual matched item_key — differs from item_key when item_key_is_regex=true */ + matched_item_key: string; +} + +export interface SignalRow { + real_time: string; + game_tick: string; + combinator: string; + item_key: string; + green?: number; + red?: number; +} + +export interface UpsRow { + real_time: string; + game_tick: number; + combinator: string; + ups: number; +} + +export interface SessionBoundary { + real_time: string; + game_tick: number; +} + +export type TimeMode = 'real' | 'tick'; +export type TimeRange = '30m' | '1h' | '6h' | '24h' | '7d' | '30d'; + +export const TIME_RANGE_MS: Record = { + '30m': 30 * 60 * 1000, + '1h': 60 * 60 * 1000, + '6h': 6 * 60 * 60 * 1000, + '24h': 24 * 60 * 60 * 1000, + '7d': 7 * 24 * 60 * 60 * 1000, + '30d': 30 * 24 * 60 * 60 * 1000, +}; \ No newline at end of file diff --git a/web/migrations/001_initial_schema.js b/web/migrations/001_initial_schema.js new file mode 100644 index 0000000..a0c7f7f --- /dev/null +++ b/web/migrations/001_initial_schema.js @@ -0,0 +1,94 @@ +/** @type {import('node-pg-migrate').MigrationBuilder} */ +exports.up = (pgm) => { + pgm.sql(`CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE`); + + pgm.createTable('signals', { + real_time: { type: 'timestamptz', notNull: true }, + game_tick: { type: 'bigint', notNull: true }, + combinator: { type: 'text', notNull: true }, + item_key: { type: 'text', notNull: true }, + green: { type: 'integer', notNull: true, default: 0 }, + red: { type: 'integer', notNull: true, default: 0 }, + logistic: { type: 'integer' }, + }, { ifNotExists: true }); + + pgm.sql(`SELECT create_hypertable('signals', 'real_time', if_not_exists => true)`); + pgm.sql(`CREATE INDEX IF NOT EXISTS signals_combinator_item_key_real_time_idx ON signals (combinator, item_key, real_time DESC)`); + pgm.sql(`CREATE INDEX IF NOT EXISTS signals_game_tick_idx ON signals (game_tick DESC)`); + pgm.sql(`SELECT add_retention_policy('signals', INTERVAL '30 days', if_not_exists => true)`); + + pgm.createTable('tick_timing', { + real_time: { type: 'timestamptz', notNull: true }, + game_tick: { type: 'bigint', notNull: true }, + combinator: { type: 'text', notNull: true }, + }, { ifNotExists: true }); + + pgm.sql(`SELECT create_hypertable('tick_timing', 'real_time', if_not_exists => true)`); + pgm.sql(`CREATE INDEX IF NOT EXISTS tick_timing_combinator_real_time_idx ON tick_timing (combinator, real_time DESC)`); + pgm.sql(`SELECT add_retention_policy('tick_timing', INTERVAL '30 days', if_not_exists => true)`); + + pgm.createTable('charts', { + id: { type: 'uuid', primaryKey: true, default: pgm.func('gen_random_uuid()') }, + title: { type: 'text', notNull: true }, + pos_x: { type: 'integer', notNull: true, default: 0 }, + pos_y: { type: 'integer', notNull: true, default: 0 }, + width: { type: 'integer', notNull: true, default: 2 }, + height: { type: 'integer', notNull: true, default: 4 }, + signal_type: { type: 'text', notNull: true, default: 'both' }, + chart_type: { type: 'text', notNull: true, default: 'signals' }, + viz_type: { type: 'text', notNull: true, default: 'line' }, + filter_combinators: { type: 'text[]' }, + filter_items: { type: 'text[]' }, + filter_items_exclude: { type: 'text[]' }, + filter_items_regex: { type: 'boolean', notNull: true, default: false }, + y_min: { type: 'real' }, + y_max: { type: 'real' }, + series_limit: { type: 'integer', notNull: true, default: 20 }, + order_by: { type: 'text', notNull: true, default: 'time' }, + created_at: { type: 'timestamptz', notNull: true, default: pgm.func('now()') }, + }, { ifNotExists: true }); + + // Use DO blocks so constraints are idempotent on existing DBs + pgm.sql(`DO $$ BEGIN + ALTER TABLE charts ADD CONSTRAINT charts_signal_type_check CHECK (signal_type IN ('green','red','both')); + EXCEPTION WHEN duplicate_object THEN NULL; END $$`); + + pgm.sql(`DO $$ BEGIN + ALTER TABLE charts ADD CONSTRAINT charts_chart_type_check CHECK (chart_type IN ('signals','ups')); + EXCEPTION WHEN duplicate_object THEN NULL; END $$`); + + pgm.sql(`DO $$ BEGIN + ALTER TABLE charts ADD CONSTRAINT charts_viz_type_check CHECK (viz_type IN ('line','stacked','table')); + EXCEPTION WHEN duplicate_object THEN NULL; END $$`); + + pgm.sql(`DO $$ BEGIN + ALTER TABLE charts ADD CONSTRAINT charts_order_by_check CHECK (order_by IN ('time','value_asc','value_desc','abs_desc','delta_asc','delta_desc')); + EXCEPTION WHEN duplicate_object THEN NULL; END $$`); + + pgm.createTable('alerts', { + id: { type: 'uuid', primaryKey: true, default: pgm.func('gen_random_uuid()') }, + item_key: { type: 'text', notNull: true }, + item_key_is_regex: { type: 'boolean', notNull: true, default: false }, + combinator: { type: 'text' }, + signal_type: { type: 'text', notNull: true, default: 'green' }, + condition: { type: 'text', notNull: true }, + threshold: { type: 'integer', notNull: true }, + active: { type: 'boolean', notNull: true, default: true }, + created_at: { type: 'timestamptz', notNull: true, default: pgm.func('now()') }, + }, { ifNotExists: true }); + + pgm.sql(`DO $$ BEGIN + ALTER TABLE alerts ADD CONSTRAINT alerts_signal_type_check CHECK (signal_type IN ('green','red')); + EXCEPTION WHEN duplicate_object THEN NULL; END $$`); + + pgm.sql(`DO $$ BEGIN + ALTER TABLE alerts ADD CONSTRAINT alerts_condition_check CHECK (condition IN ('above','below')); + EXCEPTION WHEN duplicate_object THEN NULL; END $$`); + + pgm.createTable('settings', { + key: { type: 'text', primaryKey: true }, + value: { type: 'text', notNull: true }, + }, { ifNotExists: true }); +}; + +exports.down = () => Promise.resolve(); \ No newline at end of file diff --git a/web/migrations/002_add_y_scale_delta_order.js b/web/migrations/002_add_y_scale_delta_order.js new file mode 100644 index 0000000..08b3819 --- /dev/null +++ b/web/migrations/002_add_y_scale_delta_order.js @@ -0,0 +1,18 @@ +/** @type {import('node-pg-migrate').MigrationBuilder} */ +exports.up = (pgm) => { + pgm.sql(`ALTER TABLE charts ADD COLUMN IF NOT EXISTS y_scale TEXT NOT NULL DEFAULT 'linear'`); + + pgm.sql(`DO $$ BEGIN + ALTER TABLE charts ADD CONSTRAINT charts_y_scale_check CHECK (y_scale IN ('linear','log')); + EXCEPTION WHEN duplicate_object THEN NULL; END $$`); + + pgm.sql(`ALTER TABLE charts DROP CONSTRAINT IF EXISTS charts_order_by_check`); + pgm.sql(`ALTER TABLE charts ADD CONSTRAINT charts_order_by_check CHECK (order_by IN ('time','value_asc','value_desc','abs_desc','delta_asc','delta_desc'))`); +}; + +exports.down = (pgm) => { + pgm.sql(`ALTER TABLE charts DROP CONSTRAINT IF EXISTS charts_order_by_check`); + pgm.sql(`ALTER TABLE charts ADD CONSTRAINT charts_order_by_check CHECK (order_by IN ('time','value_asc','value_desc','abs_desc'))`); + pgm.sql(`ALTER TABLE charts DROP CONSTRAINT IF EXISTS charts_y_scale_check`); + pgm.sql(`ALTER TABLE charts DROP COLUMN IF EXISTS y_scale`); +}; \ No newline at end of file diff --git a/web/migrations/003_remove_stacked_add_divider.js b/web/migrations/003_remove_stacked_add_divider.js new file mode 100644 index 0000000..93bba5c --- /dev/null +++ b/web/migrations/003_remove_stacked_add_divider.js @@ -0,0 +1,19 @@ +/** @type {import('node-pg-migrate').MigrationBuilder} */ +exports.up = (pgm) => { + pgm.sql(`ALTER TABLE charts DROP CONSTRAINT IF EXISTS charts_viz_type_check`); + pgm.sql(`ALTER TABLE charts ADD CONSTRAINT charts_viz_type_check CHECK (viz_type IN ('line','table'))`); + + pgm.sql(`ALTER TABLE charts DROP CONSTRAINT IF EXISTS charts_chart_type_check`); + pgm.sql(`ALTER TABLE charts ADD CONSTRAINT charts_chart_type_check CHECK (chart_type IN ('signals','ups','divider'))`); + + // Migrate any existing stacked charts to line + pgm.sql(`UPDATE charts SET viz_type = 'line' WHERE viz_type = 'stacked'`); +}; + +exports.down = (pgm) => { + pgm.sql(`ALTER TABLE charts DROP CONSTRAINT IF EXISTS charts_viz_type_check`); + pgm.sql(`ALTER TABLE charts ADD CONSTRAINT charts_viz_type_check CHECK (viz_type IN ('line','stacked','table'))`); + + pgm.sql(`ALTER TABLE charts DROP CONSTRAINT IF EXISTS charts_chart_type_check`); + pgm.sql(`ALTER TABLE charts ADD CONSTRAINT charts_chart_type_check CHECK (chart_type IN ('signals','ups'))`); +}; \ No newline at end of file diff --git a/web/next.config.ts b/web/next.config.ts new file mode 100644 index 0000000..de2d453 --- /dev/null +++ b/web/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + output: "standalone", +}; + +export default nextConfig; \ No newline at end of file diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 0000000..36ebd5c --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,2373 @@ +{ + "name": "web", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web", + "version": "0.1.0", + "dependencies": { + "@tailwindcss/postcss": "^4.3.0", + "next": "16.2.6", + "pg": "^8.20.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-grid-layout": "^2.2.3", + "react-resizable": "^4.0.1", + "uplot": "^1.6.32" + }, + "devDependencies": { + "@types/node": "^24", + "@types/pg": "^8.20.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "node-pg-migrate": "^8.0.4", + "postcss": "^8.5.14", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@next/env": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", + "integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.6.tgz", + "integrity": "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.6.tgz", + "integrity": "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.6.tgz", + "integrity": "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.6.tgz", + "integrity": "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.6.tgz", + "integrity": "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.6.tgz", + "integrity": "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.6.tgz", + "integrity": "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.6.tgz", + "integrity": "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", + "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.21.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", + "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-x64": "4.3.0", + "@tailwindcss/oxide-freebsd-x64": "4.3.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-x64-musl": "4.3.0", + "@tailwindcss/oxide-wasm32-wasi": "4.3.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", + "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", + "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", + "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", + "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.0.tgz", + "integrity": "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "postcss": "^8.5.10", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@types/node": { + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.29", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz", + "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.21.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.3.tgz", + "integrity": "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-equals": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz", + "integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==", + "license": "MIT" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "16.2.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz", + "integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.6", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.6", + "@next/swc-darwin-x64": "16.2.6", + "@next/swc-linux-arm64-gnu": "16.2.6", + "@next/swc-linux-arm64-musl": "16.2.6", + "@next/swc-linux-x64-gnu": "16.2.6", + "@next/swc-linux-x64-musl": "16.2.6", + "@next/swc-win32-arm64-msvc": "16.2.6", + "@next/swc-win32-x64-msvc": "16.2.6", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-pg-migrate": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/node-pg-migrate/-/node-pg-migrate-8.0.4.tgz", + "integrity": "sha512-HTlJ6fOT/2xHhAUtsqSN85PGMAqSbfGJNRwQF8+ZwQ1+sVGNUTl/ZGEshPsOI3yV22tPIyHXrKXr3S0JxeYLrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "~11.1.0", + "yargs": "~17.7.0" + }, + "bin": { + "node-pg-migrate": "bin/node-pg-migrate.js" + }, + "engines": { + "node": ">=20.11.0" + }, + "peerDependencies": { + "@types/pg": ">=6.0.0 <9.0.0", + "pg": ">=4.3.0 <9.0.0" + }, + "peerDependenciesMeta": { + "@types/pg": { + "optional": true + } + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, + "node_modules/react-draggable": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.5.0.tgz", + "integrity": "sha512-VC+HBLEZ0XJxnOxVAZsdRi8rD04Iz3SiiKOoYzamjylUcju/hP9np/aZdLHf/7WOD268WMoNJMvYfB5yAK45cw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/react-grid-layout": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-2.2.3.tgz", + "integrity": "sha512-OAEJHBxmfuxQfVtZwRzmsokijGlBgzYIJ7MUlLk/VSa43SaGzu15w5D0P2RDrfX5EvP9POMbL6bFrai/huDzbQ==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "fast-equals": "^4.0.3", + "prop-types": "^15.8.1", + "react-draggable": "^4.4.6", + "react-resizable": "^3.1.3", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/react-grid-layout/node_modules/react-resizable": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.2.0.tgz", + "integrity": "sha512-3NKQ0SLZV7rs3LQHeXlOzDSRQfFrkX6TVet77/Qk03zqiZyee37b7N8/gwDJAA8UUjRz7PdWCCy49hcso45SMQ==", + "license": "MIT", + "dependencies": { + "prop-types": "15.x", + "react-draggable": "^4.5.0" + }, + "peerDependencies": { + "react": ">= 16.3", + "react-dom": ">= 16.3" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-resizable": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-4.0.1.tgz", + "integrity": "sha512-FR25Rcfxpi1iKiC7taIrqc1Tz6VnslqM94/IrA1LxoM5C3ap2EqaKLnCit/aKrcn3H4wfzO0nFBadFBc+SzEWA==", + "license": "MIT", + "dependencies": { + "prop-types": "15.x", + "react-draggable": "^4.5.0" + }, + "peerDependencies": { + "react": ">= 16.3", + "react-dom": ">= 16.3" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tailwindcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", + "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uplot": { + "version": "1.6.32", + "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.32.tgz", + "integrity": "sha512-KIMVnG68zvu5XXUbC4LQEPnhwOxBuLyW1AHtpm6IKTXImkbLgkMy+jabjLgSLMasNuGGzQm/ep3tOkyTxpiQIw==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..1408741 --- /dev/null +++ b/web/package.json @@ -0,0 +1,34 @@ +{ + "name": "web", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "next lint", + "migrate": "node-pg-migrate up -m migrations", + "migrate:down": "node-pg-migrate down -m migrations", + "migrate:create": "node-pg-migrate create -m migrations" + }, + "dependencies": { + "@tailwindcss/postcss": "^4.3.0", + "next": "16.2.6", + "pg": "^8.20.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-grid-layout": "^2.2.3", + "react-resizable": "^4.0.1", + "uplot": "^1.6.32" + }, + "devDependencies": { + "@types/node": "^24", + "@types/pg": "^8.20.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "node-pg-migrate": "^8.0.4", + "postcss": "^8.5.14", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3" + } +} diff --git a/web/postcss.config.mjs b/web/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/web/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/web/public/factorio_english_items.csv b/web/public/factorio_english_items.csv new file mode 100644 index 0000000..b274d5b --- /dev/null +++ b/web/public/factorio_english_items.csv @@ -0,0 +1,1770 @@ +section,item_key,localized_name +entity-name,tree-proxy,Trees +entity-name,tree-dying-proxy,Pollution absorbed by damaging trees +entity-name,tile-proxy,Tiles +entity-name,cliff,Cliff +entity-name,small-cliff,Small cliff +entity-name,stone,Stone +entity-name,wooden-chest,Wooden chest +entity-name,copper-ore,Copper ore +entity-name,iron-ore,Iron ore +entity-name,uranium-ore,Uranium ore +entity-name,coal,Coal +entity-name,stone-furnace,Stone furnace +entity-name,steel-furnace,Steel furnace +entity-name,electric-furnace,Electric furnace +entity-name,transport-belt,Transport belt +entity-name,fast-transport-belt,Fast transport belt +entity-name,express-transport-belt,Express transport belt +entity-name,underground-belt,Underground belt +entity-name,fast-underground-belt,Fast underground belt +entity-name,express-underground-belt,Express underground belt +entity-name,loader-1x1,Loader 1x1 +entity-name,loader,Loader +entity-name,fast-loader,Fast loader +entity-name,express-loader,Express loader +entity-name,electric-mining-drill,Electric mining drill +entity-name,burner-mining-drill,Burner mining drill +entity-name,gun-turret,Gun turret +entity-name,cutscene-gun-turret,Gun turret +entity-name,laser-turret,Laser turret +entity-name,flamethrower-turret,Flamethrower turret +entity-name,artillery-turret,Artillery turret +entity-name,burner-inserter,Burner inserter +entity-name,inserter,Inserter +entity-name,long-handed-inserter,Long-handed inserter +entity-name,fast-inserter,Fast inserter +entity-name,filter-inserter,Filter inserter +entity-name,stack-inserter,Stack inserter +entity-name,stack-filter-inserter,Stack filter inserter +entity-name,iron-chest,Iron chest +entity-name,steel-chest,Steel chest +entity-name,construction-robot,Construction robot +entity-name,logistic-robot,Logistic robot +entity-name,logistic-chest-active-provider,Active provider chest +entity-name,logistic-chest-passive-provider,Passive provider chest +entity-name,logistic-chest-storage,Storage chest +entity-name,logistic-chest-buffer,Buffer chest +entity-name,logistic-chest-requester,Requester chest +entity-name,beacon,Beacon +entity-name,car,Car +entity-name,spidertron,Spidertron +entity-name,tank,Tank +entity-name,straight-rail,Straight rail +entity-name,curved-rail,Curved rail +entity-name,rail-ending-remnants,Rail ending remnants +entity-name,offshore-pump,Offshore pump +entity-name,water-well-pump,Water well pump +entity-name,pump,Pump +entity-name,pipe,Pipe +entity-name,pipe-to-ground,Pipe to ground +entity-name,locomotive,Locomotive +entity-name,boiler,Boiler +entity-name,heat-exchanger,Heat exchanger +entity-name,heat-pipe,Heat pipe +entity-name,copper-cable,Copper cable +entity-name,small-electric-pole,Small electric pole +entity-name,steam-engine,Steam engine +entity-name,steam-turbine,Steam turbine +entity-name,assembling-machine-1,Assembling machine 1 +entity-name,assembling-machine-2,Assembling machine 2 +entity-name,assembling-machine-3,Assembling machine 3 +entity-name,centrifuge,Centrifuge +entity-name,oil-refinery,Oil refinery +entity-name,chemical-plant,Chemical plant +entity-name,biter-spawner,Biter spawner +entity-name,rocket,Rocket +entity-name,land-mine,Land mine +entity-name,fish,Fish +entity-name,solar-panel,Solar panel +entity-name,small-biter,Small biter +entity-name,small-biter-corpse,Small biter corpse +entity-name,medium-biter,Medium biter +entity-name,medium-biter-corpse,Medium biter corpse +entity-name,big-biter,Big biter +entity-name,behemoth-biter,Behemoth biter +entity-name,big-biter-corpse,Big biter corpse +entity-name,behemoth-biter-corpse,Behemoth biter corpse +entity-name,biter-spawner-corpse,Biter spawner corpse +entity-name,small-spitter,Small spitter +entity-name,small-spitter-corpse,Small spitter corpse +entity-name,medium-spitter,Medium spitter +entity-name,medium-spitter-corpse,Medium spitter corpse +entity-name,big-spitter,Big spitter +entity-name,behemoth-spitter,Behemoth spitter +entity-name,big-spitter-corpse,Big spitter corpse +entity-name,behemoth-spitter-corpse,Behemoth spitter corpse +entity-name,spitter-spawner,Spitter spawner +entity-name,spitter-spawner-corpse,Spitter spawner corpse +entity-name,radar,Radar +entity-name,stone-wall,Wall +entity-name,gate,Gate +entity-name,lab,Lab +entity-name,character,Character +entity-name,player-port,Player port +entity-name,item-on-ground,Item on ground +entity-name,small-lamp,Lamp +entity-name,space-module-wreck,Space module wreckage +entity-name,rocket-silo,Rocket silo +entity-name,roboport,Roboport +entity-name,splitter,Splitter +entity-name,fast-splitter,Fast splitter +entity-name,express-splitter,Express splitter +entity-name,market,Market +entity-name,train-stop,Train stop +entity-name,rail-signal,Rail signal +entity-name,rail-chain-signal,Rail chain signal +entity-name,cargo-wagon,Cargo wagon +entity-name,fluid-wagon,Fluid wagon +entity-name,artillery-wagon,Artillery wagon +entity-name,decider-combinator,Decider combinator +entity-name,arithmetic-combinator,Arithmetic combinator +entity-name,constant-combinator,Constant combinator +entity-name,power-switch,Power switch +entity-name,programmable-speaker,Programmable speaker +entity-name,big-electric-pole,Big electric pole +entity-name,medium-electric-pole,Medium electric pole +entity-name,accumulator,Accumulator +entity-name,substation,Substation +entity-name,small-worm-turret,Small worm +entity-name,medium-worm-turret,Medium worm +entity-name,big-worm-turret,Big worm +entity-name,behemoth-worm-turret,Behemoth worm +entity-name,small-worm-corpse,Small worm corpse +entity-name,medium-worm-corpse,Medium worm corpse +entity-name,big-worm-corpse,Big worm corpse +entity-name,behemoth-worm-corpse,Behemoth worm corpse +entity-name,defender,Defender +entity-name,distractor,Distractor +entity-name,destroyer,Destroyer +entity-name,poison-cloud,Poison cloud +entity-name,small-remnants,Small remnants +entity-name,medium-remnants,Medium remnants +entity-name,medium-small-remnants,Medium small remnants +entity-name,big-remnants,Big remnants +entity-name,1x2-remnants,1x2 remnants +entity-name,small-scorchmark,Small scorchmark +entity-name,small-scorchmark-tintable,Small tinted scorchmark +entity-name,medium-scorchmark,Medium scorchmark +entity-name,medium-scorchmark-tintable,Medium tinted scorchmark +entity-name,big-scorchmark,Big scorchmark +entity-name,big-scorchmark-tintable,Big tinted scorchmark +entity-name,huge-scorchmark,Huge scorchmark +entity-name,huge-scorchmark-tintable,Huge tinted scorchmark +entity-name,storage-tank,Storage tank +entity-name,pumpjack,Pumpjack +entity-name,crude-oil,Crude oil +entity-name,tree,Tree +entity-name,tree-red,Red tree +entity-name,tree-brown,Brown tree +entity-name,tree-stump,Tree stump +entity-name,dead-tree-desert,Dead tree - desert +entity-name,dry-tree,Dry tree +entity-name,dead-grey-trunk,Dead grey trunk +entity-name,dry-hairy-tree,Dry hairy tree +entity-name,dead-dry-hairy-tree,Dead dry hairy tree +entity-name,green-coral,Green coral +entity-name,big-ship-wreck-1,Large shipwreck +entity-name,big-ship-wreck-2,Large shipwreck +entity-name,big-ship-wreck-3,Large shipwreck +entity-name,medium-ship-wreck,Medium shipwreck +entity-name,small-ship-wreck,Small shipwreck +entity-name,deconstructible-tile-proxy,Deconstructible tile proxy +entity-name,item-request-proxy,Item request slot +entity-name,electric-energy-interface,Electric energy interface +entity-name,heat-interface,Heat interface +entity-name,burner-generator,Burner generator +entity-name,simple-entity-with-force,Simple entity with force +entity-name,simple-entity-with-owner,Simple entity with owner +entity-name,spidertron-military-target,Spidertron military target +entity-name,tile-ghost,Tile ghost +entity-name,entity-ghost,Entity ghost +entity-name,nuclear-reactor,Nuclear reactor +entity-name,rock-huge,Huge rock +entity-name,rock-big,Big rock +entity-name,sand-rock-big,Big sandy rock +entity-name,red-desert-rock-big,Big red desert rock +entity-name,red-desert-rock-huge,Huge red desert rock +entity-name,character-corpse,Character corpse +entity-name,red-chest,Red chest +entity-name,blue-chest,Blue chest +entity-name,infinity-chest,Infinity chest +entity-name,linked-chest,Linked chest +entity-name,linked-belt,Linked belt +entity-name,infinity-pipe,Infinity pipe +entity-name,crash-site-chest-1,Chest capsule +entity-name,crash-site-chest-2,Chest capsule +entity-name,crash-site-spaceship,Spaceship +entity-name,crash-site-spaceship-wreck-big,Spaceship Wreck Big +entity-name,crash-site-spaceship-wreck-medium,Spaceship Wreck Medium +entity-name,crash-site-spaceship-wreck-small,Spaceship Wreck Small +entity-name,crash-site-fire-flame,Crash site fire flame +entity-name,compilatron,Compilatron +entity-name,fire-flame,Fire +entity-name,acid-splash,Acid splash +entity-name,explosion,Explosion +entity-name,explosion-hit,Explosion hit +entity-name,big-explosion,Big explosion +entity-name,medium-explosion,Medium explosion +entity-name,grenade-explosion,Grenade explosion +entity-name,massive-explosion,Massive explosion +entity-name,ground-explosion,Ground explosion +entity-name,blood-explosion-small,Blood explosion small +entity-name,blood-explosion-big,Blood explosion big +entity-name,blood-explosion-huge,Blood explosion huge +entity-name,blood-fountain,Blood fountain +entity-name,blood-fountain-big,Blood fountain big +entity-name,blood-fountain-hit-spray,Blood fountain hit spray +entity-name,laser-bubble,Laser bubble +entity-name,big-artillery-explosion,Big artillery explosion +entity-name,water-splash,Water splash +entity-name,spark-explosion,Spark explosion +entity-name,spark-explosion-higher,Spark explosion higher +entity-name,wall-damaged-explosion,Wall damaged explosion +entity-name,rock-damaged-explosion,Rock damaged explosion +entity-name,enemy-damaged-explosion,Enemy damaged explosion +entity-name,flying-robot-damaged-explosion,Flying robot damaged explosion +entity-name,uranium-cannon-shell-explosion,Uranium cannon shell explosion +entity-name,spidertron-leg,Spidertron leg +entity-name,factorio-logo-11tiles,Factorio logo 11 tiles +entity-name,factorio-logo-16tiles,Factorio logo 16 tiles +entity-name,factorio-logo-22tiles,Factorio logo 22 tiles +equipment-name,energy-shield-equipment,Energy shield +equipment-name,energy-shield-mk2-equipment,Energy shield MK2 +equipment-name,battery-equipment,Personal battery +equipment-name,battery-mk2-equipment,Personal battery MK2 +equipment-name,solar-panel-equipment,Portable solar panel +equipment-name,fusion-reactor-equipment,Portable fusion reactor +equipment-name,personal-laser-defense-equipment,Personal laser defense +equipment-name,discharge-defense-equipment,Discharge defense +equipment-name,exoskeleton-equipment,Exoskeleton +equipment-name,night-vision-equipment,Nightvision +equipment-name,belt-immunity-equipment,Belt immunity equipment +equipment-name,personal-roboport-equipment,Personal roboport +equipment-name,personal-roboport-mk2-equipment,Personal roboport MK2 +fluid-name,water,Water +fluid-name,steam,Steam +fluid-name,crude-oil,Crude oil +fluid-name,light-oil,Light oil +fluid-name,heavy-oil,Heavy oil +fluid-name,petroleum-gas,Petroleum gas +fluid-name,sulfuric-acid,Sulfuric acid +fluid-name,lubricant,Lubricant +virtual-signal-name,signal-everything,Everything +virtual-signal-name,signal-anything,Anything +virtual-signal-name,signal-each,Each +virtual-signal-name,signal-1,Signal 1 +virtual-signal-name,signal-2,Signal 2 +virtual-signal-name,signal-3,Signal 3 +virtual-signal-name,signal-4,Signal 4 +virtual-signal-name,signal-5,Signal 5 +virtual-signal-name,signal-6,Signal 6 +virtual-signal-name,signal-7,Signal 7 +virtual-signal-name,signal-8,Signal 8 +virtual-signal-name,signal-9,Signal 9 +virtual-signal-name,signal-0,Signal 0 +virtual-signal-name,signal-A,Signal A +virtual-signal-name,signal-B,Signal B +virtual-signal-name,signal-C,Signal C +virtual-signal-name,signal-D,Signal D +virtual-signal-name,signal-E,Signal E +virtual-signal-name,signal-F,Signal F +virtual-signal-name,signal-G,Signal G +virtual-signal-name,signal-H,Signal H +virtual-signal-name,signal-I,Signal I +virtual-signal-name,signal-J,Signal J +virtual-signal-name,signal-K,Signal K +virtual-signal-name,signal-L,Signal L +virtual-signal-name,signal-M,Signal M +virtual-signal-name,signal-N,Signal N +virtual-signal-name,signal-O,Signal O +virtual-signal-name,signal-P,Signal P +virtual-signal-name,signal-Q,Signal Q +virtual-signal-name,signal-R,Signal R +virtual-signal-name,signal-S,Signal S +virtual-signal-name,signal-T,Signal T +virtual-signal-name,signal-U,Signal U +virtual-signal-name,signal-V,Signal V +virtual-signal-name,signal-W,Signal W +virtual-signal-name,signal-X,Signal X +virtual-signal-name,signal-Y,Signal Y +virtual-signal-name,signal-Z,Signal Z +virtual-signal-name,signal-green,Green signal +virtual-signal-name,signal-red,Red signal +virtual-signal-name,signal-blue,Blue signal +virtual-signal-name,signal-yellow,Yellow signal +virtual-signal-name,signal-pink,Pink signal +virtual-signal-name,signal-cyan,Cyan signal +virtual-signal-name,signal-white,White signal +virtual-signal-name,signal-grey,Grey signal +virtual-signal-name,signal-black,Black signal +virtual-signal-name,signal-check,Check signal +virtual-signal-name,signal-dot,Dot signal +virtual-signal-name,signal-info,Info signal +item-name,pollution,Pollution +item-name,repair-pack,Repair pack +item-name,stone,Stone +item-name,wood,Wood +item-name,copper-ore,Copper ore +item-name,iron-ore,Iron ore +item-name,uranium-ore,Uranium ore +item-name,coal,Coal +item-name,copper-plate,Copper plate +item-name,iron-plate,Iron plate +item-name,steel-plate,Steel plate +item-name,stone-brick,Stone brick +item-name,iron-gear-wheel,Iron gear wheel +item-name,iron-stick,Iron stick +item-name,copper-cable,Copper cable +item-name,cliff-explosives,Cliff explosives +item-name,pistol,Pistol +item-name,submachine-gun,Submachine gun +item-name,vehicle-machine-gun,Vehicle machine gun +item-name,tank-machine-gun,Vehicle machine gun +item-name,tank-flamethrower,Vehicle flamethrower +item-name,artillery-wagon-cannon,Artillery cannon +item-name,rocket-launcher,Rocket launcher +item-name,spidertron-rocket-launcher,Spidertron rocket launcher +item-name,flamethrower,Flamethrower +item-name,flamethrower-ammo,Flamethrower ammo +item-name,flamethrower-turret,Flamethrower turret +item-name,artillery-turret,Artillery turret +item-name,electronic-circuit,Electronic circuit +item-name,advanced-circuit,Advanced circuit +item-name,processing-unit,Processing unit +item-name,light-armor,Light armor +item-name,heavy-armor,Heavy armor +item-name,modular-armor,Modular armor +item-name,power-armor,Power armor +item-name,power-armor-mk2,Power armor MK2 +item-name,rocket,Rocket +item-name,explosive-rocket,Explosive rocket +item-name,firearm-magazine,Firearm magazine +item-name,piercing-rounds-magazine,Piercing rounds magazine +item-name,laser-turret,Laser turret +item-name,solar-panel,Solar panel +item-name,fish,Fish +item-name,raw-fish,Raw fish +item-name,lab,Lab +item-name,automation-science-pack,Automation science pack +item-name,logistic-science-pack,Logistic science pack +item-name,chemical-science-pack,Chemical science pack +item-name,military-science-pack,Military science pack +item-name,production-science-pack,Production science pack +item-name,utility-science-pack,Utility science pack +item-name,space-science-pack,Space science pack +item-name,red-wire,Red wire +item-name,green-wire,Green wire +item-name,speed-module,Speed module +item-name,speed-module-2,Speed module 2 +item-name,speed-module-3,Speed module 3 +item-name,productivity-module,Productivity module +item-name,productivity-module-2,Productivity module 2 +item-name,productivity-module-3,Productivity module 3 +item-name,effectivity-module,Efficiency module +item-name,effectivity-module-2,Efficiency module 2 +item-name,effectivity-module-3,Efficiency module 3 +item-name,shotgun,Shotgun +item-name,combat-shotgun,Combat shotgun +item-name,shotgun-shell,Shotgun shells +item-name,piercing-shotgun-shell,Piercing shotgun shells +item-name,defender-capsule,Defender capsule +item-name,distractor-capsule,Distractor capsule +item-name,destroyer-capsule,Destroyer capsule +item-name,poison-capsule,Poison capsule +item-name,slowdown-capsule,Slowdown capsule +item-name,grenade,Grenade +item-name,cluster-grenade,Cluster grenade +item-name,discharge-defense-remote,Discharge defense remote +item-name,copy-paste-tool,Copy paste tool +item-name,blueprint,Blueprint +item-name,blueprint-book,Blueprint book +item-name,rail-planner,Rail planner +item-name,deconstruction-planner,Deconstruction planner +item-name,upgrade-planner,Upgrade planner +item-name,sulfur,Sulfur +item-name,solid-fuel,Solid fuel +item-name,plastic-bar,Plastic bar +item-name,engine-unit,Engine unit +item-name,electric-engine-unit,Electric engine unit +item-name,flying-robot-frame,Flying robot frame +item-name,explosives,Explosives +item-name,battery,Battery +item-name,empty-barrel,Empty barrel +item-name,crude-oil-barrel,Crude oil barrel +item-name,coin,Coin +item-name,cannon-shell,Cannon shell +item-name,explosive-cannon-shell,Explosive cannon shell +item-name,tank-cannon,Tank cannon +item-name,low-density-structure,Low density structure +item-name,rocket-fuel,Rocket fuel +item-name,nuclear-fuel,Nuclear fuel +item-name,rocket-control-unit,Rocket control unit +item-name,rocket-part,Rocket part +item-name,satellite,Satellite +item-name,stone-path,Stone path +item-name,concrete,Concrete +item-name,refined-concrete,Refined concrete +item-name,hazard-concrete,Hazard concrete +item-name,refined-hazard-concrete,Refined hazard concrete +item-name,rail,Rail +item-name,landfill,Landfill +item-name,electric-energy-interface,Electric energy interface +item-name,heat-interface,Heat interface +item-name,burner-generator,Burner generator +item-name,simple-entity-with-force,Simple entity with force +item-name,simple-entity-with-owner,Simple entity with owner +item-name,uranium-235,Uranium-235 +item-name,uranium-238,Uranium-238 +item-name,uranium-fuel-cell,Uranium fuel cell +item-name,used-up-uranium-fuel-cell,Used-up uranium fuel cell +item-name,filled-barrel,__1__ barrel +item-name,uranium-rounds-magazine,Uranium rounds magazine +item-name,uranium-cannon-shell,Uranium cannon shell +item-name,explosive-uranium-cannon-shell,Explosive uranium cannon shell +item-name,atomic-bomb,Atomic bomb +item-name,item-with-tags,Item with tags +item-name,item-with-label,Item with label +item-name,item-with-inventory,Item with inventory +item-name,selection-tool,Selection tool +item-name,infinity-chest,Infinity chest +item-name,linked-chest,Linked chest +item-name,infinity-pipe,Infinity pipe +item-name,belt-immunity-equipment,Belt immunity equipment +item-name,artillery-shell,Artillery shell +item-name,artillery-targeting-remote,Artillery targeting remote +item-name,cut-paste-tool,Cut paste tool +item-name,spidertron-remote,Spidertron remote +entity-name,aai-strongbox,Strongbox +entity-name,aai-strongbox-passive-provider,Passive provider strongbox +entity-name,aai-strongbox-active-provider,Active provider strongbox +entity-name,aai-strongbox-buffer,Buffer strongbox +entity-name,aai-strongbox-storage,Storage strongbox +entity-name,aai-strongbox-requester,Requester strongbox +entity-name,aai-storehouse,Storehouse +entity-name,aai-storehouse-passive-provider,Passive provider storehouse +entity-name,aai-storehouse-active-provider,Active provider storehouse +entity-name,aai-storehouse-buffer,Buffer storehouse +entity-name,aai-storehouse-storage,Storage storehouse +entity-name,aai-storehouse-requester,Requester storehouse +entity-name,aai-warehouse,Warehouse +entity-name,aai-warehouse-passive-provider,Passive provider warehouse +entity-name,aai-warehouse-active-provider,Active provider warehouse +entity-name,aai-warehouse-buffer,Buffer warehouse +entity-name,aai-warehouse-storage,Storage warehouse +entity-name,aai-warehouse-requester,Requester warehouse +item-name,stone-tablet,Stone tablet +item-name,motor,Single-cylinder engine +item-name,electric-motor,Small electric motor +item-name,burner-lab,Burner lab +item-name,burner-assembling-machine,Burner assembling machine +item-name,burner-turbine,Burner turbine generator +item-name,small-electric-pole,Small wood electric pole +item-name,small-iron-electric-pole,Small iron electric pole +item-name,processed-fuel,Processed fuel +item-name,wooden-chest,Wooden chest +item-name,sand,Sand +item-name,solid-sand,Washed sand +item-name,washed-sand,Washed sand +item-name,glass,Glass +item-name,area-mining-drill,Big mining drill +entity-name,burner-lab,Burner lab +entity-name,burner-assembling-machine,Burner assembling machine +entity-name,burner-turbine,Burner turbine generator +entity-name,burner-turbine-water,Burner turbine generator +entity-name,burner-turbine-generator,Burner turbine generator +entity-name,powered-offshore-pump,Offshore pump +entity-name,offshore-pump-output,Offshore pump +entity-name,small-iron-electric-pole,Small iron electric pole +entity-name,aai-big-ship-wreck-1,Wreckage +entity-name,aai-big-ship-wreck-2,Wreckage +entity-name,aai-big-ship-wreck-3,Wreckage +entity-name,aai-medium-ship-wreck-1,Wreckage +entity-name,aai-medium-ship-wreck-2,Wreckage +entity-name,aai-small-ship-wreck,Wreckage +entity-name,fuel-processor,Fuel processor +entity-name,concrete-block-wall,Concrete block wall +entity-name,concrete-wall,Concrete wall +entity-name,refined-concrete-wall,Refined concrete wall +entity-name,steel-wall,Steel wall +entity-name,industrial-furnace,Industrial furnace +entity-name,area-mining-drill,Big mining drill +entity-name,aai-signal-sender,Signal transmitter +entity-name,aai-signal-receiver,Signal receiver +entity-name,aai-signal-receiver-combinator,Signal receiver +entity-name,aai-filter,Signal filter +virtual-signal-name,aai-select-icon,Select icon +item-name,gunship,Gunship +item-name,aircraft-machine-gun,Vehicle-Mounted Machine gun +item-name,aircraft-rocket-launcher,Vehicle-Mounted Rocket launcher +item-name,cargo-plane,Cargo plane +item-name,jet,Jet +item-name,flying-fortress,Flying Fortress +item-name,cargo-plane-machine-gun,Machine gun +item-name,aircraft-cannon,Vehicle-Mounted Cannon +item-name,high-explosive-cannon-shell,High explosive cannon shell +item-name,flying-fortress-machine-gun,Flying-fortress machine gun +item-name,flying-fortress-rocket-launcher,Flying-fortress rocket launcher +item-name,napalm-launcher,Napalm launcher +item-name,cheat-machine,Cheat machine +item-name,aircraft-energy-shield,Aircraft Energy Shield +item-name,aircraft-afterburner,Afterburner +item-name,napalm,Napalm +entity-name,gunship,Gunship +entity-name,cargo-plane,Cargo plane +entity-name,jet,Jet +entity-name,flying-fortress,Flying fortress +entity-name,cheat-machine,Cheat machine +entity-name,napalm_fire_flame,Napalm fire +equipment-name,aircraft-energy-shield,Aircraft Energy Shield +equipment-name,aircraft-afterburner,Afterburner +entity-name,rock,Rock +entity-name,autodrive-requester,Hidden requester chest (Autodrive debugging) +entity-name,autodrive-provider,Hidden provider chest (Autodrive debugging) +item-name,autodrive-control,Vehicle radio control +item-name,autodrive-train-sensor,Train sensor +item-name,autodrive-enemy-sensor,Enemy sensor +item-name,autodrive-fuel-sensor,Fuel sensor +item-name,autodrive-ammo-sensor,Ammo sensor +item-name,autodrive-gate-sensor,Gate sensor +item-name,autodrive-logistic-sensor,Logistic network sensor +item-name,autodrive-circuit-sensor,Circuit network sensor (Shortwave) +item-name,autodrive-follow-sensor,Follow player sensor +item-name,autodrive-repair-sensor,Repair sensor __1__ +item-name,autodrive-repair-sensor_no-tier,Repair sensor +virtual-signal-name,autodrive-request,Request: __1__ +virtual-signal-name,autodrive-provide,Provide: __1__ +item-name,service_station,Constructron Service Station +item-name,constructron,Constructron +item-name,constructron-rocket-powered,Rocket Powered Constructron +item-name,ctron-selection-tool,Constructron Selection Tool +entity-name,service_station,Constructron Service Station +entity-name,constructron,Constructron +entity-name,constructron-rocket-powered,Rocket Powered Constructron +entity-name,electric-energy-interface-drain-1,Electric energy interface primary drain +entity-name,electric-energy-interface-source-1,Electric energy interface primary source +entity-name,electric-energy-interface-drain-2,Electric energy interface secondary drain +entity-name,electric-energy-interface-source-2,Electric energy interface secondary source +item-name,chunk-eraser,Chunk Eraser +entity-name,early-construction-robot,Early construction robot +item-name,early-construction-light-armor,Early construction light armor +item-name,early-construction-heavy-armor,Early construction heavy armor +equipment-name,early-construction-equipment,Early construction equipment +entity-name,equipment-gantry,Equipment gantry +entity-name,equipment-gantry-container-grid,Equipment gantry grid item input +entity-name,equipment-gantry-container-output,Equipment gantry grid item output +entity-name,equipment-gantry-container-equipment,Equipment gantry equipment item input +entity-name,equipment-gantry-remover,Equipment remover gantry +entity-name,equipment-gantry-remover-container-grid,Equipment remover grid item input +entity-name,equipment-gantry-remover-container-output,Equipment remover grid item output +entity-name,equipment-gantry-remover-container-equipment,Equipment remover equipment output +item-name,fp_beacon_selector,Beacon Selector +entity-name,farl,F.A.R.L. +item-name,farl,F.A.R.L. +item-name,farl-roboport,F.A.R.L. Module +equipment-name,farl-roboport,F.A.R.L. Module +entity-name,fc-filter-prefix,Filter +entity-name,fc-filter-steel-chest,Filter chest +entity-name,fluid-level-indicator,Fluid level indicator +entity-name,fluid-level-indicator-k2,Steel fluid level indicator +entity-name,fluid-level-indicator-straight,Fluid level indicator straight +entity-name,fluid-level-indicator-straight-k2,Steel fluid level indicator straight +entity-name,fluid-level-indicator-st-bobs-steel,Fluid level indicator MK2 +entity-name,fluid-level-indicator-st-bobs-plastic,Fluid level indicator MK3 +entity-name,fluid-level-indicator-st-bobs-tungsten,Fluid level indicator MK4 +entity-name,fluid-level-indicator-st-bobs-coppertungsten,Fluid level indicator MK5 +item-name,ghost-counter-tool,Ghost Counter selection tool +virtual-signal-name,informatron,InformaTron +entity-name,item-sensor,Inventory Sensor +item-name,item-sensor,Inventory Sensor +virtual-signal-name,inv-sensor-detected-locomotive,Locomotive Detected +virtual-signal-name,inv-sensor-detected-wagon,Cargo Wagon Detected +virtual-signal-name,inv-sensor-detected-car,Car Detected +virtual-signal-name,inv-sensor-detected-tank,Tank Detected +virtual-signal-name,inv-sensor-detected-spider,Spidertron Detected +virtual-signal-name,inv-sensor-temperature,Temperature +virtual-signal-name,inv-sensor-progress,Crafting Progress +virtual-signal-name,inv-sensor-fuel,Remaining fuel (MJ) +entity-name,jetpack-character,__1__ (flying) +equipment-name,jetpack-1,Jetpack Equipment MK1 +equipment-name,jetpack-2,Jetpack Equipment MK2 +equipment-name,jetpack-3,Jetpack Equipment MK3 +equipment-name,jetpack-4,Jetpack Equipment MK4 +item-name,jetpack-1,Jetpack Equipment MK1 +item-name,jetpack-2,Jetpack Equipment MK2 +item-name,jetpack-3,Jetpack Equipment MK3 +item-name,jetpack-4,Jetpack Equipment MK4 +entity-name,advanced-radar,Advanced radar +entity-name,biusart-lab,Advanced lab +entity-name,imersite,Imersite cave +entity-name,kr-activated-intergalactic-transceiver,Activated intergalactic transceiver +entity-name,kr-advanced-assembling-machine,Advanced assembling machine +entity-name,kr-advanced-chemical-plant,Advanced chemical plant +entity-name,kr-advanced-furnace,Advanced furnace +entity-name,kr-advanced-loader,Advanced loader +entity-name,kr-advanced-solar-panel,Advanced solar panel +entity-name,kr-advanced-splitter,Advanced splitter +entity-name,kr-advanced-steam-turbine,Advanced steam turbine +entity-name,kr-advanced-tank,Tank +entity-name,kr-advanced-transport-belt,Advanced transport belt +entity-name,kr-advanced-underground-belt,Advanced underground belt +entity-name,kr-air-purifier,Air purifier +entity-name,kr-antimatter-reactor,Antimatter reactor +entity-name,kr-armored-vehicle,Heavy armored vehicle +entity-name,kr-atmospheric-condenser,Atmospheric condenser +entity-name,kr-big-active-provider-container,Active provider warehouse +entity-name,kr-big-buffer-container,Buffer warehouse +entity-name,kr-big-container,Warehouse +entity-name,kr-big-passive-provider-container,Passive provider warehouse +entity-name,kr-big-random-pipes-remnant,Big random pipes (remnant) +entity-name,kr-big-requester-container,Requester warehouse +entity-name,kr-big-storage-container,Storage warehouse +entity-name,kr-bio-lab,Bio lab +entity-name,kr-construction-roboport,__1__ (Construction mode) +entity-name,kr-crusher,Crusher +entity-name,kr-damaged-ship-assembler,Damaged ship assembler +entity-name,kr-damaged-ship-reactor,Damaged ship reactor +entity-name,kr-damaged-ship-research-computer,Damaged ship research computer +entity-name,kr-electric-mining-drill-mk2,Electric mining drill MK2 +entity-name,kr-electric-mining-drill-mk3,Electric mining drill MK3 +entity-name,kr-electrolysis-plant,Electrolysis plant +entity-name,kr-energy-storage,Energy storage +entity-name,kr-express-loader,Express loader +entity-name,kr-fast-loader,Fast loader +entity-name,kr-filtration-plant,Filtration plant +entity-name,kr-fluid-burner,Flare stack +entity-name,kr-fluid-storage-1,Large storage tank +entity-name,kr-fluid-storage-2,Huge storage tank +entity-name,kr-fuel-refinery,Fuel refinery +entity-name,kr-fusion-reactor,Fusion reactor +entity-name,kr-gas-power-station,Gas power station +entity-name,kr-greenhouse,Greenhouse +entity-name,kr-intergalactic-transceiver,Intergalactic transceiver +entity-name,kr-large-roboport,Large roboport +entity-name,kr-laser-artillery-turret,Laser artillery turret +entity-name,kr-loader,Loader +entity-name,kr-logistic-roboport,__1__ (Logistic mode) +entity-name,kr-logo,Krastorio 2 logo +entity-name,kr-matter-assembler,Matter assembler +entity-name,kr-matter-plant,Matter plant +entity-name,kr-medium-active-provider-container,Medium active provider container +entity-name,kr-medium-buffer-container,Medium buffer container +entity-name,kr-medium-container,Medium container +entity-name,kr-medium-passive-provider-container,Medium passive provider container +entity-name,kr-medium-random-pipes-remnant,Medium random pipes (remnant) +entity-name,kr-medium-requester-container,Medium requester container +entity-name,kr-medium-storage-container,Medium storage container +entity-name,kr-mineable-wreckage,Small shipwreck +entity-name,kr-mineral-water-pumpjack,Mineral water pumpjack +entity-name,kr-nuclear-locomotive,Nuclear locomotive +entity-name,kr-oil-pumpjack,Oil pumpjack +entity-name,kr-planetary-teleporter,Planetary teleporter +entity-name,kr-quantum-computer,Quantum computer +entity-name,kr-quarry-drill,Quarry drill +entity-name,kr-railgun-turret,Railgun turret +entity-name,kr-research-server,Research server +entity-name,kr-rocket-turret,Rocket turret +entity-name,kr-se-deep-space-loader,Deep space loader +entity-name,kr-se-loader,Space loader +entity-name,kr-sentinel,Sentinel +entity-name,kr-shelter-plus,Advanced shelter [color +entity-name,kr-shelter,Shelter +entity-name,kr-singularity-beacon,Singularity beacon +entity-name,kr-singularity-lab,Singularity lab +entity-name,kr-small-roboport,Small roboport +entity-name,kr-stabilizer-charging-station,Stabilizer charging station +entity-name,kr-steel-pipe,Steel pipe +entity-name,kr-steel-pipe-to-ground,Steel underground pipe +entity-name,kr-steel-pump,Steel pump +entity-name,kr-substation-mk2,Substation MK2 +entity-name,kr-superior-filter-inserter,Superior filter inserter +entity-name,kr-superior-inserter,Superior inserter +entity-name,kr-superior-loader,Superior loader +entity-name,kr-superior-long-filter-inserter,Superior long filter inserter +entity-name,kr-superior-long-inserter,Superior long inserter +entity-name,kr-superior-splitter,Superior splitter +entity-name,kr-superior-transport-belt,Superior transport belt +entity-name,kr-superior-underground-belt,Superior underground belt +entity-name,kr-tesla-coil,Tesla coil +entity-name,kr-wind-turbine,Wind turbine +entity-name,mineral-water,Mineral water +entity-name,poop-cloud,Mystery substance cloud +entity-name,rare-metals,__ITEM__rare-metals__ +entity-name,turret-remnant,Turret (remnant) +entity-name,virus-cloud,Virus cloud +equipment-name,additional-engine,Additional electric engine +equipment-name,advanced-additional-engine,Advanced additional electric engine +equipment-name,advanced-exoskeleton-equipment,Advanced exoskeleton +equipment-name,antimatter-reactor-equipment,Portable antimatter reactor +equipment-name,battery-mk3-equipment,Personal battery MK3 +equipment-name,big-battery-equipment,Big personal battery +equipment-name,big-battery-mk2-equipment,Big personal battery MK2 +equipment-name,big-battery-mk3-equipment,Big personal battery MK3 +equipment-name,big-imersite-solar-panel-equipment,Big portable imersite solar panel +equipment-name,big-solar-panel-equipment,Big portable solar panel +equipment-name,cyber-potato-equipment,Cyber potato +equipment-name,energy-absorber,Energy absorber +equipment-name,imersite-night-vision-equipment,Imersite night vision +equipment-name,imersite-solar-panel-equipment,Portable imersite solar panel +equipment-name,nuclear-reactor-equipment,Portable nuclear reactor +equipment-name,personal-sniper-laser-defense-mk1-equipment,Personal sniper laser defense +equipment-name,personal-sniper-laser-defense-mk2-equipment,Personal sniper laser defense MK2 +equipment-name,personal-sniper-laser-defense-mk3-equipment,Personal sniper laser defense MK3 +equipment-name,personal-sniper-laser-defense-mk4-equipment,Personal sniper laser defense MK4 +equipment-name,personal-submachine-laser-defense-mk1-equipment,Personal submachine laser defense +equipment-name,personal-submachine-laser-defense-mk2-equipment,Personal submachine laser defense MK2 +equipment-name,personal-submachine-laser-defense-mk3-equipment,Personal submachine laser defense MK3 +equipment-name,personal-submachine-laser-defense-mk4-equipment,Personal submachine laser defense MK4 +equipment-name,portable-generator,Portable generator +equipment-name,power-armor-mk3,Power armor MK3 +equipment-name,power-armor-mk4,Power armor MK4 +equipment-name,shield-generator-mk1,Shield generator +equipment-name,shield-generator-mk2,Shield generator MK2 +equipment-name,shield-generator-mk3,Shield generator MK3 +equipment-name,shield-generator-mk4,Shield generator MK4 +equipment-name,small-portable-generator,Small portable generator +equipment-name,superior-exoskeleton-equipment,Superior exoskeleton +equipment-name,vehicle-roboport,Vehicle roboport +fluid-name,ammonia,Ammonia +fluid-name,biomethanol,Biomethanol +fluid-name,chlorine,Chlorine +fluid-name,dirty-water,Dirty water +fluid-name,heavy-water,Heavy water +fluid-name,hydrogen-chloride,Hydrogen chloride +fluid-name,hydrogen,Hydrogen +fluid-name,matter,Matter +fluid-name,mineral-water,Mineral water +fluid-name,nitric-acid,Nitric acid +fluid-name,nitrogen,Nitrogen +fluid-name,oxygen,Oxygen +item-name,advanced-fuel,Advanced fuel +item-name,advanced-tank-cannon-a,Fast railgun A +item-name,advanced-tank-cannon-b,Fast railgun B +item-name,advanced-tank-cannon-c,Sniper railgun +item-name,advanced-tank-laser-cannon,Impulse cannon +item-name,advanced-tank-machine-gun,Heavy machine gun +item-name,advanced-tech-card,Advanced tech card +item-name,ai-core,AI core +item-name,anti-material-rifle,Anti-materiel rifle +item-name,anti-material-rifle-magazine,Anti-materiel rifle magazine +item-name,antimatter-artillery-shell,Antimatter artillery shell +item-name,antimatter-railgun-shell,Antimatter railgun shell +item-name,antimatter-rocket,Antimatter rocket +item-name,antimatter-turret-rocket,Antimatter turret rocket +item-name,armor-piercing-anti-material-rifle-magazine,Armor piercing anti-materiel rifle magazine +item-name,armor-piercing-pistol-magazine,Armor piercing pistol magazine +item-name,armor-piercing-rifle-magazine,Armor piercing rifle magazine +item-name,automation-core,Automation core +item-name,automation-tech-card,Automation tech card +item-name,basic-railgun-shell,Railgun shell +item-name,basic-tech-card,Basic tech card +item-name,bio-fuel,Biofuel +item-name,biomass,Biomass +item-name,biters-research-data,Biter research data +item-name,blank-tech-card,Blank tech card +item-name,charged-antimatter-fuel-cell,Charged antimatter fuel cell +item-name,charged-matter-stabilizer,Charged Matter stabilizer +item-name,chemical-tech-card,Chemical tech card +item-name,coke,Coke +item-name,dolphin-gun,Space Dolphin Gun +item-name,dt-fuel,DT-fuel cell +item-name,electronic-components,Electronic components +item-name,empty-antimatter-fuel-cell,Empty antimatter fuel cell +item-name,empty-dt-fuel,Empty DT-fuel cell +item-name,energy-control-unit,Energy control unit +item-name,enriched-copper,Enriched copper +item-name,enriched-iron,Enriched iron +item-name,enriched-rare-metals,Enriched rare metals +item-name,explosion-railgun-shell,Explosive railgun shell +item-name,explosive-turret-rocket,Explosive turret rocket +item-name,explosive-turret-rocket-turret,Explosive turret rocket +item-name,fertilizer,Fertilizer +item-name,first-aid-kit,First aid kit +item-name,fuel,Fuel +item-name,gps-satellite,GPS satellite +item-name,heavy-rocket,Heavy rocket +item-name,heavy-rocket-launcher,Heavy rocket launcher +item-name,imersite-anti-material-rifle-magazine,Imersite anti-materiel rifle magazine +item-name,imersite-crystal,Imersite crystal +item-name,imersite,Imersite +item-name,imersite-powder,Imersite powder +item-name,imersite-rifle-magazine,Imersite rifle magazine +item-name,imersite-rounds-magazine,Imersite rounds magazine +item-name,imersium-beam,Imersium beam +item-name,imersium-gear-wheel,Imersium gear wheel +item-name,imersium-plate,Imersium plate +item-name,improved-pollution-filter,Improved pollution filter +item-name,impulse-rifle-ammo,Impulse rifle ammo +item-name,impulse-rifle,Impulse rifle +item-name,inserter-parts,Inserter parts +item-name,iron-beam,Iron beam +item-name,kr-accelerator,Accelerator [color +item-name,kr-biter-virus,Anti-biter virus capsule +item-name,kr-black-reinforced-plate,Black reinforced plate +item-name,kr-creep,Biter creep +item-name,kr-creep-collector,Creep collector +item-name,kr-creep-virus,Anti-creep virus capsule +item-name,kr-jackhammer,Jackhammer +item-name,kr-loader,Loader +item-name,kr-note-1,Mystery note +item-name,kr-void,Nothing +item-name,kr-white-reinforced-plate,Light reinforced plate +item-name,lithium-chloride,Lithium chloride +item-name,lithium,Lithium +item-name,lithium-sulfur-battery,Lithium–sulfur battery +item-name,logistic-tech-card,Logistic tech card +item-name,matter-cube,Matter cube +item-name,matter-research-data,Matter research data +item-name,matter-stabilizer,Matter stabilizer +item-name,matter-tech-card,Matter tech card +item-name,military-research-data,Military research data +item-name,military-tech-card,Military tech card +item-name,nuclear-artillery-shell,Nuclear artillery shell +item-name,nuclear-turret-rocket,Nuclear turret rocket +item-name,optimization-tech-card,Optimization tech card +item-name,pistol-magazine,Pistol magazine +item-name,pollution-filter,Pollution filter +item-name,poop,Mystery substance +item-name,potato,Potato [color +item-name,power-armor-mk3,Power armor MK3 +item-name,power-armor-mk4,Power armor MK4 +item-name,production-tech-card,Production tech card +item-name,quartz,Quartz +item-name,rare-metals,Rare metals +item-name,raw-imersite,Raw imersite +item-name,raw-rare-metals,Raw rare metals +item-name,rifle-magazine,Rifle magazine +item-name,silicon,Silicon +item-name,singularity-tech-card,Singularity tech card +item-name,space-research-data,Space research data +item-name,spoiled-potato,Spoiled potato +item-name,steel-beam,Steel beam +item-name,steel-gear-wheel,Steel gear wheel +item-name,teleportation-gps-module,Teleportation GPS module +item-name,tritium,Tritium +item-name,uranium-anti-material-rifle-magazine,Uranium anti-materiel rifle magazine +item-name,uranium-rifle-magazine,Uranium rifle magazine +item-name,used-improved-pollution-filter,Used improved pollution filter +item-name,used-pollution-filter,Used pollution filter +item-name,utility-tech-card,Utility tech card +virtual-signal-name,kr-attention_1,Attention 1 +virtual-signal-name,kr-attention_2,Attention 2 +virtual-signal-name,kr-attention_3,Attention 3 +virtual-signal-name,kr-battery,Battery +virtual-signal-name,kr-battery_low,Low battery +virtual-signal-name,kr-biohazard,Biohazard +virtual-signal-name,kr-build_here,Build here +virtual-signal-name,kr-dont_touch,Don't touch! +virtual-signal-name,kr-energy-1,Energy 1 +virtual-signal-name,kr-energy-2,Energy 2 +virtual-signal-name,kr-gear_b,Gear (black) +virtual-signal-name,kr-gear_w,Gear (white) +virtual-signal-name,kr-heart,Heart <3 +virtual-signal-name,kr-kill,Kill +virtual-signal-name,kr-krastorio,Krastorio +virtual-signal-name,kr-nuclear-1,Nuclear 1 +virtual-signal-name,kr-nuclear-2,Nuclear 2 +virtual-signal-name,kr-power_off,Power off +virtual-signal-name,kr-power_on,Power on +virtual-signal-name,kr-power,Power +virtual-signal-name,kr-question-mark,Question mark +virtual-signal-name,kr-recycling,Recycling +virtual-signal-name,kr-scull,Skull +virtual-signal-name,kr-smile,Smile +virtual-signal-name,kr-star_b,Star (black) +virtual-signal-name,kr-star_w,Star (white) +virtual-signal-name,kr-time,Time +virtual-signal-name,kr-wtf,WTF? +entity-name,kr-advanced-transport-belt-beltbox,Advanced stacking beltbox +entity-name,kr-advanced-transport-belt-loader,Advanced compact loader +entity-name,kr-singularity-reactor,Singularity reactor +entity-name,kr-superior-transport-belt-beltbox,Superior stacking beltbox +entity-name,kr-superior-transport-belt-loader,Superior compact loader +item-name,carbon-steel-beam,Carbon steel beam +item-name,carbon-steel-gear,Carbon steel gear +item-name,carbon-steel-plate,Carbon steel plate +item-name,charged-lithium-sulfur-battery,Charged lithium–sulfur battery +item-name,charged-singularity-fuel-cell,Charged singularity fuel cell +item-name,crushed-rare-metals,Crushed rare metals +item-name,empty-singularity-fuel-cell,Empty singularity fuel cell +item-name,se-astronomic-tech-card,Astronomic tech card +item-name,se-biological-tech-card,Biological tech card +item-name,se-deep-space-tech-card,Deep space tech card +item-name,se-energy-tech-card,Energy tech card +item-name,se-material-tech-card,Material tech card +entity-name,logistic-train-stop,Logistic Train Stop +entity-name,logistic-train-stop-input,Logistic Train Stop Input +entity-name,logistic-train-stop-output,Logistic Train Stop Output +entity-name,ltn-port,Logistic Port +item-name,logistic-train-stop,__ENTITY__logistic-train-stop__ +item-name,logistic-train-stop-input,__ENTITY__logistic-train-stop-input__ +item-name,logistic-train-stop-output,__ENTITY__logistic-train-stop-output__ +virtual-signal-name,ltn-position-any-locomotive,Encoded positions of every locomotive +virtual-signal-name,ltn-position-any-cargo-wagon,Encoded positions of every cargo wagon +virtual-signal-name,ltn-position-any-fluid-wagon,Encoded positions of every fluid wagon +virtual-signal-name,ltn-position-any-artillery-wagon,Encoded positions of every artillery cannon +virtual-signal-name,ltn-position,Encoded positions of __1__ +virtual-signal-name,ltn-depot,Stop is Depot +virtual-signal-name,ltn-depot-priority,Depot Priority +virtual-signal-name,ltn-network-id,Encoded Network ID +virtual-signal-name,ltn-min-train-length,Minimum Train Length +virtual-signal-name,ltn-max-train-length,Maximum Train Length +virtual-signal-name,ltn-max-trains,Limit Trains +virtual-signal-name,ltn-requester-threshold,Request Threshold +virtual-signal-name,ltn-requester-stack-threshold,Request Stack Threshold +virtual-signal-name,ltn-requester-priority,Request Priority +virtual-signal-name,ltn-provider-threshold,Provide Threshold +virtual-signal-name,ltn-provider-stack-threshold,Provide Stack Threshold +virtual-signal-name,ltn-provider-priority,Provide Priority +virtual-signal-name,ltn-locked-slots,Locked Slots per Wagon +virtual-signal-name,ltn-disable-warnings,Disable Warning Messages +virtual-signal-name,ltn-cleanup-station,LTN Cleanup Stop +virtual-signal-name,ltn-item-cleanup-station,LTN Cleanup any Item +entity-name,ltn-combinator,LTN Combinator +item-name,ltn-combinator,__ENTITY__ltn-combinator__ +entity-name,ltn-provider-reader,LTN Provider content reader +entity-name,ltn-requester-reader,LTN Requester content reader +entity-name,ltn-delivery-reader,LTN Delivery content reader +item-name,ltn-provider-reader,__ENTITY__ltn-provider-reader +item-name,ltn-requester-reader,__ENTITY__ltn-requester-reader +item-name,ltn-delivery-reader,__ENTITY__ltn-delivery-reader +item-name,mining-patch-planner,Mining patch planner +item-name,module-inserter,Module Inserter +entity-name,module_inserter_pickup,Dropped modules +entity-name,mi-default-proxy-machine,Anything +entity-name,pda-road-sign-speed-limit,Speed limit sign +entity-name,pda-road-sign-speed-unlimit,End of speed limit sign +entity-name,pda-road-sign-stop,Stopp sign +entity-name,pda-road-sensor,Road sensor +item-name,pamk3-lvest,Utility vest +item-name,pamk3-hvest,Heavy utility vest +item-name,pamk3-pamk3,Power armor MK3 +item-name,pamk3-pamk4,Power armor MK4 +item-name,pamk3-nvmk2,Nightvision MK2 +item-name,pamk3-esmk3,Energy shield MK3 +item-name,pamk3-battmk3,Fusion battery +item-name,pamk3-pnr,Portable nuclear reactor +item-name,pamk3-se,Shielded singularity +item-name,pamk3-inff,Singularity fuel source +equipment-name,pamk3-nvmk2,Nightvision MK2 +equipment-name,pamk3-esmk3,Energy shield MK3 +equipment-name,pamk3-battmk3,Fusion battery +equipment-name,pamk3-pnr,Portable nuclear reactor +equipment-name,pamk3-se,Shielded singularity +item-name,rcalc-heat-dummy,Heat +item-name,rcalc-pollution-dummy,Pollution +item-name,rcalc-power-dummy,Power +item-name,rcalc-selection-tool,Rate Calculator selector +item-name,rb-crafter-blueprint,Temporary crafter blueprint +item-name,robot-attrition-crashed,Destroyed __1__ +entity-name,logistic-robot-dropped-cargo,Dropped cargo +entity-name,shield-projector,Shield projector +entity-name,shield-projector-shield-floor-east,Energy shield +entity-name,shield-projector-shield-floor-north,Energy shield +entity-name,shield-projector-shield-floor-northeast,Energy shield +entity-name,shield-projector-shield-floor-northwest,Energy shield +entity-name,shield-projector-shield-floor-south,Energy shield +entity-name,shield-projector-shield-floor-southeast,Energy shield +entity-name,shield-projector-shield-floor-southwest,Energy shield +entity-name,shield-projector-shield-floor-west,Energy shield +entity-name,shield-projector-shield-wall-east,Energy shield +entity-name,shield-projector-shield-wall-north,Energy shield +entity-name,shield-projector-shield-wall-northeast,Energy shield +entity-name,shield-projector-shield-wall-northwest,Energy shield +entity-name,shield-projector-shield-wall-south,Energy shield +entity-name,shield-projector-shield-wall-southeast,Energy shield +entity-name,shield-projector-shield-wall-southwest,Energy shield +entity-name,shield-projector-shield-wall-west,Energy shield +entity-name,shield-projector-barrier,Energy shield +entity-name,sil-filter-combinator,Filter Combinator +entity-name,sil-filter-combinator-cc,Filter Combinator +entity-name,sil-filter-combinator-ac,Filter Combinator +entity-name,sil-filter-combinator-dc,Filter Combinator +entity-name,se-linked-container,Arcolink storage +entity-name,vase,Vase +entity-name,wooden-barrel,Wooden barrel +entity-name,furnace-ruin,Ruined stone stack +entity-name,workshop-ruin,Ruined workshop +entity-name,iron-wood-chest,Old chest +entity-name,iron-wood-chest-remnants,Ruined old chest +entity-name,stone-rubble,Stone rubble +entity-name,se-gate-blocker,Unstable space +entity-name,se-gate-blocker-void,Unstable space +entity-name,destroyed-cargo-pod,Destroyed cargo pod +entity-name,meteorite,Meteorite +entity-name,rocket-fragment,Rocket fragment +entity-name,se-antimatter-reactor,Antimatter reactor +entity-name,se-beryllium-ore,Beryl +entity-name,se-cargo-rocket-cargo-pod,Cargo pod +entity-name,se-casting-machine,Casting machine +entity-name,se-cryonite,Cryonite +entity-name,se-condenser-turbine,Condenser turbine +entity-name,se-condenser-turbine-tank,Condenser turbine +entity-name,se-condenser-turbine-generator,Condenser turbine +entity-name,se-core-fragment-processor,Core fragment processor +entity-name,se-core-miner,Core mining drill +entity-name,se-core-miner-drill,Core mining drill +entity-name,se-cryogun-ice,Ice wall +entity-name,se-dimensional-anchor,Dimensional anchor +entity-name,se-electric-boiler,Electric boiler +entity-name,se-fluid-burner-generator,Fluid isothermic generator +entity-name,se-fuel-refinery,Fuel refinery +entity-name,se-gate-fragment,Artifact fragment +entity-name,se-holmium-ore,Holminite +entity-name,se-iridium-ore,Iridite +entity-name,se-meteor-defence-container,Meteor defence installation +entity-name,se-meteor-defence-charger,Meteor defence installation +entity-name,se-meteor-point-defence-container,Meteor point defence +entity-name,se-meteor-point-defence-charger,Meteor point defence +entity-name,se-meteor-point-defence-charger-overcharged,Meteor point defence - Quickcharge mode +entity-name,se-methane-ice,Methane ice +entity-name,se-naquium-ore,Naquitite +entity-name,se-pulveriser,Pulveriser +entity-name,se-delivery-cannon-capsule-projectile,Delivery capsule projectile +entity-name,se-delivery-cannon-weapon-capsule-projectile,Weapon delivery capsule projectile +entity-name,se-rocket-launch-pad,Cargo rocket silo +entity-name,se-rocket-launch-pad-tank,Cargo rocket silo +entity-name,se-rocket-launch-pad-silo,Cargo rocket silo +entity-name,se-rocket-launch-pad-combinator,Cargo rocket silo +entity-name,se-rocket-launch-pad-_-seat,Cargo rocket silo +entity-name,se-rocket-launch-pad-settings,Cargo rocket silo +entity-name,se-rocket-landing-pad,Cargo landing pad +entity-name,se-space-accumulator,Holmium accumulator +entity-name,se-space-accumulator-2,Naquium accumulator +entity-name,se-space-astrometrics-laboratory,Astrometrics facility +entity-name,se-space-biochemical-laboratory,Biochemical facility +entity-name,se-space-assembling-machine,Space assembling machine +entity-name,se-space-capsule,Space capsule +entity-name,se-space-capsule-_-vehicle,Space capsule +entity-name,se-space-capsule-scorched,Compromised space capsule +entity-name,se-space-capsule-scorched-_-vehicle,Compromised space capsule +entity-name,se-space-curved-rail,Curved space rail +entity-name,se-space-decontamination-facility,Decontamination facility +entity-name,se-space-electromagnetics-laboratory,Electromagnetics facility +entity-name,se-space-elevator,Space elevator +entity-name,se-space-elevator-lamp,Space elevator lamp +entity-name,se-space-elevator-energy-interface,Space elevator energy buffer +entity-name,se-space-elevator-energy-pole,Space elevator wire connection +entity-name,se-space-elevator-train-stop,Space elevator internal train stop +entity-name,se-space-elevator-straight-rail,Space elevator internal rail +entity-name,se-space-elevator-curved-rail,Space elevator internal rail +entity-name,se-space-elevator-rail-signal,Space elevator internal rail signal +entity-name,se-space-elevator-collider,Space elevator train detector +entity-name,se-space-elevator-tug,Space elevator tug +entity-name,se-space-genetics-laboratory,Genetics facility +entity-name,se-space-growth-facility,Growth facility +entity-name,se-space-gravimetrics-laboratory,Gravimetrics facility +entity-name,se-space-hypercooler,Hypercooler +entity-name,se-space-laser-laboratory,Laser facility +entity-name,se-lifesupport-facility,Lifesupport facility +entity-name,se-space-manufactory,Space manufactory +entity-name,se-space-material-fabricator,Material fabricator +entity-name,se-space-mechanical-laboratory,Mechanical facility +entity-name,se-space-particle-accelerator,Particle accelerator +entity-name,se-space-particle-collider,Particle collider +entity-name,se-space-plasma-generator,Plasma generator +entity-name,se-space-radiation-laboratory,Radiation facility +entity-name,se-space-radiator,Thermal radiator +entity-name,se-space-radiator-2,Thermal radiator 2 +entity-name,se-recycling-facility,Recycling facility +entity-name,se-space-pipe,Space pipe +entity-name,se-space-pipe-long,Long space pipe +entity-name,se-space-pipe-long-straight,Long straight space pipe __1__ +entity-name,se-space-pipe-long-junction,Long junction space pipe __1__ +entity-name,se-space-pipe-to-ground,Space pipe to ground +entity-name,se-space-science-lab,Space science laboratory +entity-name,se-space-solar-panel,Flat solar panel +entity-name,se-space-solar-panel-2,Flat solar panel 2 +entity-name,se-space-solar-panel-3,Flat solar panel 3 +entity-name,se-space-spectrometry-facility,Spectrometry facility +entity-name,se-space-straight-rail,Straight space rail +entity-name,se-space-supercomputer-1,Supercomputer +entity-name,se-space-supercomputer-2,Quantum supercomputer +entity-name,se-space-supercomputer-3,Neural supercomputer +entity-name,se-space-supercomputer-4,Deep supercomputer +entity-name,se-space-telescope-radio,Radio telescope +entity-name,se-space-telescope-microwave,Microwave telescope +entity-name,se-space-telescope,Telescope +entity-name,se-space-telescope-xray,Xray telescope +entity-name,se-space-telescope-gammaray,Gamma ray telescope +entity-name,se-space-thermodynamics-laboratory,Thermodynamics facility +entity-name,se-space-splitter,Space splitter +entity-name,se-space-transport-belt,Space transport belt +entity-name,se-space-underground-belt,Space underground belt +entity-name,se-spaceship-antimatter-engine,Spaceship antimatter engine +entity-name,se-spaceship-antimatter-booster-tank,Spaceship antimatter booster tank +entity-name,se-spaceship-console,Spaceship console +entity-name,se-spaceship-console-output,Spaceship console signal output +entity-name,se-spaceship-console-alt,Damaged spaceship console +entity-name,se-spaceship-gate,Spaceship door +entity-name,se-spaceship-ion-engine,Spaceship ion engine +entity-name,se-spaceship-ion-booster-tank,Spaceship ion booster tank +entity-name,se-spaceship-obstacle,Space debris +entity-name,se-spaceship-rocket-engine,Spaceship rocket engine +entity-name,se-spaceship-rocket-booster-tank,Spaceship rocket booster tank +entity-name,se-spaceship-wall,Spaceship wall +entity-name,se-spaceship-circuit-network-restore,Spaceship circuit network restorer +entity-name,se-water-ice,Water ice +entity-name,se-vitamelange,Vitamelange +entity-name,se-vulcanite,Vulcanite +entity-name,small-asteroid,Small asteroid +entity-name,medium-asteroid,Medium asteroid +entity-name,large-asteroid,Large asteroid +entity-name,se-gate-part,Artifact piece +entity-name,se-gate-platform-scaffold,Artifact jury rig +entity-name,se-gate-lock-switch,Movable component +entity-name,se-gate-lock-combinator,Combinator-attachment +entity-name,se-gate-platform,Artifact augmentation platform +entity-name,se-gate-platform-combinator,Combinator-attachment +entity-name,se-gate-energy-interface,Power platform +entity-name,se-gate-platform-button-switch,Button +entity-name,se-gate-tank-input,Fluid input +entity-name,se-gate-tank-output,Fluid output +entity-name,se-pyramid-a,Geometric structure +entity-name,se-pyramid-b,Geometric structure +entity-name,se-pyramid-c,Geometric structure +entity-name,se-cartouche-a,Cartouche +entity-name,se-cartouche-b-a,Cartouche +entity-name,se-cartouche-b-b,Cartouche +entity-name,se-cartouche-chest,Ancient container +entity-name,se-glyph,Glyph +entity-name,glyph,Glyph +entity-name,se-gate-addon,Artifact augmentation +entity-name,se-gate-platform-button-middle,Stop +entity-name,se-gate-platform-button-left,Left +entity-name,se-gate-platform-button-right,Right +entity-name,se-compact-beacon,Compact beacon +entity-name,se-compact-beacon-2,Compact beacon 2 +entity-name,se-wide-beacon,Wide area beacon +entity-name,se-wide-beacon-2,Wide area beacon 2 +entity-name,se-supercharger,Supercharger +entity-name,se-addon-power-pole,Addon power pole +entity-name,se-pylon,Pylon +entity-name,se-pylon-substation,Pylon substation +entity-name,se-pylon-construction,Construction pylon +entity-name,se-pylon-construction-roboport,Construction pylon +entity-name,se-pylon-construction-radar,Radar construction pylon +entity-name,se-pylon-construction-radar-roboport,Radar construction pylon +entity-name,se-pylon-construction-radar-radar,Radar construction pylon +entity-name,se-shield-projector,Shield projector +entity-name,se-shield-projector-shield-floor-east,Energy shield +entity-name,se-shield-projector-shield-floor-north,Energy shield +entity-name,se-shield-projector-shield-floor-northeast,Energy shield +entity-name,se-shield-projector-shield-floor-northwest,Energy shield +entity-name,se-shield-projector-shield-floor-south,Energy shield +entity-name,se-shield-projector-shield-floor-southeast,Energy shield +entity-name,se-shield-projector-shield-floor-southwest,Energy shield +entity-name,se-shield-projector-shield-floor-west,Energy shield +entity-name,se-shield-projector-shield-wall-east,Energy shield +entity-name,se-shield-projector-shield-wall-north,Energy shield +entity-name,se-shield-projector-shield-wall-northeast,Energy shield +entity-name,se-shield-projector-shield-wall-northwest,Energy shield +entity-name,se-shield-projector-shield-wall-south,Energy shield +entity-name,se-shield-projector-shield-wall-southeast,Energy shield +entity-name,se-shield-projector-shield-wall-southwest,Energy shield +entity-name,se-shield-projector-shield-wall-west,Energy shield +entity-name,se-shield-projector-barrier,Energy shield +entity-name,se-naquium-heat-pipe,Naquium heat pipe +entity-name,se-naquium-heat-pipe-horizontal,Naquium heat pipe horizontal +entity-name,se-naquium-heat-pipe-vertical,Naquium heat pipe vertical +entity-name,se-naquium-heat-pipe-long,Naquium heat pipe long __1__ +entity-name,se-deep-space-transport-belt,Deep space transport belt +entity-name,se-deep-space-transport-belt-black,Black deep space transport belt +entity-name,se-deep-space-transport-belt-white,White deep space transport belt +entity-name,se-deep-space-transport-belt-red,Red deep space transport belt +entity-name,se-deep-space-transport-belt-yellow,Yellow deep space transport belt +entity-name,se-deep-space-transport-belt-green,Green deep space transport belt +entity-name,se-deep-space-transport-belt-cyan,Cyan deep space transport belt +entity-name,se-deep-space-transport-belt-blue,Blue deep space transport belt +entity-name,se-deep-space-transport-belt-magenta,Magenta deep space transport belt +entity-name,se-deep-space-underground-belt,Deep space underground belt +entity-name,se-deep-space-underground-belt-black,Black deep space underground belt +entity-name,se-deep-space-underground-belt-white,White deep space underground belt +entity-name,se-deep-space-underground-belt-red,Red deep space underground belt +entity-name,se-deep-space-underground-belt-yellow,Yellow deep space underground belt +entity-name,se-deep-space-underground-belt-green,Green deep space underground belt +entity-name,se-deep-space-underground-belt-cyan,Cyan deep space underground belt +entity-name,se-deep-space-underground-belt-blue,Blue deep space underground belt +entity-name,se-deep-space-underground-belt-magenta,Magenta deep space underground belt +entity-name,se-deep-space-splitter,Deep space splitter +entity-name,se-deep-space-splitter-black,Black deep space splitter +entity-name,se-deep-space-splitter-white,White deep space splitter +entity-name,se-deep-space-splitter-red,Red deep space splitter +entity-name,se-deep-space-splitter-yellow,Yellow deep space splitter +entity-name,se-deep-space-splitter-green,Green deep space splitter +entity-name,se-deep-space-splitter-cyan,Cyan deep space splitter +entity-name,se-deep-space-splitter-blue,Blue deep space splitter +entity-name,se-deep-space-splitter-magenta,Magenta deep space splitter +entity-name,se-core-seam,Core seam +entity-name,se-core-seam-type,Core seam (__1__) +entity-name,se-big-turbine,High temperature turbine generator +entity-name,se-big-turbine-generator-NW,High temperature turbine generator +entity-name,se-big-turbine-generator-SE,High temperature turbine generator +entity-name,se-big-turbine-tank,High temperature turbine generator +entity-name,se-big-heat-exchanger,High temperature heat exchanger +entity-name,se-blueprint-registration-point,Blueprint registration point +entity-name,se-delivery-cannon,Delivery cannon +entity-name,se-delivery-cannon-settings,Delivery cannon +entity-name,se-delivery-cannon-energy-interface,Delivery cannon +entity-name,se-delivery-cannon-chest,Delivery cannon chest +entity-name,se-delivery-cannon-weapon,Weapons delivery cannon +entity-name,se-delivery-cannon-weapon-settings,Weapons delivery cannon +entity-name,se-delivery-cannon-weapon-energy-interface,Weapons delivery cannon +entity-name,se-spaceship-clamp,Spaceship clamp +entity-name,se-spaceship-clamp-place,Spaceship clamp +entity-name,se-spaceship-clamp-power-pole-external-east,Spaceship clamp wire pass-through +entity-name,se-spaceship-clamp-power-pole-external-west,Spaceship clamp wire pass-through +entity-name,se-bloater-pool-cloud,Bloatburst pool +entity-name,se-energy-beam,Energy beam +entity-name,se-energy-transmitter-emitter,Energy beam emitter +entity-name,se-energy-transmitter-chamber,Energy beam chamber +entity-name,se-energy-transmitter-injector,Energy beam injector +entity-name,se-energy-transmitter-injector-reactor,Energy beam injector +entity-name,se-energy-receiver,Energy beam receiver +entity-name,se-energy-beam-defence,Umbrella +entity-name,se-nexus,Nexus +entity-name,se-nexus-charger,Nexus +entity-name,se-space-probe-rocket,Space probe rocket +entity-name,se-space-probe-rocket-silo,Space probe rocket silo +entity-name,se-interburbulator-interface,Interburbulator interface +entity-name,se-interburbulator-control,Interburbulator control +entity-name,se-interburbulator-projector,Interburbulator projector +entity-name,se-burbulator,Brontion Burbulator 33027756 +entity-name,se-core-seam-fissure,Core fissure +entity-name,se-core-seam-smoke-generator,Core seam smoke +entity-name,se-space-exploration-logo-shattered-15tiles,Space Exploration logo shattered 15 tiles +entity-name,se-space-exploration-logo-shattered-22tiles,Space Exploration logo shattered 22 tiles +entity-name,se-space-exploration-logo-shattered-30tiles,Space Exploration logo shattered 30 tiles +entity-name,se-space-exploration-logo-shadow-15tiles,Space Exploration logo shadow 15 tiles +entity-name,se-space-exploration-logo-shadow-22tiles,Space Exploration logo shadow 22 tiles +entity-name,se-space-exploration-logo-shadow-30tiles,Space Exploration logo shadow 30 tiles +entity-name,se-space-exploration-logo-white-15tiles,Space Exploration logo white 15 tiles +entity-name,se-space-exploration-logo-black-15tiles,Space Exploration logo black 15 tiles +entity-name,se-biter-friend,Friend +entity-name,se-biter-friend-corpse,Friend corpse +entity-name,kr-se-space-loader,Space loader +entity-name,kr-atmospheric-condenser-_-waterless,Atmospheric condenser (waterless) +entity-name,se-kr-big-fuel-refinery,Big fuel refinery +equipment-name,energy-shield-mk3-equipment,Energy shield MK3 +equipment-name,energy-shield-mk4-equipment,Energy shield MK4 +equipment-name,energy-shield-mk5-equipment,Energy shield MK5 +equipment-name,energy-shield-mk6-equipment,Energy shield MK6 +equipment-name,se-adaptive-armour-equipment-1,Adaptive armour MK1 +equipment-name,se-adaptive-armour-equipment-2,Adaptive armour MK2 +equipment-name,se-adaptive-armour-equipment-3,Adaptive armour MK3 +equipment-name,se-adaptive-armour-equipment-4,Adaptive armour MK4 +equipment-name,se-adaptive-armour-equipment-5,Adaptive armour MK5 +equipment-name,se-rtg-equipment,Portable RTG +equipment-name,se-rtg-equipment-2,Portable RTG MK2 +equipment-name,se-lifesupport-equipment-1,Lifesupport equipment MK1 +equipment-name,se-lifesupport-equipment-2,Lifesupport equipment MK2 +equipment-name,se-lifesupport-equipment-3,Lifesupport equipment MK3 +equipment-name,se-lifesupport-equipment-4,Lifesupport equipment MK4 +fluid-name,se-antimatter-stream,Antimatter stream +fluid-name,se-bio-sludge,Biosludge +fluid-name,se-contaminated-bio-sludge,Contaminated biosludge +fluid-name,se-contaminated-space-water,Contaminated cosmic water +fluid-name,se-chemical-gel,Chemical gel +fluid-name,se-decompressing-steam,Internal turbine steam +fluid-name,se-liquid-rocket-fuel,Liquid rocket fuel +fluid-name,se-methane-gas,Methane gas +fluid-name,se-methane-gas-mixed,Mixed methane gas +fluid-name,se-nutrient-gel,Nutrient gel +fluid-name,se-neural-gel,Neural gel +fluid-name,se-neural-gel-2,Advanced neural gel +fluid-name,se-ion-stream,Ion stream +fluid-name,se-plasma-stream,Plasma stream +fluid-name,se-particle-stream,Particle stream +fluid-name,se-proton-stream,Proton stream +fluid-name,se-space-coolant,Thermofluid 25°C +fluid-name,se-space-coolant-hot,Thermofluid 25°C +fluid-name,se-space-coolant-warm,Cool thermofluid -10°C +fluid-name,se-space-coolant-cold,Cold thermofluid -100°C +fluid-name,se-space-coolant-supercooled,Supercooled thermofluid -273°C +fluid-name,se-space-water,Cosmic water +fluid-name,se-beryllium-hydroxide,Beryllium hydroxide +fluid-name,se-cryonite-slush,Cryonite slush +fluid-name,se-vitalic-acid,Vitalic acid +fluid-name,se-molten-iron,Molten iron +fluid-name,se-molten-copper,Molten copper +fluid-name,se-molten-holmium,Molten holmium +fluid-name,se-molten-beryllium,Molten beryllium +fluid-name,se-pyroflux,Pyroflux +fluid-name,se-kr-imersium-sulfide,Imersium sulfide +fluid-name,dirty-water-ir,Dirty Iridium Water +fluid-name,dirty-water-ho,Dirty Holmium Water +item-name,spidertron,Spidertron +item-name,core-fragment,Core fragment (__1__) +item-name,effectivity-module-4,Efficiency module 4 +item-name,effectivity-module-5,Efficiency module 5 +item-name,effectivity-module-6,Efficiency module 6 +item-name,effectivity-module-7,Efficiency module 7 +item-name,effectivity-module-8,Efficiency module 8 +item-name,effectivity-module-9,Efficiency module 9 +item-name,productivity-module-4,Productivity module 4 +item-name,productivity-module-5,Productivity module 5 +item-name,productivity-module-6,Productivity module 6 +item-name,productivity-module-7,Productivity module 7 +item-name,productivity-module-8,Productivity module 8 +item-name,productivity-module-9,Productivity module 9 +item-name,se-satellite-telemetry,Satellite telemetry +item-name,se-antimatter-canister,Antimatter canister +item-name,se-ion-canister,Ion canister +item-name,se-astrometric-data,Astrometric data +item-name,se-astronomic-catalogue-1,Astronomic catalogue +item-name,se-astronomic-catalogue-2,Broad astronomic catalogue +item-name,se-astronomic-catalogue-3,Comprehensive astronomic catalogue +item-name,se-astronomic-catalogue-4,Extended astronomic catalogue +item-name,se-astronomic-insight,Astronomic insight +item-name,se-astronomic-science-pack-1,Astronomic science pack 1 +item-name,se-astronomic-science-pack-2,Astronomic science pack 2 +item-name,se-astronomic-science-pack-3,Astronomic science pack 3 +item-name,se-astronomic-science-pack-4,Astronomic science pack 4 +item-name,se-atomic-data,Atomic data +item-name,se-beryllium-ore,Beryl +item-name,se-ballistic-shielding-data,Ballistic shielding data +item-name,se-beryllium-ore-crushed,Crushed beryl +item-name,se-beryllium-ore-washed,Washed beryl +item-name,se-beryllium-plate,Beryllium plate +item-name,se-beryllium-powder,Beryllium powder +item-name,se-beryllium-ingot,Beryllium ingot +item-name,se-beryllium-sulfate,Beryllium sulfate +item-name,se-bio-combustion-data,Bio combustion data +item-name,se-bio-combustion-resistance-data,Bio combustion resistance data +item-name,se-bio-spectral-data,Bio-spectral data +item-name,se-biochemical-data,Biochemical data +item-name,se-biochemical-resistance-data,Biochemical resistance data +item-name,se-bioculture,Bio-culture +item-name,se-bioelectrics-data,Bioelectric data +item-name,se-biological-catalogue-1,Biological catalogue +item-name,se-biological-catalogue-2,Broad biological catalogue +item-name,se-biological-catalogue-3,Comprehensive biological catalogue +item-name,se-biological-catalogue-4,Extended biological catalogue +item-name,se-biological-insight,Biological insight +item-name,se-biological-science-pack-1,Biological science pack 1 +item-name,se-biological-science-pack-2,Biological science pack 2 +item-name,se-biological-science-pack-3,Biological science pack 3 +item-name,se-biological-science-pack-4,Biological science pack 4 +item-name,se-biomechanical-data,Biomechanical data +item-name,se-biomechanical-resistance-data,Biomechanical resistance data +item-name,se-boson-data,Boson data +item-name,se-broken-data,Broken data card +item-name,se-canister,Secure canister +item-name,se-biogun,Bio gun +item-name,se-bloater-ammo,Bloatburst ammo +item-name,se-pheromone-ammo,Pheromone dart +item-name,se-cryogun,Cryogun +item-name,se-cryogun-ammo,Glacier ammo +item-name,se-rocket-launch-pad-silo-dummy-ingredient-item,Cargo rocket (Hidden Ingredient) +item-name,se-rocket-launch-pad-silo-dummy-result-item,Cargo rocket (Hidden Result) +item-name,se-cargo-rocket-cargo-pod,Cargo pod +item-name,se-cargo-rocket-fuel-tank,Rocket fuel tank +item-name,se-cargo-rocket-section,Cargo rocket section +item-name,se-cargo-rocket-section-packed,Cargo rocket section packed +item-name,se-cold-thermodynamics-data,Cold thermodynamics data +item-name,se-comparative-genetic-data,Comparative genetic data +item-name,se-compressive-strength-data,Compressive strength data +item-name,se-conductivity-data,Conductivity data +item-name,se-contaminated-scrap,Contaminated scrap +item-name,se-core-fragment-omni,Core fragment +item-name,se-corrosion-resistance-data,Corrosion resistance data +item-name,se-cryogenics-data,Cryogenics data +item-name,se-cryonite,Cryonite +item-name,se-cryonite-crushed,Crushed cryonite +item-name,se-cryonite-powder,Cryonite powder +item-name,se-cryonite-washed,Washed cryonite +item-name,se-cryonite-crystal,Cryonite crystal +item-name,se-cryonite-rod,Cryonite rod +item-name,se-cryonite-ion-exchange-beads,Anion ion exchange beads +item-name,se-dark-energy-data,Dark energy data +item-name,se-darkmatter-data,Dark matter data +item-name,se-data-storage-substrate-cleaned,Polished data storage substrate +item-name,se-data-storage-substrate,Rough data storage substrate +item-name,se-decompression-data,Decompression data +item-name,se-decompression-resistance-data,Decompression resistance data +item-name,se-universal-catalogue,Universal catalogue +item-name,se-deep-space-science-pack,Deep space science pack +item-name,se-deep-space-science-pack-1,Deep space science pack 1 +item-name,se-deep-space-science-pack-2,Deep space science pack 2 +item-name,se-deep-space-science-pack-3,Deep space science pack 3 +item-name,se-deep-space-science-pack-4,Deep space science pack 4 +item-name,se-doppler-shift-data,Doppler shift data +item-name,se-durability-data,Durability data +item-name,se-electrical-shielding-data,Electrical shielding data +item-name,se-electromagnetic-field-data,Electromagnetic field data +item-name,se-space-elevator-cable,Space elevator cable +item-name,se-empty-data,Blank data card +item-name,se-empty-lifesupport-canister,Empty lifesupport canister +item-name,se-energy-catalogue-1,Energy catalogue +item-name,se-energy-catalogue-2,Broad energy catalogue +item-name,se-energy-catalogue-3,Comprehensive energy catalogue +item-name,se-energy-catalogue-4,Extended energy catalogue +item-name,se-energy-insight,Energy insight +item-name,se-energy-science-pack-1,Energy science pack 1 +item-name,se-energy-science-pack-2,Energy science pack 2 +item-name,se-energy-science-pack-3,Energy science pack 3 +item-name,se-energy-science-pack-4,Energy science pack 4 +item-name,se-entanglement-data,Entanglement data +item-name,se-enriched-naquium,Enriched naquium +item-name,se-exotic-fission-data,Exotic fission data +item-name,se-exotic-singularity-data,Singularity data +item-name,se-explosion-shielding-data,Explosion shielding data +item-name,se-experimental-alloys-data,Experimental alloys data +item-name,se-experimental-biochemical-data,Experimental biochemical data +item-name,se-experimental-bioculture,Experimental bio-culture +item-name,se-experimental-genetic-data,Experimental genetic data +item-name,se-experimental-material-decay-data,Experimental material decay data +item-name,se-experimental-material-spectral-data,Experimental material spectral data +item-name,se-experimental-material,Experimental material prototype +item-name,se-experimental-specimen,Experimental biomass +item-name,se-experimental-superconductor,Superconductor prototype +item-name,se-forcefield-data,Forcefield data +item-name,se-friction-data,Friction data +item-name,se-fusion-test-data,Fusion test data +item-name,se-gammaray-detector,Gamma ray detector +item-name,se-gammaray-observation-data,Gamma ray observation data +item-name,se-gammaray-test-data,Gamma ray data +item-name,se-gate-fragment,Artifact fragment +item-name,se-genetic-data,Genetic data +item-name,se-gravity-wave-observation-data,Gravity wave observation data +item-name,se-gravity-wave-data,Gravity wave data +item-name,se-gravimetric-observation-data,Gravimetric observation data +item-name,se-gravimetric-test-data,Gravimetric test data +item-name,se-gravitational-lensing-data,Gravitational lensing data +item-name,se-heat-shielding,Heat shielding +item-name,se-holmium-ore,Holminite +item-name,se-holmium-ore-crushed,Crushed holminite +item-name,se-holmium-ore-washed,Washed holminite +item-name,se-holmium-chloride,Holmium chloride +item-name,se-holmium-powder,Holmium powder +item-name,se-holmium-plate,Holmium plate +item-name,se-holmium-ingot,Holmium ingot +item-name,se-hot-thermodynamics-data,Hot thermodynamics data +item-name,se-impact-shielding-data,Impact shielding data +item-name,se-infrared-observation-data,Infrared observation data +item-name,se-ion-spectrometry-data,Ion spectrometry data +item-name,se-iridium-ore,Iridite +item-name,se-iridium-ore-crushed,Crushed iridite +item-name,se-iridium-ore-washed,Washed iridite +item-name,se-iridium-piledriver,Iridium piledriver +item-name,se-iridium-powder,Iridium powder +item-name,se-iridium-blastcake,Iridium blastcake +item-name,se-iridium-plate,Iridium plate +item-name,se-iridium-ingot,Iridium ingot +item-name,se-junk-data,Junk data card +item-name,se-laser-shielding-data,Laser shielding data +item-name,se-lepton-data,Lepton data +item-name,se-lifesupport-canister,Lifesupport canister +item-name,se-machine-learning-data,Machine learning data +item-name,se-magnetic-canister,Magnetic canister +item-name,se-magnetic-monopole-data,Magnetic monopole data +item-name,se-material-decay-data,Material decay data +item-name,se-material-science-pack-1,Material science pack 1 +item-name,se-material-science-pack-2,Material science pack 2 +item-name,se-material-science-pack-3,Material science pack 3 +item-name,se-material-science-pack-4,Material science pack 4 +item-name,se-material-spectral-data,Material spectral data +item-name,se-material-testing-pack,Material testing pack +item-name,se-material-catalogue-1,Material catalogue +item-name,se-material-catalogue-2,Broad material catalogue +item-name,se-material-catalogue-3,Comprehensive material catalogue +item-name,se-material-catalogue-4,Extended material catalogue +item-name,se-material-insight,Material insight +item-name,se-medpack,Medpack +item-name,se-medpack-2,Medpack 2 +item-name,se-medpack-3,Medpack 3 +item-name,se-medpack-4,Medpack 4 +item-name,se-meteor-defence,Meteor defence installation +item-name,se-meteor-defence-ammo,Meteor defence installation ammo +item-name,se-meteor-point-defence,Meteor point defence +item-name,se-meteor-point-defence-ammo,Meteor point defence ammo +item-name,se-methane-ice,Methane ice +item-name,se-micro-black-hole-data,Micro black hole data +item-name,se-microwave-observation-data,Microwave observation data +item-name,se-negative-pressure-data,Negative pressure data +item-name,se-nano-cold-thermodynamics-data,Nanomaterial cold thermodynamics data +item-name,se-nano-compressive-strength-data,Nanomaterial compressive strength data +item-name,se-nano-hot-thermodynamics-data,Nanomaterial hot thermodynamics data +item-name,se-nanomaterial,Nanomaterial +item-name,se-nano-tensile-strength-data,Nanomaterial tensile strength data +item-name,se-naquium-ore,Naquitite +item-name,se-naquium-ore-crushed,Crushed naquitite +item-name,se-naquium-ore-washed,Washed naquitite +item-name,se-naquium-refined,Refined naquitite +item-name,se-naquium-crystal,Naquitite crystal +item-name,se-naquium-powder,Naquium powder +item-name,se-naquium-plate,Naquium plate +item-name,se-naquium-ingot,Naquium ingot +item-name,se-neural-anomaly-data,Neural anomaly data +item-name,se-nutrient-vat,Nutrient vat +item-name,se-observation-frame-blank,Blank observation frame +item-name,se-observation-frame-gammaray,Gamma ray observation frame +item-name,se-observation-frame-infrared,Infrared observation frame +item-name,se-observation-frame-microwave,Microwave observation frame +item-name,se-observation-frame-radio,Radio wave observation frame +item-name,se-observation-frame-uv,UV observation frame +item-name,se-observation-frame-visible,Visible observation frame +item-name,se-observation-frame-xray,Xray observation frame +item-name,se-orbital-data,Orbital calculations data +item-name,se-particle-beam-shielding-data,Particle beam shielding data +item-name,se-plague-bomb,Plague rocket +item-name,se-plasma-canister,Plasma canister +item-name,se-plasma-electrodynamics-data,Plasma electrodynamics data +item-name,se-plasma-thermodynamics-data,Plasma thermodynamics data +item-name,se-polarisation-data,Polarisation data +item-name,se-pressure-containment-data,Pressure containment data +item-name,se-quantum-phenomenon-data,Quantum phenomenon data +item-name,se-quark-data,Quark data +item-name,se-radiation-data,Radiation data +item-name,se-radiation-exposure-data,Radiation exposure data +item-name,se-radiation-exposure-resistance-data,Radiation resistance data +item-name,se-radiation-shielding-data,Radiation shielding data +item-name,se-radio-observation-data,Radio wave observation data +item-name,se-rigidity-data,Rigidity data +item-name,se-rtg-equipment,Portable RTG +item-name,se-rtg-equipment-2,Portable RTG MK2 +item-name,se-scrap,Scrap +item-name,se-shear-strength-data,Shear strength data +item-name,se-significant-data,Significant data +item-name,se-significant-specimen,Significant biomass +item-name,se-singularity-data,Singularity data +item-name,se-space-capsule,Space capsule +item-name,se-space-capsule-scorched,Compromised space capsule +item-name,se-space-mirror,Multispectral Mirror +item-name,se-space-platform-plating,Space platform plating +item-name,se-space-platform-scaffold,Space platform scaffold +item-name,se-space-rail,Space rail +item-name,se-spaceship-floor,Spaceship floor +item-name,se-specimen,Biomass +item-name,se-subatomic-data,Subatomic data +item-name,se-superconductivity-data,Superconductivity data +item-name,se-superconductor,Superconductor +item-name,se-superconductive-cable,Superconductive cable +item-name,se-tensile-strength-data,Tensile strength data +item-name,se-tesla-ammo,Tesla gun ammo +item-name,se-tesla-gun,Tesla gun +item-name,se-thruster-suit,Thruster suit +item-name,se-thruster-suit-2,Thruster suit MK2 +item-name,se-thruster-suit-3,Thruster suit MK3 +item-name,se-thruster-suit-4,Thruster suit MK4 +item-name,se-timespace-anomaly-data,Timespace anomaly data +item-name,se-used-lifesupport-canister,Used lifesupport canister +item-name,se-uv-observation-data,UV observation data +item-name,se-visible-observation-data,Visible observation data +item-name,se-vitamelange,Vitamelange +item-name,se-vitamelange-nugget,Vitamelange nugget +item-name,se-vitamelange-bloom,Vitamelange bloom +item-name,se-vitamelange-roast,Vitamelange roast +item-name,se-vitamelange-spice,Vitamelange spice +item-name,se-vitamelange-extract,Vitamelange extract +item-name,se-vulcanite,Vulcanite +item-name,se-vulcanite-pure,Pure vulcanite +item-name,se-vulcanite-enriched,Enriched vulcanite +item-name,se-vulcanite-crushed,Crushed vulcanite +item-name,se-vulcanite-washed,Washed vulcanite +item-name,se-vulcanite-block,Vulcanite block +item-name,se-vulcanite-ion-exchange-beads,Cation ion exchange beads +item-name,se-water-ice,Water ice +item-name,se-xray-observation-data,Xray observation data +item-name,se-zero-point-energy-data,Zero point energy data +item-name,se-rocket-science-pack,Rocket science pack +item-name,se-computer-science-pack,Computer science pack +item-name,speed-module-4,Speed module 4 +item-name,speed-module-5,Speed module 5 +item-name,speed-module-6,Speed module 6 +item-name,speed-module-7,Speed module 7 +item-name,speed-module-8,Speed module 8 +item-name,speed-module-9,Speed module 9 +item-name,se-aeroframe-pole,Aeroframe pole +item-name,se-aeroframe-scaffold,Aeroframe scaffold +item-name,se-aeroframe-bulkhead,Aeroframe bulkhead +item-name,se-lattice-pressure-vessel,Lattice pressure vessel +item-name,se-heavy-girder,Heavy girder +item-name,se-heavy-bearing,Heavy bearing +item-name,se-heavy-composite,Heavy composite +item-name,se-heavy-assembly,Heavy assembly +item-name,se-bioscrubber,Bioscrubber +item-name,se-vitalic-epoxy,Vitalic epoxy +item-name,se-vitalic-reagent,Vitalic reagent +item-name,se-vitalic-acid,Vitalic acid +item-name,se-self-sealing-gel,Self-sealing gel +item-name,se-holmium-cable,Holmium cable +item-name,se-holmium-solenoid,Holmium solenoid +item-name,se-quantum-processor,Quantum processor +item-name,se-dynamic-emitter,Dynamic emitter +item-name,se-naquium-processor,Naquium processor +item-name,se-naquium-cube,Naquium cube +item-name,se-naquium-tessaract,Naquium tesseract +item-name,se-compact-beacon,Compact beacon +item-name,se-compact-beacon-2,Compact beacon 2 +item-name,se-wide-beacon,Wide area beacon +item-name,se-wide-beacon-2,Wide area beacon 2 +item-name,se-lifesupport-equipment-1,Lifesupport equipment MK1 +item-name,se-lifesupport-equipment-2,Lifesupport equipment MK2 +item-name,se-lifesupport-equipment-3,Lifesupport equipment MK3 +item-name,se-lifesupport-equipment-4,Lifesupport equipment MK4 +item-name,se-naquium-heat-pipe,Naquium heat pipe +item-name,se-naquium-heat-pipe-horizontal,Naquium heat pipe horizontal +item-name,se-naquium-heat-pipe-vertical,Naquium heat pipe vertical +item-name,se-naquium-heat-pipe-long,Naquium heat pipe long __1__ +item-name,se-deep-space-transport-belt,Deep space transport belt +item-name,se-deep-space-transport-belt-black,Black deep space transport belt +item-name,se-deep-space-transport-belt-white,White deep space transport belt +item-name,se-deep-space-transport-belt-red,Red deep space transport belt +item-name,se-deep-space-transport-belt-yellow,Yellow deep space transport belt +item-name,se-deep-space-transport-belt-green,Green deep space transport belt +item-name,se-deep-space-transport-belt-cyan,Cyan deep space transport belt +item-name,se-deep-space-transport-belt-blue,Blue deep space transport belt +item-name,se-deep-space-transport-belt-magenta,Magenta deep space transport belt +item-name,se-deep-space-underground-belt,Deep space underground belt +item-name,se-deep-space-underground-belt-black,Black deep space underground belt +item-name,se-deep-space-underground-belt-white,White deep space underground belt +item-name,se-deep-space-underground-belt-red,Red deep space underground belt +item-name,se-deep-space-underground-belt-yellow,Yellow deep space underground belt +item-name,se-deep-space-underground-belt-green,Green deep space underground belt +item-name,se-deep-space-underground-belt-cyan,Cyan deep space underground belt +item-name,se-deep-space-underground-belt-blue,Blue deep space underground belt +item-name,se-deep-space-underground-belt-magenta,Magenta deep space underground belt +item-name,se-deep-space-splitter,Deep space splitter +item-name,se-deep-space-splitter-black,Black deep space splitter +item-name,se-deep-space-splitter-white,White deep space splitter +item-name,se-deep-space-splitter-red,Red deep space splitter +item-name,se-deep-space-splitter-yellow,Yellow deep space splitter +item-name,se-deep-space-splitter-green,Green deep space splitter +item-name,se-deep-space-splitter-cyan,Cyan deep space splitter +item-name,se-deep-space-splitter-blue,Blue deep space splitter +item-name,se-deep-space-splitter-magenta,Magenta deep space splitter +item-name,se-blueprint-registration-point,Blueprint registration point +item-name,se-delivery-cannon-capsule,Delivery cannon capsule +item-name,se-delivery-cannon-capsule-packed,Delivery cannon capsule: __1__ +item-name,se-delivery-cannon-targeter,Delivery cannon targeter +item-name,se-delivery-cannon-weapon-capsule,Weapon delivery capsule +item-name,se-delivery-cannon-weapon-capsule-packed,Weapon delivery capsule: __1__ +item-name,se-delivery-cannon-weapon-targeter,Weapon delivery cannon targeter +item-name,se-delivery-cannon-artillery-targeter,Weapon delivery cannon targeting remote: __1__ +item-name,se-energy-transmitter-targeter,Energy beam targeter +item-name,se-arcosphere,Arcosphere +item-name,se-arcosphere-a,λ Arcosphere lambda +item-name,se-arcosphere-b,ξ Arcosphere xi +item-name,se-arcosphere-c,ζ Arcosphere zeta +item-name,se-arcosphere-d,θ Arcosphere theta +item-name,se-arcosphere-e,ε Arcosphere epsilon +item-name,se-arcosphere-f,φ Arcosphere phi +item-name,se-arcosphere-g,γ Arcosphere gamma +item-name,se-arcosphere-h,ω Arcosphere omega +item-name,se-arcosphere-collector,Arcosphere collector +item-name,se-star-probe,Star probe +item-name,se-belt-probe,Asteroid belt probe +item-name,se-void-probe,Interstellar void probe +item-name,se-star-probe-data,Star probe data +item-name,se-belt-probe-data,Asteroid belt probe data +item-name,se-void-probe-data,Interstellar void probe data +item-name,se-nano-engineering-data,Nanoengineering data +item-name,se-annihilation-data,Annihilation data +item-name,se-naquium-structural-data,Naquium structural data +item-name,se-hyperlattice-data,Hyperlattice data +item-name,se-naquium-energy-data,Naquium energy data +item-name,se-space-fold-data,Space folding data +item-name,se-space-warp-data,Space warping data +item-name,se-space-dilation-data,Space dilation data +item-name,se-space-injection-data,Space injection data +item-name,se-interstellar-data,Interstellar travel data +item-name,se-teleportation-data,Teleportation data +item-name,se-wormhole-data,Wormhole data +item-name,se-rhga-data,Reality hypergraph analysis data +item-name,se-deep-catalogue-1,Deep space catalogue +item-name,se-deep-catalogue-2,Broad deep space catalogue +item-name,se-deep-catalogue-3,Comprehensive deep space catalogue +item-name,se-deep-catalogue-4,Extended deep space catalogue +item-name,se-space-probe-rocket,Space probe rocket +item-name,se-space-probe-rocket-deployed,Space probe rocket (Deployed) +item-name,se-railgun,Railgun +item-name,se-railgun-ammo,Railgun ammo +item-name,se-space-capsule-targeter,Space capsule landing targeter +item-name,se-train-gui-targeter,Cross-surface train targeter +item-name,se-iron-ingot,Iron ingot +item-name,se-steel-ingot,Steel ingot +item-name,se-copper-ingot,Copper ingot +item-name,se-kr-imersite-powder,Crushed imersite +item-name,se-kr-fine-imersite-powder,Fine imersite powder +item-name,se-capsule-se-biter-friend,Sleeping friend +item-name,se-kr-advanced-catalogue-1,Advanced catalogue +item-name,se-kr-advanced-catalogue-2,Broad advanced catalogue +item-name,se-kr-combined-catalogue,Combined catalogue +item-name,se-kr-remote-probe,Remote sensing probe +item-name,se-kr-power-density-data,Power density data +item-name,se-kr-quantum-computation-data,Quantum computation data +item-name,se-kr-remote-sensing-data,Remote Sensing data +item-name,se-kr-macroscale-entanglement-data,Macroscale entanglement data +item-name,se-kr-timespace-manipulation-data,Timespace manipulation data +item-name,se-kr-singularity-application-data,Singularity application data +item-name,kr-quantum-computer,Advanced research server +item-name,kr-singularity-beacon,Advanced beacon +item-name,se-kr-matter-catalogue-1,Matter catalogue +item-name,se-kr-matter-catalogue-2,Broad matter catalogue +item-name,se-kr-matter-synthesis-data,Matter synthesis data +item-name,se-kr-matter-containment-data,Matter containment data +item-name,se-kr-matter-liberation-data,Matter liberation data +item-name,se-kr-matter-science-pack-2,Matter science pack 2 +item-name,se-kr-matter-manipulation-data,Matter manipulation data +item-name,se-kr-matter-recombination-data,Matter recombination data +item-name,se-kr-matter-stabilization-data,Matter stabilization data +item-name,se-kr-matter-utilization-data,Matter utilization data +item-name,se-kr-basic-stabilizer,Basic matter stabilizer +item-name,se-kr-charged-basic-stabilizer,Charged basic matter stabilizer +item-name,se-kr-rocket-tech-card,Rocket tech card +item-name,se-kr-intergalactic-transceiver-activation,Activated intergalactic transceiver +virtual-signal-name,signal-speed,Speed signal +virtual-signal-name,se-signal-speed,Speed signal +virtual-signal-name,signal-distance,Distance signal +virtual-signal-name,se-signal-distance,Distance signal +virtual-signal-name,se-star,Star +virtual-signal-name,se-planet,Planet +virtual-signal-name,se-planet-orbit,Planet orbit +virtual-signal-name,se-moon,Moon +virtual-signal-name,se-moon-orbit,Moon orbit +virtual-signal-name,se-asteroid-belt,Asteroid belt +virtual-signal-name,se-asteroid-field,Asteroid field +virtual-signal-name,se-anomaly,Anomaly +virtual-signal-name,se-meteor,Meteor +virtual-signal-name,se-spaceship,Spaceship +virtual-signal-name,se-cargo-rocket,Cargo rocket +virtual-signal-name,se-remote-view,Remote view +virtual-signal-name,se-death,Death +virtual-signal-name,se-character-corpse,Corpse +virtual-signal-name,se-ruin,Ruin +virtual-signal-name,se-accolade,Accolade +virtual-signal-name,se-remove,Remove +virtual-signal-name,se-radius,Radius +virtual-signal-name,se-hierarchy,Hierarchy +virtual-signal-name,se-spaceship-launch,Spaceship launch +virtual-signal-name,se-anchor-using-left-clamp,Anchor using spaceship left clamp +virtual-signal-name,se-anchor-using-right-clamp,Anchor using spaceship right clamp +virtual-signal-name,se-anchor-to-left-clamp,Anchor to target left clamp +virtual-signal-name,se-anchor-to-right-clamp,Anchor to target right clamp +virtual-signal-name,se-beacon-overload,Beacon overload +virtual-signal-name,se-warning,Warning +virtual-signal-name,se-danger,Danger +virtual-signal-name,se-core-seam,Core seam +virtual-signal-name,se-heat,Heat +virtual-signal-name,se-select-icon,Select icon +virtual-signal-name,se-nav-arrow-land,Arrow land +virtual-signal-name,se-nav-arrow-launch,Arrow launch +virtual-signal-name,se-nav-arrow-up-right,Arrow up-right +virtual-signal-name,se-nav-arrow-up-left,Arrow up-left +virtual-signal-name,se-nav-arrow-left-up,Arrow left-up +virtual-signal-name,se-nav-arrow-left-down,Arrow left-down +virtual-signal-name,se-nav-arrows-cross,Arrows cross +virtual-signal-name,se-pin,Pin +entity-name,spidertron-enhancements-dummy-spidertron,Travelling __1__ +entity-name,spidertron-enhancements-corpse,Spidertron corpse +entity-name,stack-constant-combinator,Stack constant combinator +entity-name,stack-constant-combinator-internal,Stack constant combinator (internal) +entity-name,textplate,__1__ __2__ text plate +entity-name,textplate-legacy,Legacy __1__ __2__ __3__ +item-name,textplate,__1__ __2__ text plate +item-name,textplate-legacy,Legacy __1__ __2__ __3__ +item-name,well-planner,Well Planner +item-name,merge-chest-selector,Chest Merge Tool +entity-name,rm_overlay,Resource Overlay +item-name,yarm-selector-tool,Resource monitor \ No newline at end of file diff --git a/web/public/factorio_german_items.csv b/web/public/factorio_german_items.csv new file mode 100644 index 0000000..2735eb0 --- /dev/null +++ b/web/public/factorio_german_items.csv @@ -0,0 +1,1664 @@ +section,item_key,localized_name +entity-name,1x2-remnants,Überreste 1×2 +entity-name,accumulator,Akkumulator +entity-name,acid-splash,Säurepfütze +entity-name,arithmetic-combinator,Kombinator für Berechnungen +entity-name,artillery-turret,Artillerie-Geschützturm +entity-name,artillery-wagon,Artilleriewaggon +entity-name,assembling-machine-1,Montagemaschine 1 +entity-name,assembling-machine-2,Montagemaschine 2 +entity-name,assembling-machine-3,Montagemaschine 3 +entity-name,beacon,Effektverteiler +entity-name,behemoth-biter,Riesiger Beißer +entity-name,behemoth-biter-corpse,Toter riesiger Beißer +entity-name,behemoth-spitter,Riesiger Speier +entity-name,behemoth-spitter-corpse,Toter riesiger Speier +entity-name,behemoth-worm-corpse,Toter riesiger Wurm +entity-name,behemoth-worm-turret,Riesiger Wurm +entity-name,big-artillery-explosion,Große Explosion durch Artilleriegranate +entity-name,big-biter,Großer Beißer +entity-name,big-biter-corpse,Toter großer Beißer +entity-name,big-electric-pole,Großer Strommast +entity-name,big-explosion,Große Explosion +entity-name,big-remnants,Große Überreste +entity-name,big-scorchmark,Große Brandspur +entity-name,big-scorchmark-tintable,Große gefärbte Brandspur +entity-name,big-ship-wreck-1,Großes Schiffswrack +entity-name,big-ship-wreck-2,Großes Schiffswrack +entity-name,big-ship-wreck-3,Großes Schiffswrack +entity-name,big-spitter,Großer Speier +entity-name,big-spitter-corpse,Toter großer Speier +entity-name,big-worm-corpse,Toter großer Wurm +entity-name,big-worm-turret,Großer Wurm +entity-name,biter-spawner,Beißernest +entity-name,biter-spawner-corpse,Totes Beißernest +entity-name,blood-explosion-big,Große Blut-Explosion +entity-name,blood-explosion-huge,Riesige Blut-Explosion +entity-name,blood-explosion-small,Kleine Blut-Explosion +entity-name,blood-fountain,Blut-Fontäne +entity-name,blood-fountain-big,Große Blut-Fontäne +entity-name,blood-fountain-hit-spray,Blutspritzer durch Treffer +entity-name,blue-chest,Blaue Kiste +entity-name,boiler,Heizkessel +entity-name,burner-generator,Befeuerter Generator +entity-name,burner-inserter,Befeuerter Greifarm +entity-name,burner-mining-drill,Befeuerter Erzförderer +entity-name,car,Auto +entity-name,cargo-wagon,Güterwaggon +entity-name,centrifuge,Zentrifuge +entity-name,character,Charakter +entity-name,character-corpse,Spielerleiche +entity-name,chemical-plant,Chemiefabrik +entity-name,cliff,Klippe +entity-name,coal,Kohle +entity-name,compilatron,Compilatron +entity-name,constant-combinator,Kombinator für Konstanten +entity-name,construction-robot,Bauroboter +entity-name,copper-cable,Kupferkabel +entity-name,copper-ore,Kupfererz +entity-name,crash-site-chest-1,Frachtkapsel +entity-name,crash-site-chest-2,Frachtkapsel +entity-name,crash-site-fire-flame,Flamme an der Absturzstelle +entity-name,crash-site-spaceship,Raumschiff +entity-name,crash-site-spaceship-wreck-big,großes Schiffswrack +entity-name,crash-site-spaceship-wreck-medium,mittelgroßes Schiffswrack +entity-name,crash-site-spaceship-wreck-small,kleines Schiffswrack +entity-name,crude-oil,Rohöl +entity-name,curved-rail,Gebogenes Gleis +entity-name,cutscene-gun-turret,Geschützturm +entity-name,dead-dry-hairy-tree,Toter vertrockneter borstiger Baum +entity-name,dead-grey-trunk,Toter grauer Baumstamm +entity-name,dead-tree-desert,Toter Wüstenbaum +entity-name,decider-combinator,Kombinator für Vergleiche +entity-name,deconstructible-tile-proxy,Kachel-Abriss-Markierung +entity-name,defender,Verteidiger +entity-name,destroyer,Zerstörer +entity-name,distractor,Ablenker +entity-name,dry-hairy-tree,Vertrockneter borstiger Baum +entity-name,dry-tree,Vertrockneter Baum +entity-name,electric-energy-interface,Schnittstelle für elektrische Energie +entity-name,electric-furnace,Lichtbogenofen +entity-name,electric-mining-drill,Elektrischer Erzförderer +entity-name,enemy-damaged-explosion,Beschädigende Explosion an einem Feind +entity-name,entity-ghost,Objekt-Geist +entity-name,explosion,Explosion +entity-name,explosion-hit,Explosionstreffer +entity-name,express-loader,Express-Belader +entity-name,express-splitter,Express-Teilerfließband +entity-name,express-transport-belt,Express-Fließband +entity-name,express-underground-belt,Unterirdisches Express-Fließband +entity-name,factorio-logo-11tiles,Factorio-Logo (11 Kacheln) +entity-name,factorio-logo-16tiles,Factorio-Logo (16 Kacheln) +entity-name,factorio-logo-22tiles,Factorio-Logo (22 Kacheln) +entity-name,fast-inserter,Schneller Greifarm +entity-name,fast-loader,Schneller Belader +entity-name,fast-splitter,Schnelles Teilerfließband +entity-name,fast-transport-belt,Schnelles Fließband +entity-name,fast-underground-belt,Schnelles unterirdisches Fließband +entity-name,filter-inserter,Filternder Greifarm +entity-name,fire-flame,Feuer +entity-name,fish,Fisch +entity-name,flamethrower-turret,Flammenwerfer-Geschützturm +entity-name,fluid-wagon,Tankwaggon +entity-name,flying-robot-damaged-explosion,Beschädigende Explosion an einem fliegenden Roboter +entity-name,gate,Tor +entity-name,green-coral,Grüne Koralle +entity-name,grenade-explosion,Explosion durch Granate +entity-name,ground-explosion,Bodenexplosion +entity-name,gun-turret,Geschützturm +entity-name,heat-exchanger,Wärmetauscher +entity-name,heat-interface,Schnittstelle für Wärme +entity-name,heat-pipe,Wärmerohr +entity-name,huge-scorchmark,Riesige Brandspur +entity-name,huge-scorchmark-tintable,Riesige gefärbte Brandspur +entity-name,infinity-chest,Unendlichkeitskiste +entity-name,infinity-pipe,Unendlichkeitsrohr +entity-name,inserter,Greifarm +entity-name,iron-chest,Eisenkiste +entity-name,iron-ore,Eisenerz +entity-name,item-on-ground,Gegenstand auf dem Boden +entity-name,item-request-proxy,Anforderungsplatz für Gegenstände +entity-name,lab,Labor +entity-name,land-mine,Landmine +entity-name,laser-bubble,Laserblase +entity-name,laser-turret,Laser-Geschützturm +entity-name,linked-belt,Verbundenes Fließband +entity-name,linked-chest,Verbundene Kiste +entity-name,loader,Belader +entity-name,loader-1x1,Belader 1×1 +entity-name,locomotive,Lokomotive +entity-name,logistic-chest-active-provider,Aktive Anbieterkiste +entity-name,logistic-chest-buffer,Pufferkiste +entity-name,logistic-chest-passive-provider,Passive Anbieterkiste +entity-name,logistic-chest-requester,Anforderungskiste +entity-name,logistic-chest-storage,Lagerkiste +entity-name,logistic-robot,Logistikroboter +entity-name,long-handed-inserter,Langer Greifarm +entity-name,market,Markt +entity-name,massive-explosion,Massive Explosion +entity-name,medium-biter,Mittelgroßer Beißer +entity-name,medium-biter-corpse,Toter mittelgroßer Beißer +entity-name,medium-electric-pole,Mittelgroßer Strommast +entity-name,medium-explosion,Mittelgroße Explosion +entity-name,medium-remnants,Mittelgroße Überreste +entity-name,medium-scorchmark,Mittelgroße Brandspur +entity-name,medium-scorchmark-tintable,Mittelgroße gefärbte Brandspur +entity-name,medium-ship-wreck,Mittelgroßes Schiffswrack +entity-name,medium-small-remnants,Mittelgroße Überreste +entity-name,medium-spitter,Mittelgroßer Speier +entity-name,medium-spitter-corpse,Toter mittelgroßer Speier +entity-name,medium-worm-corpse,Toter mittelgroßer Wurm +entity-name,medium-worm-turret,Mittelgroßer Wurm +entity-name,nuclear-reactor,Kernreaktor +entity-name,offshore-pump,Gewässerpumpe +entity-name,oil-refinery,Ölraffinerie +entity-name,pipe,Rohr +entity-name,pipe-to-ground,Unterirdisches Rohr +entity-name,player-port,Spawnpunkt +entity-name,poison-cloud,Giftwolke +entity-name,power-switch,Stromschalter +entity-name,programmable-speaker,Programmierbarer Lautsprecher +entity-name,pump,Pumpe +entity-name,pumpjack,Förderpumpe +entity-name,radar,Radar +entity-name,rail-chain-signal,Zug-Kettensignal +entity-name,rail-ending-remnants,Überreste eines Gleisendes +entity-name,rail-signal,Zugsignal +entity-name,red-chest,Rote Kiste +entity-name,red-desert-rock-big,Großer roter Wüstenfelsen +entity-name,red-desert-rock-huge,Riesiger roter Wüstenfelsen +entity-name,roboport,Roboterhangar +entity-name,rock-big,Großer Felsen +entity-name,rock-damaged-explosion,Beschädigende Explosion an einem Felsen +entity-name,rock-huge,Riesiger Felsen +entity-name,rocket,Rakete +entity-name,rocket-silo,Raketensilo +entity-name,sand-rock-big,Großer sandiger Felsen +entity-name,simple-entity-with-force,Einfaches Objekt mit Partei +entity-name,simple-entity-with-owner,Einfaches Objekt mit Besitzer +entity-name,small-biter,Kleiner Beißer +entity-name,small-biter-corpse,Toter kleiner Beißer +entity-name,small-cliff,Kleine Klippe +entity-name,small-electric-pole,Kleiner Strommast +entity-name,small-lamp,Lampe +entity-name,small-remnants,Kleine Überreste +entity-name,small-scorchmark,Kleine Brandspur +entity-name,small-scorchmark-tintable,Kleine gefärbte Brandspur +entity-name,small-ship-wreck,Kleines Schiffswrack +entity-name,small-spitter,Kleiner Speier +entity-name,small-spitter-corpse,Toter kleiner Speier +entity-name,small-worm-corpse,Toter kleiner Wurm +entity-name,small-worm-turret,Kleiner Wurm +entity-name,solar-panel,Solarpanel +entity-name,space-module-wreck,Rettungskapsel-Wrack +entity-name,spark-explosion,Funken-Explosion +entity-name,spark-explosion-higher,Hohe Funken-Explosion +entity-name,spidertron,Spidertron +entity-name,spidertron-leg,Spidertron-Bein +entity-name,spidertron-military-target,Spidertron-Militärziel +entity-name,spitter-spawner,Speiernest +entity-name,spitter-spawner-corpse,Totes Speiernest +entity-name,splitter,Teilerfließband +entity-name,stack-filter-inserter,Filternder Stapelgreifarm +entity-name,stack-inserter,Stapelgreifarm +entity-name,steam-engine,Dampfmaschine +entity-name,steam-turbine,Dampfturbine +entity-name,steel-chest,Stahlkiste +entity-name,steel-furnace,Hochofen +entity-name,stone,Stein +entity-name,stone-furnace,Schmelzofen +entity-name,stone-wall,Mauer +entity-name,storage-tank,Lagertank +entity-name,straight-rail,Gerades Gleis +entity-name,substation,Umspannwerk +entity-name,tank,Panzer +entity-name,tile-ghost,Kachel-Geist +entity-name,tile-proxy,Kacheln +entity-name,train-stop,Zughaltestelle +entity-name,transport-belt,Fließband +entity-name,tree,Baum +entity-name,tree-brown,Brauner Baum +entity-name,tree-dying-proxy,Durch Schädigung von Bäumen absorbierte Umweltverschmutzung +entity-name,tree-proxy,Bäume +entity-name,tree-red,Roter Baum +entity-name,tree-stump,Baumstumpf +entity-name,underground-belt,Unterirdisches Fließband +entity-name,uranium-cannon-shell-explosion,Explosion durch uranversetztes Kanonengeschoss +entity-name,uranium-ore,Uranerz +entity-name,wall-damaged-explosion,Beschädigende Explosion an einer Mauer +entity-name,water-splash,Wasserspritzer +entity-name,water-well-pump,Brunnenpumpe +entity-name,wooden-chest,Holzkiste +equipment-name,battery-equipment,Persönlicher Akku +equipment-name,battery-mk2-equipment,Persönlicher Akku 2 +equipment-name,belt-immunity-equipment,Fließbandimmunitäts-Ausrüstung +equipment-name,discharge-defense-equipment,Entladungsverteidigung +equipment-name,energy-shield-equipment,Energieschild +equipment-name,energy-shield-mk2-equipment,Energieschild 2 +equipment-name,exoskeleton-equipment,Exoskelett +equipment-name,fusion-reactor-equipment,Tragbarer Fusionsreaktor +equipment-name,night-vision-equipment,Nachtsichtgerät +equipment-name,personal-laser-defense-equipment,Persönliche Laserverteidigung +equipment-name,personal-roboport-equipment,Persönlicher Roboterhangar +equipment-name,personal-roboport-mk2-equipment,Persönlicher Roboterhangar 2 +equipment-name,solar-panel-equipment,Tragbares Solarpanel +fluid-name,crude-oil,Rohöl +fluid-name,heavy-oil,Schweröl +fluid-name,light-oil,Leichtöl +fluid-name,lubricant,Schmiermittel +fluid-name,petroleum-gas,Flüssiggas +fluid-name,steam,Dampf +fluid-name,sulfuric-acid,Schwefelsäure +fluid-name,water,Wasser +item-name,advanced-circuit,Erweiterter Schaltkreis +item-name,artillery-shell,Artilleriegranate +item-name,artillery-targeting-remote,Fernsteuerung für Artillerie +item-name,artillery-turret,Artillerie-Geschützturm +item-name,artillery-wagon-cannon,Artilleriekanone +item-name,atomic-bomb,Atombombe +item-name,automation-science-pack,Wissenschaftspaket für Automatisierung +item-name,battery,Batterie +item-name,belt-immunity-equipment,Fließbandimmunitäts-Ausrüstung +item-name,blueprint,Blaupause +item-name,blueprint-book,Blaupausenbuch +item-name,burner-generator,Befeuerter Generator +item-name,cannon-shell,Kanonengeschoss +item-name,chemical-science-pack,Wissenschaftspaket für Chemie +item-name,cliff-explosives,Klippensprengstoff +item-name,cluster-grenade,Splittergranate +item-name,coal,Kohle +item-name,coin,Münze +item-name,combat-shotgun,Kampfschrotflinte +item-name,concrete,Beton +item-name,copper-cable,Kupferkabel +item-name,copper-ore,Kupfererz +item-name,copper-plate,Kupferplatte +item-name,copy-paste-tool,Kopieren-Einfügen-Werkzeug +item-name,crude-oil-barrel,Rohöl im Fass +item-name,cut-paste-tool,Ausschneiden-Einfügen-Werkzeug +item-name,deconstruction-planner,Abrissplan +item-name,defender-capsule,Verteidiger-Kapsel +item-name,destroyer-capsule,Zerstörer-Kapsel +item-name,discharge-defense-remote,Fernbedienung für die Entladungsverteidigung +item-name,distractor-capsule,Ablenker-Kapsel +item-name,effectivity-module,Effizienzmodul +item-name,effectivity-module-2,Effizienzmodul 2 +item-name,effectivity-module-3,Effizienzmodul 3 +item-name,electric-energy-interface,Schnittstelle für elektrische Energie +item-name,electric-engine-unit,Elektromotor-Einheit +item-name,electronic-circuit,Elektronischer Schaltkreis +item-name,empty-barrel,Leeres Fass +item-name,engine-unit,Motor-Einheit +item-name,explosive-cannon-shell,Explosives Kanonengeschoss +item-name,explosive-rocket,Explosive Rakete +item-name,explosive-uranium-cannon-shell,Explosives uranversetztes Kanonengeschoss +item-name,explosives,Sprengstoff +item-name,filled-barrel,__1__ im Fass +item-name,firearm-magazine,Schusswaffen-Munition +item-name,fish,Fisch +item-name,flamethrower,Flammenwerfer +item-name,flamethrower-ammo,Brennstoff für Flammenwerfer +item-name,flamethrower-turret,Flammenwerfer-Geschützturm +item-name,flying-robot-frame,Flugrobotergestell +item-name,green-wire,Grünes Signalkabel +item-name,grenade,Granate +item-name,hazard-concrete,Beton mit Warnmarkierung +item-name,heat-interface,Schnittstelle für Wärme +item-name,heavy-armor,Schwere Rüstung +item-name,infinity-chest,Unendlichkeitskiste +item-name,infinity-pipe,Unendlichkeitsrohr +item-name,iron-gear-wheel,Eisenzahnrad +item-name,iron-ore,Eisenerz +item-name,iron-plate,Eisenplatte +item-name,iron-stick,Eisenstange +item-name,item-with-inventory,Gegenstand mit Inventar +item-name,item-with-label,Gegenstand mit Bezeichnung +item-name,item-with-tags,Gegenstand mit Markierungen +item-name,lab,Labor +item-name,landfill,Landaufschüttung +item-name,laser-turret,Laser-Geschützturm +item-name,light-armor,Leichte Rüstung +item-name,linked-chest,Verbundene Kiste +item-name,logistic-science-pack,Wissenschaftspaket für Logistik +item-name,low-density-structure,Leichtbauteil +item-name,military-science-pack,Wissenschaftspaket für Militär +item-name,modular-armor,Modulare Rüstung +item-name,nuclear-fuel,Uranversetzter Brennstoff +item-name,piercing-rounds-magazine,Panzerbrechende Munition +item-name,piercing-shotgun-shell,Panzerbrechende Schrotpatronen +item-name,pistol,Pistole +item-name,plastic-bar,Kunststoffstange +item-name,poison-capsule,Gift-Kapsel +item-name,pollution,Umweltverschmutzung +item-name,power-armor,Hochleistungsrüstung +item-name,power-armor-mk2,Hochleistungsrüstung 2 +item-name,processing-unit,Prozessoreinheit +item-name,production-science-pack,Wissenschaftspaket für Produktion +item-name,productivity-module,Produktivitätsmodul +item-name,productivity-module-2,Produktivitätsmodul 2 +item-name,productivity-module-3,Produktivitätsmodul 3 +item-name,rail,Gleis +item-name,rail-planner,Gleisplaner +item-name,raw-fish,Roher Fisch +item-name,red-wire,Rotes Signalkabel +item-name,refined-concrete,Stahlbeton +item-name,refined-hazard-concrete,Stahlbeton mit Warnmarkierung +item-name,repair-pack,Reparaturkit +item-name,rocket,Rakete +item-name,rocket-control-unit,Raketensteuereinheit +item-name,rocket-fuel,Raketenbrennstoff +item-name,rocket-launcher,Raketenwerfer +item-name,rocket-part,Raketenbauteil +item-name,satellite,Satellit +item-name,selection-tool,Auswahlwerkzeug +item-name,shotgun,Schrotflinte +item-name,shotgun-shell,Schrotpatronen +item-name,simple-entity-with-force,Einfaches Objekt mit Partei +item-name,simple-entity-with-owner,Einfaches Objekt mit Besitzer +item-name,slowdown-capsule,Verlangsamungs-Kapsel +item-name,solar-panel,Solarpanel +item-name,solid-fuel,Festbrennstoff +item-name,space-science-pack,Wissenschaftspaket für Weltraumforschung +item-name,speed-module,Tempomodul +item-name,speed-module-2,Tempomodul 2 +item-name,speed-module-3,Tempomodul 3 +item-name,spidertron-remote,Spidertron-Fernbedienung +item-name,spidertron-rocket-launcher,Spidertron-Raketenwerfer +item-name,steel-plate,Stahlträger +item-name,stone,Stein +item-name,stone-brick,Ziegelstein +item-name,stone-path,Steinweg +item-name,submachine-gun,Maschinenpistole +item-name,sulfur,Schwefel +item-name,tank-cannon,Panzerkanone +item-name,tank-flamethrower,Fahrzeug-Flammenwerfer +item-name,tank-machine-gun,Fahrzeug-Maschinengewehr +item-name,upgrade-planner,Upgradeplan +item-name,uranium-235,Uran-235 +item-name,uranium-238,Uran-238 +item-name,uranium-cannon-shell,Uranversetztes Kanonengeschoss +item-name,uranium-fuel-cell,Uran-Brennelement +item-name,uranium-ore,Uranerz +item-name,uranium-rounds-magazine,Uranversetzte Munition +item-name,used-up-uranium-fuel-cell,Verbrauchtes Uran-Brennelement +item-name,utility-science-pack,Wissenschaftspaket für Zubehör +item-name,vehicle-machine-gun,Fahrzeug-Maschinengewehr +item-name,wood,Holz +virtual-signal-name,signal-0,Signal 0 +virtual-signal-name,signal-1,Signal 1 +virtual-signal-name,signal-2,Signal 2 +virtual-signal-name,signal-3,Signal 3 +virtual-signal-name,signal-4,Signal 4 +virtual-signal-name,signal-5,Signal 5 +virtual-signal-name,signal-6,Signal 6 +virtual-signal-name,signal-7,Signal 7 +virtual-signal-name,signal-8,Signal 8 +virtual-signal-name,signal-9,Signal 9 +virtual-signal-name,signal-A,Signal A +virtual-signal-name,signal-B,Signal B +virtual-signal-name,signal-C,Signal C +virtual-signal-name,signal-D,Signal D +virtual-signal-name,signal-E,Signal E +virtual-signal-name,signal-F,Signal F +virtual-signal-name,signal-G,Signal G +virtual-signal-name,signal-H,Signal H +virtual-signal-name,signal-I,Signal I +virtual-signal-name,signal-J,Signal J +virtual-signal-name,signal-K,Signal K +virtual-signal-name,signal-L,Signal L +virtual-signal-name,signal-M,Signal M +virtual-signal-name,signal-N,Signal N +virtual-signal-name,signal-O,Signal O +virtual-signal-name,signal-P,Signal P +virtual-signal-name,signal-Q,Signal Q +virtual-signal-name,signal-R,Signal R +virtual-signal-name,signal-S,Signal S +virtual-signal-name,signal-T,Signal T +virtual-signal-name,signal-U,Signal U +virtual-signal-name,signal-V,Signal V +virtual-signal-name,signal-W,Signal W +virtual-signal-name,signal-X,Signal X +virtual-signal-name,signal-Y,Signal Y +virtual-signal-name,signal-Z,Signal Z +virtual-signal-name,signal-anything,Irgendetwas +virtual-signal-name,signal-black,Schwarzes Signal +virtual-signal-name,signal-blue,Blaues Signal +virtual-signal-name,signal-check,Häkchen-Signal +virtual-signal-name,signal-cyan,Türkisfarbenes Signal +virtual-signal-name,signal-dot,Punkt-Signal +virtual-signal-name,signal-each,Jeweils +virtual-signal-name,signal-everything,Alles +virtual-signal-name,signal-green,Grünes Signal +virtual-signal-name,signal-grey,Graues Signal +virtual-signal-name,signal-info,Info-Signal +virtual-signal-name,signal-pink,Rosa Signal +virtual-signal-name,signal-red,Rotes Signal +virtual-signal-name,signal-white,Weißes Signal +virtual-signal-name,signal-yellow,Gelbes Signal +item-name,stone-tablet,Steinplatte +item-name,motor,Motor +item-name,electric-motor,Elektrischer Motor +item-name,burner-lab,Befeuertes Forschungslabor +item-name,burner-assembling-machine,Befeuerte Montagemaschine +item-name,burner-turbine,Befeuerter Turbinengenerator +item-name,small-electric-pole,Kleiner hölzerner Strommast +item-name,small-iron-electric-pole,Kleiner eisener Strommast +item-name,processed-fuel,Fahrzeug-Kraftstoff +item-name,wooden-chest,Hölzerne Kiste +item-name,stone-wall,Steinmauer +item-name,concrete-block-wall,Betonsteinmauer +item-name,concrete-wall,Betonmauer +item-name,refined-concrete-wall,Verbesserte Betonmauer +item-name,steel-wall,Mauer mit Stahlspitzen +item-name,sand,Sand +item-name,solid-sand,Fester Sand +item-name,washed-sand,Fester Sand +item-name,glass,Glas +item-name,area-mining-drill,Großer Erzförderer +entity-name,burner-lab,Befeuertes Forschungslabor +entity-name,burner-assembling-machine,Befeuerte Montagemaschine +entity-name,burner-turbine,Befeuerter Turbinengenerator +entity-name,burner-turbine-water,Befeuerter Turbinengenerator +entity-name,burner-turbine-generator,Befeuerter Turbinengenerator +entity-name,powered-offshore-pump,Offshore Pumpe +entity-name,offshore-pump-output,Offshore Pumpe +entity-name,small-iron-electric-pole,Kleiner eisener Strommast +entity-name,aai-big-ship-wreck-1,Trümmer +entity-name,aai-big-ship-wreck-2,Trümmer +entity-name,aai-big-ship-wreck-3,Trümmer +entity-name,aai-medium-ship-wreck-1,Trümmer +entity-name,aai-medium-ship-wreck-2,Trümmer +entity-name,aai-small-ship-wreck,Trümmerteil +entity-name,fuel-processor,Kraftstoff-Raffinerie +entity-name,concrete-block-wall,Betonsteinmauer +entity-name,concrete-wall,Betonmauer +entity-name,refined-concrete-wall,Verbesserte Betonmauer +entity-name,steel-wall,Betonmauer mit Stahlspitzen +entity-name,industrial-furnace,Industrieller Ofen +entity-name,area-mining-drill,Großer Erzförderer +entity-name,aai-signal-sender,Signaltransmitter +entity-name,aai-signal-receiver,Signalempfänger +entity-name,aai-signal-receiver-combinator,Signalempfänger +entity-name,aai-filter,Signalfilter +virtual-signal-name,se-select-icon,Wähle Symbol +item-name,gunship,Aufklärungs-Flugzeug +item-name,aircraft-machine-gun,Maschinengewehr +item-name,aircraft-rocket-launcher,Raketenwerfer +item-name,cargo-plane,Frachtflugzeug +item-name,jet,Düsenjäger +item-name,flying-fortress,Fliegende Festung +item-name,cargo-plane-machine-gun,Maschinengewehr +item-name,aircraft-cannon,Kanone +item-name,high-explosive-cannon-shell,Hochexplosives Kanonengeschoss +item-name,flying-fortress-machine-gun,Fliegende Festungs Maschinengewehr +item-name,flying-fortress-rocket-launcher,Fliegende Festungs Raketenwerfer +item-name,napalm-launcher,Napalmwerfer +item-name,cheat-machine,Cheat Maschine +item-name,aircraft-energy-shield,Flugzeug-Energieschild +item-name,aircraft-afterburner,Nachbrenner +item-name,napalm,Napalm +entity-name,gunship,Aufklärungs-Flugzeug +entity-name,cargo-plane,Frachtflugzeug +entity-name,jet,Düsenjäger +entity-name,flying-fortress,Fliegende Festung +entity-name,cheat-machine,Cheat Maschine +entity-name,napalm_fire_flame,Napalm Feuer +equipment-name,aircraft-energy-shield,Flugzeug-Energieschild +equipment-name,aircraft-afterburner,Nachbrenner +entity-name,farl,F.A.R.L. +item-name,farl,F.A.R.L. +item-name,farl-roboport,F.A.R.L. Modul +equipment-name,farl-roboport,F.A.R.L. Modul +entity-name,fluid-level-indicator,Füllstandsanzeige +entity-name,fluid-level-indicator-k2,Stahl-Füllstandsanzeige +entity-name,fluid-level-indicator-straight,Gerade Füllstandsanzeige +entity-name,fluid-level-indicator-straight-k2,Gerade Stahl-Füllstandsanzeige +entity-name,fluid-level-indicator-st-bobs-steel,Füllstandsanzeige MK2 +entity-name,fluid-level-indicator-st-bobs-plastic,Füllstandsanzeige MK3 +entity-name,fluid-level-indicator-st-bobs-tungsten,Füllstandsanzeige MK4 +entity-name,fluid-level-indicator-st-bobs-coppertungsten,Füllstandsanzeige MK5 +virtual-signal-name,informatron,InformaTron +entity-name,item-sensor,Inventarsensor +item-name,item-sensor,Inventarsensor +virtual-signal-name,inv-sensor-detected-locomotive,Lokomotive erkannt +virtual-signal-name,inv-sensor-detected-wagon,Güterwaggon erkannt +virtual-signal-name,inv-sensor-detected-car,Auto erkannt +virtual-signal-name,inv-sensor-detected-tank,Panzer erkannt +virtual-signal-name,inv-sensor-detected-spider,Spidertron erkannt +virtual-signal-name,inv-sensor-temperature,Temperatur +virtual-signal-name,inv-sensor-progress,Fortschritt +virtual-signal-name,inv-sensor-fuel,Brennstoff (MJ) +entity-name,jetpack-character,__1__ (fliegend) +equipment-name,jetpack-1,Jetpack Ausrüstung MK1 +equipment-name,jetpack-2,Jetpack Ausrüstung MK2 +equipment-name,jetpack-3,Jetpack Ausrüstung MK3 +equipment-name,jetpack-4,Jetpack Ausrüstung MK4 +item-name,jetpack-1,Jetpack Ausrüstung MK1 +item-name,jetpack-2,Jetpack Ausrüstung MK2 +item-name,jetpack-3,Jetpack Ausrüstung MK3 +item-name,jetpack-4,Jetpack Ausrüstung MK4 +entity-name,advanced-radar,Fortschrittliches Radar +entity-name,biusart-lab,Fortschrittliches Labor +entity-name,imersite,Imersit-Höhle +entity-name,kr-activated-intergalactic-transceiver,Intergalaktischer Transceiver aktiviert +entity-name,kr-advanced-assembling-machine,Fortschrittliche Montagemaschine +entity-name,kr-advanced-chemical-plant,Fortschrittliche Chemiefabrik +entity-name,kr-advanced-furnace,Fortschrittlicher Schmelzofen +entity-name,kr-advanced-loader,Fortschrittlicher Lader +entity-name,kr-advanced-solar-panel,Fortschrittliches Solarmodul +entity-name,kr-advanced-splitter,Fortschrittlicher Teiler +entity-name,kr-advanced-steam-turbine,Fortschrittliche Dampfturbine +entity-name,kr-advanced-tank,Panzer +entity-name,kr-advanced-transport-belt,Fortschrittliches Fließband +entity-name,kr-advanced-underground-belt,Fortschrittliches Untergrund Fließband +entity-name,kr-air-purifier,Luftreiniger +entity-name,kr-antimatter-reactor,Antimaterie Reaktor +entity-name,kr-armored-vehicle,Schweres gepanzertes Fahrzeug +entity-name,kr-atmospheric-condenser,Atmosphärenkondensator +entity-name,kr-big-active-provider-container,Aktive Anbieterlagerhalle +entity-name,kr-big-buffer-container,Pufferlagerhalle +entity-name,kr-big-container,Lagerhalle +entity-name,kr-big-passive-provider-container,Passive Anbieterlagerhalle +entity-name,kr-big-random-pipes-remnant,Große zufällige Rohre (Überbleibsel) +entity-name,kr-big-requester-container,Anforderungslagerhalle +entity-name,kr-big-storage-container,Logistiklagerhalle +entity-name,kr-bio-lab,Biolabor +entity-name,kr-construction-roboport,__1__ (Baumodus) +entity-name,kr-crusher,Zerkleinerer +entity-name,kr-damaged-ship-assembler,Beschädigte Schiffmontagemaschine +entity-name,kr-damaged-ship-reactor,Beschädigter Schiffsreaktor +entity-name,kr-damaged-ship-research-computer,Beschädigter Schiffsforschungscomputer +entity-name,kr-electric-mining-drill-mk2,Elektrischer Erzförderer 2 +entity-name,kr-electric-mining-drill-mk3,Elektrischer Erzförderer 3 +entity-name,kr-electrolysis-plant,Elektrolyseanlage +entity-name,kr-energy-storage,Energiespeicher +entity-name,kr-express-loader,Express Lader +entity-name,kr-fast-loader,Schneller Lader +entity-name,kr-filtration-plant,Filteranlage +entity-name,kr-fluid-burner,Gasfackel +entity-name,kr-fluid-storage-1,Grosser Lagertank +entity-name,kr-fluid-storage-2,Riesiger Lagertank +entity-name,kr-fuel-refinery,Treibstoffraffinerie +entity-name,kr-fusion-reactor,Fusionsreaktor +entity-name,kr-gas-power-station,Gaskraftwerk +entity-name,kr-greenhouse,Gewächshaus +entity-name,kr-intergalactic-transceiver,Intergalaktischer Transceiver +entity-name,kr-large-roboport,Grosser Roboport +entity-name,kr-laser-artillery-turret,Laser-Artillerieturm +entity-name,kr-loader,Lader +entity-name,kr-logistic-roboport,__1__ (Logistikmodus) +entity-name,kr-logo,Krastorio 2 Logo +entity-name,kr-matter-assembler,Materie Montagemaschine +entity-name,kr-matter-plant,Materieanlage +entity-name,kr-medium-active-provider-container,Mittelgrosser aktiver Anbietercontainer +entity-name,kr-medium-buffer-container,Mittelgrosser Puffercontainer +entity-name,kr-medium-container,Mittelgrosser Container +entity-name,kr-medium-passive-provider-container,Mittelgrosser passiver Anbietercontainer +entity-name,kr-medium-random-pipes-remnant,Mittelgrosse zufällige Rohre (Überbleibsel) +entity-name,kr-medium-requester-container,Mittelgrosser Anfragecontainer +entity-name,kr-medium-storage-container,Mittelgrosser Logistikcontainer +entity-name,kr-mineable-wreckage,Kleines Schiffswrack +entity-name,kr-mineral-water-pumpjack,Bohrpumpe für Mineralisiertes Wasser +entity-name,kr-nuclear-locomotive,Nuklear-Lokomotive +entity-name,kr-oil-pumpjack,Ölbohrturm +entity-name,kr-planetary-teleporter,Planetarischer Teleporter +entity-name,kr-quantum-computer,Quantencomputer +entity-name,kr-quarry-drill,Steinbruch Bohrer +entity-name,kr-railgun-turret,Railgun-Geschützturm +entity-name,kr-research-server,Forschungsserver +entity-name,kr-rocket-turret,Raketen-Geschützturm +entity-name,kr-se-deep-space-loader,Tieflader für den Weltraum +entity-name,kr-se-loader,Raumlader +entity-name,kr-sentinel,Sentinel +entity-name,kr-shelter-plus,Erweiterter Unterstand [color +entity-name,kr-shelter,Unterstand +entity-name,kr-singularity-beacon,Singularitätseffektverteier +entity-name,kr-singularity-lab,Singularitätslabor +entity-name,kr-small-roboport,Kleiner Roboter-Port +entity-name,kr-stabilizer-charging-station,Stabilisator-Ladestation +entity-name,kr-steel-pipe,Stahlrohr +entity-name,kr-steel-pipe-to-ground,Unterirdisches Stahlrohr +entity-name,kr-steel-pump,Stahlpumpe +entity-name,kr-substation-mk2,Umspannwerk MK2 +entity-name,kr-superior-filter-inserter,Überlegener Filter Greifarm +entity-name,kr-superior-inserter,Überlegener Greifarm +entity-name,kr-superior-loader,Überlegener Lader +entity-name,kr-superior-long-filter-inserter,Überlegener langer Filter Greifarm +entity-name,kr-superior-long-inserter,Überlegener langer Greifarm +entity-name,kr-superior-splitter,Überlegener Splitter +entity-name,kr-superior-transport-belt,Überlegenes Fließband +entity-name,kr-superior-underground-belt,Überlegenes Untergrund Fließband +entity-name,kr-tesla-coil,Tesla-Spule +entity-name,kr-wind-turbine,Windturbine +entity-name,mineral-water,Mineralisiertes Wasser +entity-name,poop-cloud,Mysteriöse Substanzwolke +entity-name,rare-metals,__ITEM__rare-metals__ +entity-name,turret-remnant,Geschützturm (Rest) +entity-name,virus-cloud,Viruswolke +equipment-name,additional-engine,Zusätzlicher Elektromotor +equipment-name,advanced-additional-engine,Fortschrittlicher zusätzlicher Elektromotor +equipment-name,advanced-exoskeleton-equipment,Fortschrittliches Exoskelett +equipment-name,antimatter-reactor-equipment,Tragbarer Antimateriereaktor +equipment-name,battery-mk3-equipment,Persönlicher Akku MK3 +equipment-name,big-battery-equipment,Großer persönlicher Akku +equipment-name,big-battery-mk2-equipment,Großer persönlicher Akku MK2 +equipment-name,big-battery-mk3-equipment,Großer persönlicher Akku MK3 +equipment-name,big-imersite-solar-panel-equipment,Großes tragbares Imersit-Solarpanel +equipment-name,big-solar-panel-equipment,Großes tragbares Solarpanel +equipment-name,cyber-potato-equipment,Cyberkartoffel +equipment-name,energy-absorber,Energieabsorber +equipment-name,imersite-night-vision-equipment,Imersit Nachtsichtgerät +equipment-name,imersite-solar-panel-equipment,Tragbares Imersit-Solarpanel +equipment-name,nuclear-reactor-equipment,Tragbarer Kernreaktor +equipment-name,personal-sniper-laser-defense-mk1-equipment,Persönliche Scharfschützen-Laser Verteidigung +equipment-name,personal-sniper-laser-defense-mk2-equipment,Persönliche Scharfschützen-Laser Verteidigung MK2 +equipment-name,personal-sniper-laser-defense-mk3-equipment,Persönliche Scharfschützen-Laser Verteidigung MK3 +equipment-name,personal-sniper-laser-defense-mk4-equipment,Persönliche Scharfschützen-Laser Verteidigung MK4 +equipment-name,personal-submachine-laser-defense-mk1-equipment,Persönliche Laser Verteidigung +equipment-name,personal-submachine-laser-defense-mk2-equipment,Persönliche Laser Verteidigung MK2 +equipment-name,personal-submachine-laser-defense-mk3-equipment,Persönliche Laser Verteidigung MK3 +equipment-name,personal-submachine-laser-defense-mk4-equipment,Persönliche Laser Verteidigung MK4 +equipment-name,portable-generator,Tragbarer Generator +equipment-name,power-armor-mk3,Kampfanzug MK3 +equipment-name,power-armor-mk4,Kampfanzug MK4 +equipment-name,shield-generator-mk1,Schildgenerator +equipment-name,shield-generator-mk2,Schildgenerator MK2 +equipment-name,shield-generator-mk3,Schildgenerator MK3 +equipment-name,shield-generator-mk4,Schildgenerator MK4 +equipment-name,small-portable-generator,"Kleiner, tragbarer Generator" +equipment-name,superior-exoskeleton-equipment,Verbessertes Exoskelett +equipment-name,vehicle-roboport,Fahrzeugroboterhangar MK1 +fluid-name,ammonia,Ammoniak +fluid-name,biomethanol,Biomethanol +fluid-name,chlorine,Chlor +fluid-name,dirty-water,Schmutzwasser +fluid-name,heavy-water,Schweres Wasser +fluid-name,hydrogen-chloride,Chlorwasserstoff +fluid-name,hydrogen,Wasserstoff +fluid-name,matter,Materie +fluid-name,mineral-water,Mineralwasser +fluid-name,nitric-acid,Salpetersäure +fluid-name,nitrogen,Stickstoff +fluid-name,oxygen,Sauerstoff +item-name,advanced-fuel,Verbesserter Kraftstoff +item-name,advanced-tank-cannon-a,Schweres Geschütz A +item-name,advanced-tank-cannon-b,Schweres Geschütz B +item-name,advanced-tank-cannon-c,Scharfschützen-Railgun +item-name,advanced-tank-laser-cannon,Laser-Geschütz +item-name,advanced-tank-machine-gun,Schweres Maschinengewehr +item-name,advanced-tech-card,Verbesserte Technologiekarte +item-name,ai-core,KI Kern +item-name,anti-material-rifle,Scharfschützengewehr +item-name,anti-material-rifle-magazine,Scharfschützengewehr-Magazin +item-name,antimatter-artillery-shell,Anti-Materie-Artilleriegranate +item-name,antimatter-railgun-shell,Anti-Materie-Railgun Munition +item-name,antimatter-rocket,Anti-Materie-Rakete +item-name,antimatter-turret-rocket,Anti-Materie-Geschützturm Rakete +item-name,armor-piercing-anti-material-rifle-magazine,Panzerbrechende Scharfschützengewehr -Magazin +item-name,armor-piercing-pistol-magazine,Panzerbrechende Anti-Materie-Pistolen-Magazin +item-name,armor-piercing-rifle-magazine,Panzerbrechende Anti-Materie-Gewehr-Magazin +item-name,automation-core,Automatisierungskern +item-name,automation-tech-card,Technologiekarte für Automatisierung +item-name,basic-railgun-shell,Railgun Geschoss +item-name,basic-tech-card,Basis Technologiekarte +item-name,bio-fuel,Bio-Kraftstoff +item-name,biomass,Biomasse +item-name,biters-research-data,Beißer-Forschungsdaten +item-name,blank-tech-card,Leere Technologiekarte +item-name,charged-antimatter-fuel-cell,Aufgeladene Antimaterie-Brennstoffzelle +item-name,charged-matter-stabilizer,Aufgeladener Materie-Stabilisator +item-name,chemical-tech-card,Technologiekarte für Chemie +item-name,coke,Koks +item-name,dolphin-gun,Weltraum-Delfinpistole +item-name,dt-fuel,DT-Brennstoffzelle +item-name,electronic-components,Elektronische Bauteile +item-name,empty-antimatter-fuel-cell,Leere Antimaterie-Brennstoffzelle +item-name,empty-dt-fuel,Leere DT-Brennstoffzelle +item-name,energy-control-unit,Energie-Steuereinheit +item-name,enriched-copper,Angereichertes Kupfer +item-name,enriched-iron,Angereichertes Eisen +item-name,enriched-rare-metals,Angereicherte Seltene Metalle +item-name,explosion-railgun-shell,Explosives Railgun Geschoss +item-name,explosive-turret-rocket,Explosive Geschützturm Rakete +item-name,explosive-turret-rocket-turret,Explosive Geschützturm Rakete +item-name,fertilizer,Dünger +item-name,first-aid-kit,Erste-Hilfe-Koffer +item-name,fuel,Kraftstoff +item-name,gps-satellite,GPS Satellit +item-name,heavy-rocket,Schwere Rakete +item-name,heavy-rocket-launcher,Schwerer Raketenwerfer +item-name,imersite-anti-material-rifle-magazine,Imersit Scharfschützengewehr Magazin +item-name,imersite-crystal,Imersitkristall +item-name,imersite,Imersit +item-name,imersite-powder,Imersitpulver +item-name,imersite-rifle-magazine,Imersit-Gewehrmagazin +item-name,imersite-rounds-magazine,Imersit-Gewehrmagazin +item-name,imersium-beam,Imersiumträger +item-name,imersium-gear-wheel,Imersium Zahnrad +item-name,imersium-plate,Imersium Platte +item-name,improved-pollution-filter,Verbesserter Filtereinsatz +item-name,impulse-rifle-ammo,Impulsgewehrmunition +item-name,impulse-rifle,Impulsgewehr +item-name,inserter-parts,Greifarmteile +item-name,iron-beam,Eisenträger +item-name,kr-accelerator,Schutzraum [color +item-name,kr-biter-virus,Anti-Beißer-Virus-Kapsel +item-name,kr-black-reinforced-plate,Schwarze Verstärkte Platte +item-name,kr-creep,Beißer Schleim +item-name,kr-creep-collector,Schleim-Sammler +item-name,kr-creep-virus,Anti-Schleim-Virus-Kapsel +item-name,kr-jackhammer,Presslufthammer +item-name,kr-loader,Lader +item-name,kr-note-1,Geheimnisvoller Brief +item-name,kr-void,Nichts +item-name,kr-white-reinforced-plate,Leichte Verstärkte Platte +item-name,lithium-chloride,Lithiumchlorid +item-name,lithium,Lithium +item-name,lithium-sulfur-battery,Lithium-Schwefel-Batterie +item-name,logistic-tech-card,Technologiekarte für Logistik +item-name,matter-cube,Materiewürfel +item-name,matter-research-data,Forschungsdaten für Materie +item-name,matter-stabilizer,Materie-Stabilisator +item-name,matter-tech-card,Technologiekarte für Materie +item-name,military-research-data,Forschungsdaten für Militär +item-name,military-tech-card,Technologiekarte für Militär +item-name,nuclear-artillery-shell,Atom Artilleriemunition +item-name,nuclear-turret-rocket,Atom-Geschützrakete +item-name,optimization-tech-card,Technologiekarte für Optimierung +item-name,pistol-magazine,Pistolen-Magazin +item-name,pollution-filter,Umweltverschmutzungsfilter +item-name,poop,Mysteriöse Substanz +item-name,potato,Kartoffel [color +item-name,power-armor-mk3,Kampfanzug MK3 +item-name,power-armor-mk4,Kampfanzug MK4 +item-name,production-tech-card,Technologiekarte für Produktion +item-name,quartz,Quarz +item-name,rare-metals,Seltene Metalle +item-name,raw-imersite,Rohes Imersit +item-name,raw-rare-metals,Rohe seltene Metalle +item-name,rifle-magazine,Gewehr-Magazin +item-name,silicon,Silizium +item-name,singularity-tech-card,Technologiekarte für Singularität +item-name,space-research-data,Weltraumforschungsdaten +item-name,spoiled-potato,Verdorbene Kartoffel +item-name,steel-beam,Stahlträger +item-name,steel-gear-wheel,Stahlzahnrad +item-name,teleportation-gps-module,Teleportations-GPS-Modul +item-name,tritium,Tritium +item-name,uranium-anti-material-rifle-magazine,Uranversetztes Scharfschützengewehr-Magazin +item-name,uranium-rifle-magazine,Uranversetzte Gewehr Magazin +item-name,used-improved-pollution-filter,Verbrauchter verbesserter Filtereinsatz +item-name,used-pollution-filter,Verbrauchter Filtereinsatz +item-name,utility-tech-card,Technologiekarte für Zubehör +virtual-signal-name,kr-attention_1,Achtung 1 +virtual-signal-name,kr-attention_2,Achtung 2 +virtual-signal-name,kr-attention_3,Achtung 3 +virtual-signal-name,kr-battery,Batterie +virtual-signal-name,kr-battery_low,Niedriger Akkustand +virtual-signal-name,kr-biohazard,Biohazard +virtual-signal-name,kr-build_here,Hier bauen +virtual-signal-name,kr-dont_touch,Nicht berühren! +virtual-signal-name,kr-energy-1,Energie 1 +virtual-signal-name,kr-energy-2,Energie 2 +virtual-signal-name,kr-gear_b,Zahnrad (Schwarz) +virtual-signal-name,kr-gear_w,Zahnrad (weiß) +virtual-signal-name,kr-heart,Herz <3 +virtual-signal-name,kr-kill,Töten +virtual-signal-name,kr-krastorio,Krastorio +virtual-signal-name,kr-nuclear-1,Nuklear 1 +virtual-signal-name,kr-nuclear-2,Nuklear 2 +virtual-signal-name,kr-power_off,Power aus +virtual-signal-name,kr-power_on,Power an +virtual-signal-name,kr-power,Power +virtual-signal-name,kr-question-mark,Fragezeichen +virtual-signal-name,kr-recycling,Recycling +virtual-signal-name,kr-scull,Totenkopf +virtual-signal-name,kr-smile,Lächeln +virtual-signal-name,kr-star_b,Stern (Schwarz) +virtual-signal-name,kr-star_w,Stern (weiß) +virtual-signal-name,kr-time,Zeit +virtual-signal-name,kr-wtf,WTF? +entity-name,kr-advanced-transport-belt-beltbox,Verbesserte stapelbare Fließbandkiste +entity-name,kr-advanced-transport-belt-loader,Weiterentwickelter kompakter Lader +entity-name,kr-singularity-reactor,Singularitätsreaktor +entity-name,kr-superior-transport-belt-beltbox,Überlegene stapelbare Fließbandkiste +entity-name,kr-superior-transport-belt-loader,Überlegener Kompakt-Lader +item-name,carbon-steel-beam,Stahlträger +item-name,carbon-steel-gear,Stahlzahnrad +item-name,carbon-steel-plate,Stahlplatte +item-name,charged-lithium-sulfur-battery,Aufgeladene Lithium-Schwefel-Batterie +item-name,charged-singularity-fuel-cell,Geladene Singularitäts-Treibstoffzelle +item-name,crushed-rare-metals,"Zerkleinerte, seltene Metalle" +item-name,empty-singularity-fuel-cell,Leere Singularitäts-Treibstoffzelle +item-name,se-astronomic-tech-card,Technologiekarte für Astronomie +item-name,se-biological-tech-card,Technologiekarte für Biologie +item-name,se-deep-space-tech-card,Weltraum-Technologiekarte +item-name,se-energy-tech-card,Technologiekarte für Energie +item-name,se-material-tech-card,Technologiekarte für Material +entity-name,logistic-train-stop,Logistik Haltestelle +entity-name,logistic-train-stop-input,Logistik Haltestelle Signaleingang +entity-name,logistic-train-stop-output,Logistik Haltestelle Signalausgang +entity-name,ltn-port,Logistik Hafen +item-name,logistic-train-stop,__ENTITY__logistic-train-stop__ +item-name,logistic-train-stop-input,__ENTITY__logistic-train-stop-input__ +item-name,logistic-train-stop-output,__ENTITY__logistic-train-stop-output__ +virtual-signal-name,ltn-position-any-locomotive,Kodierte Reihung aller Lokomotiven +virtual-signal-name,ltn-position-any-cargo-wagon,Kodierte Reihung aller Güterwaggons +virtual-signal-name,ltn-position-any-fluid-wagon,Kodierte Reihung aller Tankwaggons +virtual-signal-name,ltn-position-any-artillery-wagon,Kodierte Reihung aller Artilleriekanonen +virtual-signal-name,ltn-position,Kodierte Reihung von __1__ +virtual-signal-name,ltn-depot,Haltestelle ist Depot +virtual-signal-name,ltn-depot-priority,Depotpriorität +virtual-signal-name,ltn-network-id,Kodierte Netzwerk ID +virtual-signal-name,ltn-min-train-length,Minimale Zuglänge +virtual-signal-name,ltn-max-train-length,Maximale Zuglänge +virtual-signal-name,ltn-max-trains,Maximale Zuganzahl +virtual-signal-name,ltn-requester-threshold,Mindestmenge für Anforderung +virtual-signal-name,ltn-requester-stack-threshold,Mindestanzahl an Stapeln für Anforderung +virtual-signal-name,ltn-requester-priority,Anforderungspriorität +virtual-signal-name,ltn-provider-threshold,Mindestmenge für Angebot +virtual-signal-name,ltn-provider-stack-threshold,Mindestanzahl an Stapeln für Angebot +virtual-signal-name,ltn-provider-priority,Angebotspriorität +virtual-signal-name,ltn-locked-slots,gesperrte Stapel pro Waggon +virtual-signal-name,ltn-disable-warnings,Warnungen deaktivieren +entity-name,ltn-provider-reader,LTN-Angebotsleser +entity-name,ltn-requester-reader,LTN-Anforderungsleser +entity-name,ltn-delivery-reader,LTN-Lieferungsleser +item-name,ltn-provider-reader,__ENTITY__ltn-provider-reader +item-name,ltn-requester-reader,__ENTITY__ltn-requester-reader +item-name,ltn-delivery-reader,__ENTITY__ltn-delivery-reader +virtual-signal-name,ltn-cleanup-station,LTN Entleerungsstation +virtual-signal-name,ltn-item-cleanup-station,LTN Jeden Gegenstand aufräumen +entity-name,ltn-combinator,LTN-Kombinator +item-name,ltn-combinator,__ENTITY__ltn-combinator__ +entity-name,pda-road-sign-speed-limit,Markierung für Tempolimit +entity-name,pda-road-sign-speed-unlimit,Markierung für Ende des Tempolimits +entity-name,pda-road-sign-stop,Stoppschild +entity-name,pda-road-sensor,Straßensensor +item-name,pamk3-lvest,Gebrauchsweste +item-name,pamk3-hvest,Schwere Gebrauchsweste +item-name,pamk3-pamk3,Kampfanzug MK3 +item-name,pamk3-pamk4,Kampfanzug MK4 +item-name,pamk3-nvmk2,Nachtsicht MK2 +item-name,pamk3-esmk3,Energieschild MK3 +item-name,pamk3-battmk3,Fusionsbatterie +item-name,pamk3-pnr,Kernreaktorausrüstung +item-name,pamk3-se,Geschirmte Singularität +equipment-name,pamk3-nvmk2,Nachtsicht MK2 +equipment-name,pamk3-esmk3,Energieschild MK3 +equipment-name,pamk3-battmk3,Fusionsbatterie +equipment-name,pamk3-pnr,Kernreaktorausrüstung +equipment-name,pamk3-se,Geschirmte Singularität +item-name,rcalc-heat-dummy,Wärme +item-name,rcalc-pollution-dummy,Umweltverschmutzung +item-name,rcalc-power-dummy,Strom +item-name,rcalc-selection-tool,Wähler für Ratenrechner +item-name,rb-crafter-blueprint,Temporäre Herstellerblaupause +entity-name,se-linked-container,Arcolink-Speicher +entity-name,vase,Vase +entity-name,wooden-barrel,Holzfass +entity-name,furnace-ruin,Zerstörter Steinstapel +entity-name,workshop-ruin,Zerstörte Werkstatt +entity-name,iron-wood-chest,Alte Truhe +entity-name,iron-wood-chest-remnants,Zerstörte alte Truhe +entity-name,stone-rubble,Steinschutt +entity-name,se-gate-blocker,Instabiler Raum +entity-name,se-gate-blocker-void,Instabiler Raum +entity-name,destroyed-cargo-pod,Zerstörte Frachtkapsel +entity-name,meteorite,Meteorit +entity-name,rocket-fragment,Raketenfragment +entity-name,se-antimatter-reactor,Antimateriereaktor +entity-name,se-beryllium-ore,Beryll +entity-name,se-cargo-rocket-cargo-pod,Frachtkapsel +entity-name,se-casting-machine,Gießerei +entity-name,se-cryonite,Kryonit +entity-name,se-condenser-turbine,Verflüssigerturbine +entity-name,se-condenser-turbine-tank,Verflüssigerturbine +entity-name,se-condenser-turbine-generator,Verflüssigerturbine +entity-name,se-core-fragment-processor,Kernfragment-Verarbeiter +entity-name,se-core-miner,Kernerzförderer +entity-name,se-core-miner-drill,Kernerzförderer +entity-name,se-cryogun-ice,Eiswand +entity-name,se-dimensional-anchor,Dimensionsanker +entity-name,se-electric-boiler,Elektrischer Heizkessel +entity-name,se-fluid-burner-generator,Flüssigkeitswärmegenerator +entity-name,se-fuel-refinery,Kraftstoff-Raffinerie +entity-name,se-gate-fragment,Artefaktfragment +entity-name,se-holmium-ore,Holminit +entity-name,se-iridium-ore,Iridit +entity-name,se-meteor-defence-container,Meteoriten-Verteidigungsanlage +entity-name,se-meteor-defence-charger,Meteoriten-Verteidigungsanlage +entity-name,se-meteor-point-defence-container,Meteoriten-Punkt-Verteidigung +entity-name,se-meteor-point-defence-charger,Meteoriten-Punkt-Verteidigung +entity-name,se-meteor-point-defence-charger-overcharged,Meteoriten-Punkt-Verteidigung - Schnelllademodus +entity-name,se-methane-ice,Methaneis +entity-name,se-naquium-ore,Naquitit +entity-name,se-pulveriser,Pulverisierer +entity-name,se-delivery-cannon-capsule-projectile,Lieferkapsel-Projektil +entity-name,se-delivery-cannon-weapon-capsule-projectile,Waffenlieferkapsell-Projektil +entity-name,se-rocket-launch-pad,Frachtraketensilo +entity-name,se-rocket-launch-pad-tank,Frachtraketensilo +entity-name,se-rocket-launch-pad-silo,Frachtraketensilo +entity-name,se-rocket-launch-pad-combinator,Frachtraketensilo +entity-name,se-rocket-launch-pad-_-seat,Frachtraketensilo +entity-name,se-rocket-launch-pad-settings,Frachtraketensilo +entity-name,se-rocket-landing-pad,Frachtlandeplattform +entity-name,se-space-accumulator,Holmium-Akkumulator +entity-name,se-space-accumulator-2,Naquium-Akkumulator +entity-name,se-space-astrometrics-laboratory,Astrometrische Anlage +entity-name,se-space-biochemical-laboratory,Biochemische Anlage +entity-name,se-space-assembling-machine,Weltraum-Montagemaschine +entity-name,se-space-capsule,Weltraumkapsel +entity-name,se-space-capsule-_-vehicle,Weltraumkapsel +entity-name,se-space-capsule-scorched,Beschädigte Weltraumkapsel +entity-name,se-space-capsule-scorched-_-vehicle,Beschädigte Weltraumkapsel +entity-name,se-space-curved-rail,Kurvenförmiges Weltraumgleis +entity-name,se-space-decontamination-facility,Dekontaminationsanlage +entity-name,se-space-electromagnetics-laboratory,Elektromagnetische Anlage +entity-name,se-space-elevator,Weltraumlift +entity-name,se-space-elevator-lamp,Weltraumlift-Lampe +entity-name,se-space-elevator-energy-interface,Weltraumlift-Energiepuffer +entity-name,se-space-elevator-energy-pole,Weltraumlift-Kabelverbindung +entity-name,se-space-elevator-train-stop,Interne Weltraumlift-Zughaltestelle +entity-name,se-space-elevator-straight-rail,Internes Weltraumlift-Gleis +entity-name,se-space-elevator-curved-rail,Internes Weltraumlift-Gleis +entity-name,se-space-elevator-rail-signal,Internes Weltraumlift-Zugsignal +entity-name,se-space-elevator-collider,Weltraumlift-Zugdetektor +entity-name,se-space-elevator-tug,Weltraumlift-Schlepper +entity-name,se-space-genetics-laboratory,Genetische Anlage +entity-name,se-space-growth-facility,Aufzuchtanlage +entity-name,se-space-gravimetrics-laboratory,Gravimetrische Anlage +entity-name,se-space-hypercooler,Wärmetauscher +entity-name,se-space-laser-laboratory,Laseranlage +entity-name,se-lifesupport-facility,Lebenserhaltungsanlage +entity-name,se-space-manufactory,Weltraumfabrik +entity-name,se-space-material-fabricator,Materialhersteller +entity-name,se-space-mechanical-laboratory,Mechanische Anlage +entity-name,se-space-particle-accelerator,Teilchenbeschleuniger +entity-name,se-space-particle-collider,Teilchenkollidierer +entity-name,se-space-plasma-generator,Plasmagenerator +entity-name,se-space-radiation-laboratory,Strahlungsanlage +entity-name,se-space-radiator,Thermokühler +entity-name,se-space-radiator-2,Thermokühler 2 +entity-name,se-recycling-facility,Recyclinganlage +entity-name,se-space-pipe,Weltraumrohr +entity-name,se-space-pipe-long,Langes Weltraumrohr +entity-name,se-space-pipe-long-straight,Langes gerades Weltraumrohr __1__ +entity-name,se-space-pipe-long-junction,Lange Weltraumrohrkreuzung __1__ +entity-name,se-space-pipe-to-ground,Unterirdisches Weltraumrohr +entity-name,se-space-science-lab,Weltraumwissenschaftslabor +entity-name,se-space-solar-panel,Flaches Solarpanel +entity-name,se-space-solar-panel-2,Flaches Solarpanel 2 +entity-name,se-space-solar-panel-3,Flaches Solarpanel 3 +entity-name,se-space-spectrometry-facility,Spektrometrieanlage +entity-name,se-space-straight-rail,Gerades Weltraumgleis +entity-name,se-space-supercomputer-1,Supercomputer +entity-name,se-space-supercomputer-2,Quantensupercomputer +entity-name,se-space-supercomputer-3,Neuronaler Supercomputer +entity-name,se-space-supercomputer-4,Extemsupercomputer +entity-name,se-space-telescope-radio,Radioteleskop +entity-name,se-space-telescope-microwave,Mikrowellenteleskop +entity-name,se-space-telescope,Teleskop +entity-name,se-space-telescope-xray,Röntgenteleskop +entity-name,se-space-telescope-gammaray,Gammastrahlenteleskop +entity-name,se-space-thermodynamics-laboratory,Thermodynamische Anlage +entity-name,se-space-splitter,Space-Teilerfließband +entity-name,se-space-transport-belt,Space-Fließband +entity-name,se-space-underground-belt,Unterirdisches Space-Fließband +entity-name,se-spaceship-antimatter-engine,Raumschiff-Antimaterietriebwerk +entity-name,se-spaceship-antimatter-booster-tank,Raumschiff-Antimaterie-Boostertank +entity-name,se-spaceship-console,Raumschiffkonsole +entity-name,se-spaceship-console-output,Signalausgang der Raumschiffkonsole +entity-name,se-spaceship-console-alt,Beschädigte Raumschiffkonsole +entity-name,se-spaceship-gate,Raumschifftor +entity-name,se-spaceship-ion-engine,Raumschiff-Ionentriebwerk +entity-name,se-spaceship-ion-booster-tank,Raumschiff-Ionen-Boostertank +entity-name,se-spaceship-obstacle,Weltraumschrott +entity-name,se-spaceship-rocket-engine,Raumschiff-Raketentriebwerk +entity-name,se-spaceship-rocket-booster-tank,Raumschiff-Raketen-Boostertank +entity-name,se-spaceship-wall,Raumschiffmauer +entity-name,se-spaceship-circuit-network-restore,Raumschiff-Schaltungsnetz-Wiederherstellung +entity-name,se-water-ice,Wassereis +entity-name,se-vitamelange,Vitamelange +entity-name,se-vulcanite,Vulkanit +entity-name,small-asteroid,Kleiner Asteroid +entity-name,medium-asteroid,Mittelgroßer Asteroid +entity-name,large-asteroid,Großer Asteroid +entity-name,se-gate-part,Artefaktstück +entity-name,se-gate-platform-scaffold,Artefakt-Jury-Rig +entity-name,se-gate-lock-switch,Bewegliche Komponente +entity-name,se-gate-lock-combinator,Kombinatorzubehör +entity-name,se-gate-platform,Artefakt-Vermehrungsplattform +entity-name,se-gate-platform-combinator,Kombinatorzubehör +entity-name,se-gate-energy-interface,Stromplattform +entity-name,se-gate-platform-button-switch,Knopf +entity-name,se-gate-tank-input,Flüssigkeitseingang +entity-name,se-gate-tank-output,Flüssigkeitsausgang +entity-name,se-pyramid-a,Geometrische Struktur +entity-name,se-pyramid-b,Geometrische Struktur +entity-name,se-pyramid-c,Geometrische Struktur +entity-name,se-cartouche-a,Kartusche +entity-name,se-cartouche-b-a,Kartusche +entity-name,se-cartouche-b-b,Kartusche +entity-name,se-cartouche-chest,Antiker Behälter +entity-name,se-glyph,Glyphe +entity-name,glyph,Glyphe +entity-name,se-gate-addon,Artefakt-Vermehrung +entity-name,se-gate-platform-button-middle,Stopp +entity-name,se-gate-platform-button-left,Links +entity-name,se-gate-platform-button-right,Rechts +entity-name,se-compact-beacon,Kompakter Effektverteiler +entity-name,se-compact-beacon-2,Kompakter Effektverteiler 2 +entity-name,se-wide-beacon,Großflächen-Effektverteiler +entity-name,se-wide-beacon-2,Großflächen-Effektverteiler 2 +entity-name,se-supercharger,Superlader +entity-name,se-addon-power-pole,Nachrüstbarer Strommast +entity-name,se-pylon,Hochspannungsmast +entity-name,se-pylon-substation,Hochspannungsmast mit Umspannwerk +entity-name,se-pylon-construction,Hochspannungsmast mit Baubereich +entity-name,se-pylon-construction-roboport,Hochspannungsmast mit Baubereich +entity-name,se-pylon-construction-radar,Hochspannungsmast mit Radar und Baubereich +entity-name,se-pylon-construction-radar-roboport,Hochspannungsmast mit Radar und Baubereich +entity-name,se-pylon-construction-radar-radar,Hochspannungsmast mit Radar und Baubereich +entity-name,se-shield-projector,Schildprojektor +entity-name,se-shield-projector-shield-floor-east,Energieschild +entity-name,se-shield-projector-shield-floor-north,Energieschild +entity-name,se-shield-projector-shield-floor-northeast,Energieschild +entity-name,se-shield-projector-shield-floor-northwest,Energieschild +entity-name,se-shield-projector-shield-floor-south,Energieschild +entity-name,se-shield-projector-shield-floor-southeast,Energieschild +entity-name,se-shield-projector-shield-floor-southwest,Energieschild +entity-name,se-shield-projector-shield-floor-west,Energieschild +entity-name,se-shield-projector-shield-wall-east,Energieschild +entity-name,se-shield-projector-shield-wall-north,Energieschild +entity-name,se-shield-projector-shield-wall-northeast,Energieschild +entity-name,se-shield-projector-shield-wall-northwest,Energieschild +entity-name,se-shield-projector-shield-wall-south,Energieschild +entity-name,se-shield-projector-shield-wall-southeast,Energieschild +entity-name,se-shield-projector-shield-wall-southwest,Energieschild +entity-name,se-shield-projector-shield-wall-west,Energieschild +entity-name,se-shield-projector-barrier,Energieschild +entity-name,se-naquium-heat-pipe,Naquium-Wärmerohr +entity-name,se-naquium-heat-pipe-horizontal,Horizontales Naquium-Wärmerohr +entity-name,se-naquium-heat-pipe-vertical,Vertikales Naquium-Wärmerohr +entity-name,se-naquium-heat-pipe-long,Langes Naquium-Wärmerohr __1__ +entity-name,se-deep-space-transport-belt,Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-black,Schwarzes Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-white,Weißes Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-red,Rotes Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-yellow,Gelbes Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-green,Grünes Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-cyan,Türkises Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-blue,Blaues Deep-Space-Fließband +entity-name,se-deep-space-transport-belt-magenta,Lila Deep-Space-Fließband +entity-name,se-deep-space-underground-belt,Unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-black,Schwarzes unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-white,Weißes unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-red,Rotes unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-yellow,Gelbes unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-green,Grünes unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-cyan,Türkises unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-blue,Blaues unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-underground-belt-magenta,Lila unterirdisches Deep-Space-Fließband +entity-name,se-deep-space-splitter,Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-black,Schwarzes Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-white,Weißes Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-red,Rotes Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-yellow,Gelbes Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-green,Grünes Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-cyan,Türkises Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-blue,Blaues Deep-Space-Teilerfließband +entity-name,se-deep-space-splitter-magenta,Lila Deep-Space-Teilerfließband +entity-name,se-core-seam,Kernriss +entity-name,se-core-seam-type,Kernriss (__1__) +entity-name,se-big-turbine,Hochtemperatur-Turbinengenerator +entity-name,se-big-turbine-generator-NW,Hochtemperatur-Turbinengenerator +entity-name,se-big-turbine-generator-SE,Hochtemperatur-Turbinengenerator +entity-name,se-big-turbine-tank,Hochtemperatur-Turbinengenerator +entity-name,se-big-heat-exchanger,Hochtemperatur-Wärmetauscher +entity-name,se-blueprint-registration-point,Blaupausen-Registrierungspunkt +entity-name,se-delivery-cannon,Lieferkanone +entity-name,se-delivery-cannon-settings,Lieferkanone +entity-name,se-delivery-cannon-energy-interface,Lieferkanone +entity-name,se-delivery-cannon-chest,Lieferkanonenkiste +entity-name,se-delivery-cannon-weapon,Waffenlieferungskanone +entity-name,se-delivery-cannon-weapon-settings,Waffenlieferungskanone +entity-name,se-delivery-cannon-weapon-energy-interface,Waffenlieferungskanone +entity-name,se-spaceship-clamp,Raumschiffklemme +entity-name,se-spaceship-clamp-place,Raumschiffklemme +entity-name,se-spaceship-clamp-power-pole-external-east,Kabeldurchführung der Raumschiffklemme +entity-name,se-spaceship-clamp-power-pole-external-west,Kabeldurchführung der Raumschiffklemme +entity-name,se-bloater-pool-cloud,Bloatburst-Lache +entity-name,se-energy-beam,Energiestrahl +entity-name,se-energy-transmitter-emitter,Energiestrahl-Emitter +entity-name,se-energy-transmitter-chamber,Energiestrahl-Kammer +entity-name,se-energy-transmitter-injector,Energiestrahl-Injektor +entity-name,se-energy-transmitter-injector-reactor,Energiestrahl-Injektor +entity-name,se-energy-receiver,Energiestrahl-Empfänger +entity-name,se-energy-beam-defence,Schirm +entity-name,se-nexus,Nexus +entity-name,se-nexus-charger,Nexus +entity-name,se-space-probe-rocket,Weltraumsonden-Rakete +entity-name,se-space-probe-rocket-silo,Weltraumsonden-Raketensilo +entity-name,se-interburbulator-interface,Interburbulator-Schnittstelle +entity-name,se-interburbulator-control,Interburbulator-Steuerung +entity-name,se-interburbulator-projector,Interburbulator-Projektor +entity-name,se-burbulator,Brontionen-Burbulator 33027756 +entity-name,se-core-seam-fissure,Kernriss +entity-name,se-core-seam-smoke-generator,Kernriss-Rauch +entity-name,se-space-exploration-logo-shattered-15tiles,Space Exploration Logo zerbrochen 15 Kacheln +entity-name,se-space-exploration-logo-shattered-22tiles,Space Exploration Logo zerbrochen 22 Kacheln +entity-name,se-space-exploration-logo-shattered-30tiles,Space Exploration Logo zerbrochen 30 Kacheln +entity-name,se-space-exploration-logo-shadow-15tiles,Space Exploration Logo-Schatten 15 Kacheln +entity-name,se-space-exploration-logo-shadow-22tiles,Space Exploration Logo-Schatten 22 Kacheln +entity-name,se-space-exploration-logo-shadow-30tiles,Space Exploration Logo-Schatten 30 Kacheln +entity-name,se-space-exploration-logo-white-15tiles,Space Exploration Logo weiß 15 Kacheln +entity-name,se-space-exploration-logo-black-15tiles,Space Exploration Logo schwarz 15 Kacheln +entity-name,se-biter-friend,Freund +entity-name,se-biter-friend-corpse,Freundesleiche +entity-name,kr-atmospheric-condenser-_-waterless,Atmosphärischer Verflüssiger (wasserfrei) +equipment-name,energy-shield-mk3-equipment,Energieschild MK3 +equipment-name,energy-shield-mk4-equipment,Energieschild MK4 +equipment-name,energy-shield-mk5-equipment,Energieschild MK5 +equipment-name,energy-shield-mk6-equipment,Energieschild MK6 +equipment-name,se-adaptive-armour-equipment-1,Adaptive Rüstung MK1 +equipment-name,se-adaptive-armour-equipment-2,Adaptive Rüstung MK2 +equipment-name,se-adaptive-armour-equipment-3,Adaptive Rüstung MK3 +equipment-name,se-adaptive-armour-equipment-4,Adaptive Rüstung MK4 +equipment-name,se-adaptive-armour-equipment-5,Adaptive Rüstung MK5 +equipment-name,se-rtg-equipment,Tragbarer RTG +equipment-name,se-rtg-equipment-2,Tragbarer RTG MK2 +equipment-name,se-lifesupport-equipment-1,Lebenserhaltende Ausrüstung MK1 +equipment-name,se-lifesupport-equipment-2,Lebenserhaltende Ausrüstung MK2 +equipment-name,se-lifesupport-equipment-3,Lebenserhaltende Ausrüstung MK3 +equipment-name,se-lifesupport-equipment-4,Lebenserhaltende Ausrüstung MK4 +fluid-name,se-antimatter-stream,Antimateriestrom +fluid-name,se-bio-sludge,Bioschlamm +fluid-name,se-contaminated-bio-sludge,Kontaminierter Bioschlamm +fluid-name,se-contaminated-space-water,Kontaminiertes kosmisches Wasser +fluid-name,se-chemical-gel,Chemisches Gel +fluid-name,se-decompressing-steam,Interner Turbinendampf +fluid-name,se-liquid-rocket-fuel,Flüssiger Raketentreibstoff +fluid-name,se-methane-gas,Methangas +fluid-name,se-methane-gas-mixed,Gemischtes Methangas +fluid-name,se-nutrient-gel,Nährstoffgel +fluid-name,se-neural-gel,Neuralgel +fluid-name,se-neural-gel-2,Fortgeschrittenes Neuralgel +fluid-name,se-ion-stream,Ionenstrom +fluid-name,se-plasma-stream,Plasmastrom +fluid-name,se-particle-stream,Teilchenstrom +fluid-name,se-proton-stream,Protonenstrom +fluid-name,se-space-coolant,Kühlmittel 25 °C +fluid-name,se-space-coolant-hot,Kühlmittel 25 °C +fluid-name,se-space-coolant-warm,Kühles Kühlmittel -10 °C +fluid-name,se-space-coolant-cold,Kaltes Kühlmittel -100 °C +fluid-name,se-space-coolant-supercooled,Superkaltes Kühlmittel -273 °C +fluid-name,se-space-water,Kosmisches Wasser +fluid-name,se-beryllium-hydroxide,Berylliumhydroxid +fluid-name,se-cryonite-slush,Kryonitmatsch +fluid-name,se-vitalic-acid,Vitale Säure +fluid-name,se-molten-iron,Geschmolzenes Eisen +fluid-name,se-molten-copper,Geschmolzenes Kupfer +fluid-name,se-molten-holmium,Geschmolzenes Holmium +fluid-name,se-molten-beryllium,Geschmolzenes Beryllium +fluid-name,se-pyroflux,Pyroflux +fluid-name,se-kr-imersium-sulfide,Imersiumsulfid +fluid-name,dirty-water-ir,Verunreinigtes Iridiumwasser +fluid-name,dirty-water-ho,Verunreinigtes Holmiumwasser +item-name,spidertron,Spidertron +item-name,core-fragment,Kernfragment (__1__) +item-name,effectivity-module-4,Effizienzmodul 4 +item-name,effectivity-module-5,Effizienzmodul 5 +item-name,effectivity-module-6,Effizienzmodul 6 +item-name,effectivity-module-7,Effizienzmodul 7 +item-name,effectivity-module-8,Effizienzmodul 8 +item-name,effectivity-module-9,Effizienzmodul 9 +item-name,productivity-module-4,Produktivitätsmodul 4 +item-name,productivity-module-5,Produktivitätsmodul 5 +item-name,productivity-module-6,Produktivitätsmodul 6 +item-name,productivity-module-7,Produktivitätsmodul 7 +item-name,productivity-module-8,Produktivitätsmodul 8 +item-name,productivity-module-9,Produktivitätsmodul 9 +item-name,se-satellite-telemetry,Satellitentelemetrie +item-name,se-antimatter-canister,Antimateriekanister +item-name,se-ion-canister,Ionenkanister +item-name,se-astrometric-data,Astrometrische Daten +item-name,se-astronomic-catalogue-1,Astronomiekatalog +item-name,se-astronomic-catalogue-2,Großer Astronomiekatalog +item-name,se-astronomic-catalogue-3,Umfassender Astronomiekatalog +item-name,se-astronomic-catalogue-4,Erweiterter Astronomiekatalog +item-name,se-astronomic-insight,Astronomische Erkenntnis +item-name,se-astronomic-science-pack-1,Wissenschaftspaket für Astronomie 1 +item-name,se-astronomic-science-pack-2,Wissenschaftspaket für Astronomie 2 +item-name,se-astronomic-science-pack-3,Wissenschaftspaket für Astronomie 3 +item-name,se-astronomic-science-pack-4,Wissenschaftspaket für Astronomie 4 +item-name,se-atomic-data,Atomare Daten +item-name,se-beryllium-ore,Beryll +item-name,se-ballistic-shielding-data,Daten zur ballistischen Abschirmung +item-name,se-beryllium-ore-crushed,Zerkleinertes Beryll +item-name,se-beryllium-ore-washed,Gewaschenes Beryl +item-name,se-beryllium-plate,Berylliumplatte +item-name,se-beryllium-powder,Berylliumpulver +item-name,se-beryllium-ingot,Berylliumbarren +item-name,se-beryllium-sulfate,Berylliumsulfat +item-name,se-bio-combustion-data,Biologische Verbrennungsdaten +item-name,se-bio-combustion-resistance-data,Daten zur biologischen Verbrennungsresistenz +item-name,se-bio-spectral-data,Biologische Spektraldaten +item-name,se-biochemical-data,Biochemische Daten +item-name,se-biochemical-resistance-data,Daten zu biochemischer Resistenz +item-name,se-bioculture,Biokultur +item-name,se-bioelectrics-data,Bioelektrische Daten +item-name,se-biological-catalogue-1,Biologiekatalog +item-name,se-biological-catalogue-2,Großer Biologiekatalog +item-name,se-biological-catalogue-3,Umfassender Biologiekatalog +item-name,se-biological-catalogue-4,Erweiterter Biologiekatalog +item-name,se-biological-insight,Biologische Erkenntnis +item-name,se-biological-science-pack-1,Wissenschaftspaket für Biologie 1 +item-name,se-biological-science-pack-2,Wissenschaftspaket für Biologie 2 +item-name,se-biological-science-pack-3,Wissenschaftspaket für Biologie 3 +item-name,se-biological-science-pack-4,Wissenschaftspaket für Biologie 4 +item-name,se-biomechanical-data,Biomechanische Daten +item-name,se-biomechanical-resistance-data,Daten zu biomechanischer Resistenz +item-name,se-boson-data,Bosondaten +item-name,se-broken-data,Zerstörte Datenkarte +item-name,se-canister,Sicherheitskanister +item-name,se-biogun,Biogewehr +item-name,se-bloater-ammo,Bloatburst-Munition +item-name,se-pheromone-ammo,Pheromonpfeil +item-name,se-cryogun,Kryogewehr +item-name,se-cryogun-ammo,Gletschermunition +item-name,se-rocket-launch-pad-silo-dummy-ingredient-item,Frachtrakete (Verborgene Zutat) +item-name,se-rocket-launch-pad-silo-dummy-result-item,Frachtrakete (Verborgenes Ergebnis) +item-name,se-cargo-rocket-cargo-pod,Frachtkapsel +item-name,se-cargo-rocket-fuel-tank,Raketentreibstofftank +item-name,se-cargo-rocket-section,Frachtraketen-Bauteil +item-name,se-cargo-rocket-section-packed,Paketiertes Frachtraketen-Bauteil +item-name,se-cold-thermodynamics-data,Kalt-Thermodynamische Daten +item-name,se-comparative-genetic-data,Vergleichende genetische Daten +item-name,se-compressive-strength-data,Druckbelastbarkeitsdaten +item-name,se-conductivity-data,Leitfähigkeitsdaten +item-name,se-contaminated-scrap,Kontaminierter Schrott +item-name,se-core-fragment-omni,Kernfragment +item-name,se-corrosion-resistance-data,Daten zur Korrosions-Resistenz +item-name,se-cryogenics-data,Kryogenische Daten +item-name,se-cryonite,Kryonit +item-name,se-cryonite-crushed,Zerkleinertes Kryonit +item-name,se-cryonite-powder,Kryonitpulver +item-name,se-cryonite-washed,Gewaschenes Kryonit +item-name,se-cryonite-crystal,Kryonitkristall +item-name,se-cryonite-rod,Kryonitstab +item-name,se-cryonite-ion-exchange-beads,Anionen-Ion-Austauschperlen +item-name,se-dark-energy-data,Daten zu dunkler Energie +item-name,se-darkmatter-data,Daten zu dunkler Materie +item-name,se-data-storage-substrate-cleaned,Poliertes Datenspeichersubstrat +item-name,se-data-storage-substrate,Unpoliertes Datenspeichersubstrat +item-name,se-decompression-data,Dekompressionsdaten +item-name,se-decompression-resistance-data,Daten zur Dekompressions-Resistenz +item-name,se-universal-catalogue,Universalkatalog +item-name,se-deep-space-science-pack,Wissenschaftspaket für Deep-Space +item-name,se-deep-space-science-pack-1,Wissenschaftspaket für Deep-Space 1 +item-name,se-deep-space-science-pack-2,Wissenschaftspaket für Deep-Space 2 +item-name,se-deep-space-science-pack-3,Wissenschaftspaket für Deep-Space 3 +item-name,se-deep-space-science-pack-4,Wissenschaftspaket für Deep-Space 4 +item-name,se-doppler-shift-data,Daten zu Dopplerverschiebungen +item-name,se-durability-data,Haltbarkeitsdaten +item-name,se-electrical-shielding-data,Daten zur elektrischen Abschirmung +item-name,se-electromagnetic-field-data,Daten zum elektromagnetischen Feld +item-name,se-space-elevator-cable,Weltraumliftkabel +item-name,se-empty-data,Leere Datenkarte +item-name,se-empty-lifesupport-canister,Leerer Lebenserhaltungs-Kanister +item-name,se-energy-catalogue-1,Energiekatalog +item-name,se-energy-catalogue-2,Großer Energiekatalog +item-name,se-energy-catalogue-3,Umfassender Energiekatalog +item-name,se-energy-catalogue-4,Erweiterter Energiekatalog +item-name,se-energy-insight,Energieerkenntnis +item-name,se-energy-science-pack-1,Wissenschaftspaket für Energie 1 +item-name,se-energy-science-pack-2,Wissenschaftspaket für Energie 2 +item-name,se-energy-science-pack-3,Wissenschaftspaket für Energie 3 +item-name,se-energy-science-pack-4,Wissenschaftspaket für Energie 4 +item-name,se-entanglement-data,Daten zur Verschränkung +item-name,se-enriched-naquium,Angereichertes Naquium +item-name,se-exotic-fission-data,Daten zur exotischen Spaltung +item-name,se-exotic-singularity-data,Daten der Singularität +item-name,se-explosion-shielding-data,Daten zur Explosionsabschirmung +item-name,se-experimental-alloys-data,Experimentelle Legierungsdaten +item-name,se-experimental-biochemical-data,Experimentelle biochemische Daten +item-name,se-experimental-bioculture,Experimentelle Biokultur +item-name,se-experimental-genetic-data,Experimentelle Genetikdaten +item-name,se-experimental-material-decay-data,Experimentelle Daten zum Materialzerfall +item-name,se-experimental-material-spectral-data,Experimentelle Material-Spektraldaten +item-name,se-experimental-material,Experimenteller Materialprototyp +item-name,se-experimental-specimen,Experimentelle Biomasse +item-name,se-experimental-superconductor,Prototyp eines Supraleiters +item-name,se-forcefield-data,Daten zum Kraftfeld +item-name,se-friction-data,Daten zur Reibung +item-name,se-fusion-test-data,Daten zum Fusionstest +item-name,se-gammaray-detector,Gammastrahlendetektor +item-name,se-gammaray-observation-data,Daten der Gammastrahlen-Beobachtung +item-name,se-gammaray-test-data,Daten zu Gammastrahlen +item-name,se-gate-fragment,Artefaktfragment +item-name,se-genetic-data,Daten zur Genetik +item-name,se-gravity-wave-observation-data,Daten der Gravitationswellen-Beobachtung +item-name,se-gravity-wave-data,Daten zu Gravitationswellen +item-name,se-gravimetric-observation-data,Daten der gravimetrischem Beobachtung +item-name,se-gravimetric-test-data,Gravimetrische Testdaten +item-name,se-gravitational-lensing-data,Daten zum Gravitationslinseneffekt +item-name,se-heat-shielding,Hitzeschild +item-name,se-holmium-ore,Holminit +item-name,se-holmium-ore-crushed,Zerkleinertes Holminit +item-name,se-holmium-ore-washed,Gewaschenes Holminit +item-name,se-holmium-chloride,Holmiumchlorid +item-name,se-holmium-powder,Holmiumpulver +item-name,se-holmium-plate,Holmiumplatte +item-name,se-holmium-ingot,Holmiumbarren +item-name,se-hot-thermodynamics-data,Heiß-Thermodynamische Daten +item-name,se-impact-shielding-data,Daten zur Aufprallabschirmung +item-name,se-infrared-observation-data,Daten der Infrarot-Beobachtung +item-name,se-ion-spectrometry-data,Daten zur Ionenspektrometrie +item-name,se-iridium-ore,Iridit +item-name,se-iridium-ore-crushed,Zerkleinertes Iridit +item-name,se-iridium-ore-washed,Gewaschenes Iridit +item-name,se-iridium-piledriver,Iridiumramme +item-name,se-iridium-powder,Iridiumpulver +item-name,se-iridium-blastcake,Iridium-Sprengkuchen +item-name,se-iridium-plate,Iridiumplatte +item-name,se-iridium-ingot,Iridiumbarren +item-name,se-junk-data,Fehlerhafte Datenkarte +item-name,se-laser-shielding-data,Daten zur Laserabschirmung +item-name,se-lepton-data,Leptondaten +item-name,se-lifesupport-canister,Lebenserhaltungs-Kanister +item-name,se-machine-learning-data,Daten zum maschinellen Lernen +item-name,se-magnetic-canister,Magnetischer Kanister +item-name,se-magnetic-monopole-data,Daten zu magnetischen Monopolen +item-name,se-material-decay-data,Daten zum Materialzerfall +item-name,se-material-science-pack-1,Wissenschaftspaket für Material 1 +item-name,se-material-science-pack-2,Wissenschaftspaket für Material 2 +item-name,se-material-science-pack-3,Wissenschaftspaket für Material 3 +item-name,se-material-science-pack-4,Wissenschaftspaket für Material 4 +item-name,se-material-spectral-data,Materialspektraldaten +item-name,se-material-testing-pack,Materialtestpaket +item-name,se-material-catalogue-1,Materialkatalog +item-name,se-material-catalogue-2,Großer Materialkatalog +item-name,se-material-catalogue-3,Umfassender Materialkatalog +item-name,se-material-catalogue-4,Erweiterter Materialkatalog +item-name,se-material-insight,Material Erkenntnis +item-name,se-medpack,Medipack +item-name,se-medpack-2,Medipack 2 +item-name,se-medpack-3,Medipack 3 +item-name,se-medpack-4,Medipack 4 +item-name,se-meteor-defence,Meteoriten-Verteidigungsanlage +item-name,se-meteor-defence-ammo,Munition für Meteoriten-Verteidigungsanlagen +item-name,se-meteor-point-defence,Meteoriten-Punkt-Verteidigung +item-name,se-meteor-point-defence-ammo,Munition für Meteoriten-Punkt-Verteidigung +item-name,se-methane-ice,Methaneis +item-name,se-micro-black-hole-data,Daten zu schwarzen Mikrolöchern +item-name,se-microwave-observation-data,Daten der Mikrowellen-Beobachtung +item-name,se-negative-pressure-data,Unterdruckdaten +item-name,se-nano-cold-thermodynamics-data,Daten zur kalten Thermodynamik von Nanomaterial +item-name,se-nano-compressive-strength-data,Daten zur Druckfestigkeit von Nanomaterial +item-name,se-nano-hot-thermodynamics-data,Daten zur heißen Thermodynamik von Nanomaterial +item-name,se-nanomaterial,Nanomaterial +item-name,se-nano-tensile-strength-data,Daten zur Zugfestigkeit von Nanomaterial +item-name,se-naquium-ore,Naquitit +item-name,se-naquium-ore-crushed,Zerkleinertes Naquitit +item-name,se-naquium-ore-washed,Gewaschenes Naquitit +item-name,se-naquium-refined,Raffiniertes Naquitit +item-name,se-naquium-crystal,Naquititkristall +item-name,se-naquium-powder,Naquiumpulver +item-name,se-naquium-plate,Naquiumplatte +item-name,se-naquium-ingot,Naquiumbarren +item-name,se-neural-anomaly-data,Daten zu neuronalen Anomalien +item-name,se-nutrient-vat,Nährstoffkultur +item-name,se-observation-frame-blank,Leerer Beobachtungsrahmen +item-name,se-observation-frame-gammaray,Gammastrahlen-Beobachtungsrahmen +item-name,se-observation-frame-infrared,Infrarot-Beobachtungsrahmen +item-name,se-observation-frame-microwave,Mikrowellen-Beobachtungsrahmen +item-name,se-observation-frame-radio,Radiowellen-Beobachtungsrahmen +item-name,se-observation-frame-uv,UV-Strahlen-Beobachtungsrahmen +item-name,se-observation-frame-visible,Sichtbarer Beobachtungsrahmen +item-name,se-observation-frame-xray,Röntgen-Beobachtungsrahmen +item-name,se-orbital-data,Daten zu Orbitalberechnungen +item-name,se-particle-beam-shielding-data,Daten zur Teilchenstrahlabschirmung +item-name,se-plague-bomb,Seuchenrakete +item-name,se-plasma-canister,Plasmakanister +item-name,se-plasma-electrodynamics-data,Elektrodynamische Plasmadaten +item-name,se-plasma-thermodynamics-data,Thermodynamische Plasmadaten +item-name,se-polarisation-data,Polarisationsdaten +item-name,se-pressure-containment-data,Daten zur Druckbegrenzung +item-name,se-quantum-phenomenon-data,Daten zu Quantenphänomenen +item-name,se-quark-data,Quarkdaten +item-name,se-radiation-data,Strahlungsdaten +item-name,se-radiation-exposure-data,Daten zur Strahlungsexposition +item-name,se-radiation-exposure-resistance-data,Daten zur Strahlungs-Resistenz +item-name,se-radiation-shielding-data,Daten zur Strahlungsabschirmung +item-name,se-radio-observation-data,Daten der Radiowellen-Beobachtung +item-name,se-rigidity-data,Steifigkeitsdaten +item-name,se-rtg-equipment,Tragbarer RTG +item-name,se-rtg-equipment-2,Tragbarer RTG MK2 +item-name,se-scrap,Schrott +item-name,se-shear-strength-data,Daten der Scherfestigkeit +item-name,se-significant-data,Signifikante Daten +item-name,se-significant-specimen,Signifikante Biomasse +item-name,se-singularity-data,Daten der Singularität +item-name,se-space-capsule,Weltraumkapsel +item-name,se-space-capsule-scorched,Beschädigte Weltraumkapsel +item-name,se-space-mirror,Multispektraler Spiegel +item-name,se-space-platform-plating,Weltraumplattform-Platten +item-name,se-space-platform-scaffold,Weltraumplattform-Gerüst +item-name,se-space-rail,Weltraumgleis +item-name,se-spaceship-floor,Raumschiffboden +item-name,se-specimen,Biomasse +item-name,se-subatomic-data,Subatomare Daten +item-name,se-superconductivity-data,Daten der Supraleitfähigkeit +item-name,se-superconductor,Supraleiter +item-name,se-superconductive-cable,Supraleitendes Kabel +item-name,se-tensile-strength-data,Daten der Zugfestigkeit +item-name,se-tesla-ammo,Teslagewehr-Munition +item-name,se-tesla-gun,Teslagewehr +item-name,se-thruster-suit,Raumanzug +item-name,se-thruster-suit-2,Raumanzug MK2 +item-name,se-thruster-suit-3,Raumanzug MK3 +item-name,se-thruster-suit-4,Raumanzug MK4 +item-name,se-timespace-anomaly-data,Daten der Zeitraumanomalie +item-name,se-used-lifesupport-canister,Verbrauchter Lebenserhaltungs-Kanister +item-name,se-uv-observation-data,Daten der UV-Strahlen-Beobachtung +item-name,se-visible-observation-data,Daten der sichtbaren Strahlungs-Beobachtung +item-name,se-vitamelange,Vitamelange +item-name,se-vitamelange-nugget,Vitamelange Klumpen +item-name,se-vitamelange-bloom,Vitamelange Blüte +item-name,se-vitamelange-roast,Geröstetes Vitamelange +item-name,se-vitamelange-spice,Vitamelange Gewürz +item-name,se-vitamelange-extract,Vitamelange Extrakt +item-name,se-vulcanite,Vulkanit +item-name,se-vulcanite-pure,Reines Vulkanit +item-name,se-vulcanite-enriched,Angereichertes Vulkanit +item-name,se-vulcanite-crushed,Zerkleinertes Vulkanit +item-name,se-vulcanite-washed,Gewaschenes Vulkanit +item-name,se-vulcanite-block,Vulkanitblock +item-name,se-vulcanite-ion-exchange-beads,Kationen-Ion-Austauschperlen +item-name,se-water-ice,Wassereis +item-name,se-xray-observation-data,Daten der Röntgenstrahlungs-Beobachtung +item-name,se-zero-point-energy-data,Daten der Nullpunktenergie +item-name,se-rocket-science-pack,Wissenschaftspaket für Raketen +item-name,se-computer-science-pack,Wissenschaftspaket für Computer +item-name,speed-module-4,Tempomodul 4 +item-name,speed-module-5,Tempomodul 5 +item-name,speed-module-6,Tempomodul 6 +item-name,speed-module-7,Tempomodul 7 +item-name,speed-module-8,Tempomodul 8 +item-name,speed-module-9,Tempomodul 9 +item-name,se-aeroframe-pole,Leichtmetallstange +item-name,se-aeroframe-scaffold,Leichtmetallgerüst +item-name,se-aeroframe-bulkhead,Leichtmetallschott +item-name,se-lattice-pressure-vessel,Gitterdruckbehälter +item-name,se-heavy-girder,Schwerer Träger +item-name,se-heavy-bearing,Schweres Lager +item-name,se-heavy-composite,Schwerer Schott +item-name,se-heavy-assembly,Schwere Baugruppe +item-name,se-bioscrubber,Biowäscher +item-name,se-vitalic-epoxy,Vitales Epoxid +item-name,se-vitalic-reagent,Vitales Reagenz +item-name,se-vitalic-acid,Vitale Säure +item-name,se-self-sealing-gel,Selbstversiegelndes Gel +item-name,se-holmium-cable,Holmiumkabel +item-name,se-holmium-solenoid,Holmium-Magnetspule +item-name,se-quantum-processor,Quantenprozessor +item-name,se-dynamic-emitter,Dynamischer Emitter +item-name,se-naquium-processor,Naquiumprozessor +item-name,se-naquium-cube,Naquiumwürfel +item-name,se-naquium-tessaract,Naquiumtesserakt +item-name,se-compact-beacon,Kompakter Effektverteiler +item-name,se-compact-beacon-2,Kompakter Effektverteiler 2 +item-name,se-wide-beacon,Großflächen-Effektverteiler +item-name,se-wide-beacon-2,Großflächen-Effektverteiler 2 +item-name,se-lifesupport-equipment-1,Lebenserhaltende Ausrüstung MK1 +item-name,se-lifesupport-equipment-2,Lebenserhaltende Ausrüstung MK2 +item-name,se-lifesupport-equipment-3,Lebenserhaltende Ausrüstung MK3 +item-name,se-lifesupport-equipment-4,Lebenserhaltende Ausrüstung MK4 +item-name,se-naquium-heat-pipe,Naquium-Wärmerohr +item-name,se-naquium-heat-pipe-horizontal,Horizontales Naquium-Wärmerohr +item-name,se-naquium-heat-pipe-vertical,Vertikales Naquium-Wärmerohr +item-name,se-naquium-heat-pipe-long,Langes Naquium-Wärmerohr __1__ +item-name,se-deep-space-transport-belt,Deep-Space-Fließband +item-name,se-deep-space-transport-belt-black,Schwarzes Deep-Space-Fließband +item-name,se-deep-space-transport-belt-white,Weißes Deep-Space-Fließband +item-name,se-deep-space-transport-belt-red,Rotes Deep-Space-Fließband +item-name,se-deep-space-transport-belt-yellow,Gelbes Deep-Space-Fließband +item-name,se-deep-space-transport-belt-green,Grünes Deep-Space-Fließband +item-name,se-deep-space-transport-belt-cyan,Türkises Deep-Space-Fließband +item-name,se-deep-space-transport-belt-blue,Blaues Deep-Space-Fließband +item-name,se-deep-space-transport-belt-magenta,Lila Deep-Space-Fließband +item-name,se-deep-space-underground-belt,Unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-black,Schwarzes unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-white,Weißes unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-red,Rotes unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-yellow,Gelbes unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-green,Grünes unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-cyan,Türkises unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-blue,Blaues unterirdisches Deep-Space-Fließband +item-name,se-deep-space-underground-belt-magenta,Lila unterirdisches Deep-Space-Fließband +item-name,se-deep-space-splitter,Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-black,Schwarzes Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-white,Weißes Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-red,Rotes Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-yellow,Gelbes Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-green,Grünes Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-cyan,Türkises Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-blue,Blaues Deep-Space-Teilerfließband +item-name,se-deep-space-splitter-magenta,Lila Deep-Space-Teilerfließband +item-name,se-blueprint-registration-point,Blaupausen-Registrierungspunkt +item-name,se-delivery-cannon-capsule,Lieferkanonenkapsel +item-name,se-delivery-cannon-capsule-packed,Lieferkanonenkapsel: __1__ +item-name,se-delivery-cannon-targeter,Lieferkanonen-Zielgerät +item-name,se-delivery-cannon-weapon-capsule,Waffenlieferkapsel +item-name,se-delivery-cannon-weapon-capsule-packed,Waffenlieferkapsel: __1__ +item-name,se-delivery-cannon-weapon-targeter,Waffenlieferkanonen-Zielgerät +item-name,se-delivery-cannon-artillery-targeter,Waffenlieferkanonen-Zielgerät: __1__ +item-name,se-energy-transmitter-targeter,Energiestrahl-Zielgerät +item-name,se-arcosphere,Arkosphäre +item-name,se-arcosphere-a,λ Arkosphäre Lambda +item-name,se-arcosphere-b,ξ Arkosphäre Xi +item-name,se-arcosphere-c,ζ Arkosphäre Zeta +item-name,se-arcosphere-d,θ Arkosphäre Theta +item-name,se-arcosphere-e,ε Arkosphäre Epsilon +item-name,se-arcosphere-f,ε Arkosphäre Phi +item-name,se-arcosphere-g,γ Arkosphäre Gamma +item-name,se-arcosphere-h,ω Arkosphäre Omega +item-name,se-arcosphere-collector,Arkosphärensammler +item-name,se-star-probe,Sternsonde +item-name,se-belt-probe,Asteroidengürtel-Sonde +item-name,se-void-probe,Interstellare Void-Sonde +item-name,se-star-probe-data,Sternsondendaten +item-name,se-belt-probe-data,Asteroidengürtel-Sondendaten +item-name,se-void-probe-data,Interstellare Void-Sondendaten +item-name,se-nano-engineering-data,Daten der Nanotechnologie +item-name,se-annihilation-data,Daten der Vernichtung +item-name,se-naquium-structural-data,Daten der Naquiumstruktur +item-name,se-hyperlattice-data,Daten der Hypergitter +item-name,se-naquium-energy-data,Daten der Naquiumenergie +item-name,se-space-fold-data,Daten der Raumfaltung +item-name,se-space-warp-data,Daten der Überlichtgeschwindigkeit +item-name,se-space-dilation-data,Daten der Weltraumausdehnung +item-name,se-space-injection-data,Daten der Weltrauminjektion +item-name,se-interstellar-data,Interstellare Reisedaten +item-name,se-teleportation-data,Daten der Teleportation +item-name,se-wormhole-data,Wurmlochdaten +item-name,se-rhga-data,Daten der Realitätshypergraphieanalyse +item-name,se-deep-catalogue-1,Deep-Space-Katalog +item-name,se-deep-catalogue-2,Großer Deep-Space-Katalog +item-name,se-deep-catalogue-3,Umfassender Deep-Space-Katalog +item-name,se-deep-catalogue-4,Erweiterter Deep-Space-Katalog +item-name,se-space-probe-rocket,Weltraumsonden-Rakete +item-name,se-space-probe-rocket-deployed,Weltraumsonden-Rakete (eingesetzt) +item-name,se-railgun,Schienenkanone +item-name,se-railgun-ammo,Munition für Schienenkanonen +item-name,se-space-capsule-targeter,Landegerät für Weltraumkapsel +item-name,se-train-gui-targeter,Oberflächenübergreifender Zugwähler +item-name,se-iron-ingot,Eisenbarren +item-name,se-steel-ingot,Stahlbarren +item-name,se-copper-ingot,Kupferbarren +item-name,se-kr-imersite-powder,Zerkleinertes Imersit +item-name,se-kr-fine-imersite-powder,Feines Imersitpulver +item-name,se-capsule-se-biter-friend,Schlafender Freund +item-name,kr-quantum-computer,Fortgeschrittener Forschungsserver +item-name,kr-singularity-beacon,Fortgeschrittener Effektverteiler +item-name,se-kr-matter-catalogue-1,Materie-Verzeichnis +item-name,se-kr-matter-catalogue-2,Großes Materie-Verzeichnis +item-name,se-kr-matter-synthesis-data,Daten zur Materie-Synthese +item-name,se-kr-matter-containment-data,Daten zur Materie-Eindämmung +item-name,se-kr-matter-liberation-data,Daten zur Materie-Freisetzung +item-name,se-kr-matter-science-pack-2,Wissenschaftspaket für Materie 2 +item-name,se-kr-matter-manipulation-data,Daten zur Materie-Manipulation +item-name,se-kr-matter-recombination-data,Daten zur Materie-Kombination +item-name,se-kr-matter-stabilization-data,Daten zur Materie-Stabilisation +item-name,se-kr-matter-utilization-data,Daten zur Materie-Verwendung +item-name,se-kr-basic-stabilizer,Einfacher Materie-Stabilisator +item-name,se-kr-charged-basic-stabilizer,Geladener einfacher Materie-Stabilisator +item-name,se-kr-rocket-tech-card,Technologiekarte für Raketen +virtual-signal-name,signal-speed,Geschwindigkeitssignal +virtual-signal-name,se-signal-speed,Geschwindigkeitssignal +virtual-signal-name,signal-distance,Entfernungssignal +virtual-signal-name,se-signal-distance,Entfernungssignal +virtual-signal-name,se-star,Stern +virtual-signal-name,se-planet,Planet +virtual-signal-name,se-planet-orbit,Planetenorbit +virtual-signal-name,se-moon,Mond +virtual-signal-name,se-moon-orbit,Mondorbit +virtual-signal-name,se-asteroid-belt,Asteroidengürtel +virtual-signal-name,se-asteroid-field,Asteroidenfeld +virtual-signal-name,se-anomaly,Anomalie +virtual-signal-name,se-meteor,Meteorit +virtual-signal-name,se-spaceship,Raumschiff +virtual-signal-name,se-cargo-rocket,Frachtrakete +virtual-signal-name,se-remote-view,Fernansicht +virtual-signal-name,se-death,Tod +virtual-signal-name,se-character-corpse,Leiche +virtual-signal-name,se-ruin,Ruine +virtual-signal-name,se-accolade,Auszeichnung +virtual-signal-name,se-remove,Entfernen +virtual-signal-name,se-radius,Radius +virtual-signal-name,se-hierarchy,Hierarchie +virtual-signal-name,se-spaceship-launch,Raumschiffstart +virtual-signal-name,se-anchor-using-left-clamp,Ankern mit linker Klemme des Raumschiffs +virtual-signal-name,se-anchor-using-right-clamp,Ankern mit rechter Klemme des Raumschiffs +virtual-signal-name,se-anchor-to-left-clamp,Ankern an der linken Zielklemme +virtual-signal-name,se-anchor-to-right-clamp,Ankern an der rechten Zielklemme +virtual-signal-name,se-beacon-overload,Effektverteiler-Überladung +virtual-signal-name,se-warning,Warnung +virtual-signal-name,se-danger,Gefahr +virtual-signal-name,se-core-seam,Kernriss +virtual-signal-name,se-heat,Hitze +virtual-signal-name,se-nav-arrow-land,"Pfeil ""Landen""" +virtual-signal-name,se-nav-arrow-launch,"Pfeil ""Starten""" +virtual-signal-name,se-nav-arrow-up-right,Pfeil oben-rechts +virtual-signal-name,se-nav-arrow-up-left,Pfeil oben-links +virtual-signal-name,se-nav-arrow-left-up,Pfeil links-oben +virtual-signal-name,se-nav-arrow-left-down,Pfeil links-unten +virtual-signal-name,se-nav-arrows-cross,Pfeile kreuzen sich +virtual-signal-name,se-pin,Pin +entity-name,spidertron-enhancements-corpse,Spidertron-Leiche +entity-name,textplate,__1__ __2__ Textplatte +item-name,textplate,__1__ __2__ Textplatte +item-name,merge-chest-selector,Kistenverbinder +entity-name,rm_overlay,Resource Overlay +item-name,yarm-selector-tool,Resourcen Monitor \ No newline at end of file diff --git a/web/public/file.svg b/web/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/web/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/globe.svg b/web/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/web/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/next.svg b/web/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/web/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/vercel.svg b/web/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/web/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/public/window.svg b/web/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/web/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..3a13f90 --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +}