feat(website): add multilingual editions and translation workflow
This commit is contained in:
parent
ff57b75e22
commit
a2d3338e90
|
|
@ -68,7 +68,7 @@ jobs:
|
|||
import os
|
||||
from pathlib import Path
|
||||
|
||||
Path("website/public/deployment.json").write_text(
|
||||
Path("website/_site/deployment.json").write_text(
|
||||
json.dumps({"commit": os.environ["GITHUB_SHA"]}) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
|
@ -78,7 +78,7 @@ jobs:
|
|||
- name: Upload the website
|
||||
uses: actions/upload-pages-artifact@v4
|
||||
with:
|
||||
path: website/public
|
||||
path: website/_site
|
||||
|
||||
deploy:
|
||||
needs: prepare
|
||||
|
|
|
|||
|
|
@ -67,3 +67,6 @@ Thumbs.db
|
|||
/docs/public/product-catalog.json
|
||||
/docs/verification/managed-conformance-manifest.json
|
||||
/docs/verification/managed-conformance-ledger.json
|
||||
|
||||
# Complete static website output, including generated language editions.
|
||||
website/_site/
|
||||
|
|
|
|||
20
README_ar.md
20
README_ar.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[الموقع](https://rea.tools/) · [الأدلة](https://rea.tools/guides/) · [دراسات الحالة](https://rea.tools/showcase/)**
|
||||
**[الموقع](https://rea.tools/ar/) · [الأدلة](https://rea.tools/ar/guides/) · [دراسات الحالة](https://rea.tools/ar/showcase/)**
|
||||
|
||||
[البدء السريع](#البدء-السريع) · [كيف يعمل REA](#كيف-يعمل-rea) · [ما الذي يمكنك تحليله](#ما-الذي-يمكنك-تحليله) · [دراسات الحالة](#دراسات-الحالة) · [الأسئلة الشائعة](#الأسئلة-الشائعة) · [التوثيق](#التوثيق)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
يسجّل الإعداد REA لدى وكيلك ويثبّت تعليمات سير العمل المطابقة. يمكن لتحليل الشيفرة الأصلية استخدام تثبيت موجود من Hopper أو Ghidra؛ ويمكن للإعداد أيضًا تثبيت Hopper اختياريًا بعد موافقتك. لا يحتاج التحليل الثابت لـ JavaScript إلى أي من المحركين.
|
||||
|
||||
> **[زر موقع REA](https://rea.tools/)** للاطلاع على تعليمات الإعداد والأدلة المصوّرة ودراسات الحالة الفعلية.
|
||||
> **[زر موقع REA](https://rea.tools/ar/)** للاطلاع على تعليمات الإعداد والأدلة المصوّرة ودراسات الحالة الفعلية.
|
||||
|
||||
## البدء السريع
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ npx rea-agents@latest setup
|
|||
|
||||
| الهدف | ما يعيده REA | المتطلبات والدليل |
|
||||
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| الملفات الثنائية للشيفرة الأصلية | شيفرة شبه برمجية، وتعليمات تجميع، وسلاسل نصية، ورموز، واستدعاءات، ومراجع | Hopper أو Ghidra أو IDA؛ [تحليل الشيفرة الأصلية](https://rea.tools/guides/native/) |
|
||||
| الملفات الثنائية للشيفرة الأصلية | شيفرة شبه برمجية، وتعليمات تجميع، وسلاسل نصية، ورموز، واستدعاءات، ومراجع | Hopper أو Ghidra أو IDA؛ [تحليل الشيفرة الأصلية](https://rea.tools/ar/guides/native/) |
|
||||
| بنية ELF دون تشغيل | الأقسام والمقاطع والرموز ومعلومات إعادة التموضع الأصلية، وآليات الحماية المحتملة المستدلّ عليها بالفحص الثابت | pwntools يوفّره المستدعي على Linux x64؛ [تشخيص الملفات الثنائية](docs/binary-diagnostics.md) |
|
||||
| شيفرة EVM البايتية | محددات التوجيه، وإزاحات البايتات، والمعاملات المستنتجة، وقابلية تغيير الحالة | مدخل محلي يحمل بايتات خامًا أو تمثيلًا سداسيًا عشريًا على Linux x64؛ [دليل EVM دون تشغيل](docs/evm-bytecode.md) |
|
||||
| أعطال Linux المسجّلة | سجلات note الخام، ومسجّلات المعالج/الإشارات لكل خيط مسجّل، وترشيحات اختيارية لخرائط الذاكرة | pwntools يوفّره المستدعي على Linux x64؛ GDB/pwndbg اختياريان؛ [الأعطال المسجّلة](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | الوحدات، وعمليات الاستيراد، وخرائط المصدر، والمسارات، وIPC، وعلاقات إضافات الشيفرة الأصلية | Node.js وnpm؛ [تحليل التطبيقات](https://rea.tools/guides/javascript/) |
|
||||
| المواقع | بنية الصفحة، والسكربتات، وملاحظات الشبكة، ولقطات الشاشة المطلوبة | متصفح من عائلة Chrome؛ [تحليل المتصفح](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | الوحدات، وعمليات الاستيراد، وخرائط المصدر، والمسارات، وIPC، وعلاقات إضافات الشيفرة الأصلية | Node.js وnpm؛ [تحليل التطبيقات](https://rea.tools/ar/guides/javascript/) |
|
||||
| المواقع | بنية الصفحة، والسكربتات، وملاحظات الشبكة، ولقطات الشاشة المطلوبة | متصفح من عائلة Chrome؛ [تحليل المتصفح](https://rea.tools/ar/guides/browser/) |
|
||||
| تسجيلات الشبكة المحفوظة | الطلبات، والاستجابات، ومحتويات الحمولة المتاحة، ومواضعها في المصدر | HAR؛ وmitmdump على Linux لتسجيلات mitmproxy بصيغتها الأصلية؛ [دليل تسجيلات الشبكة](docs/web-network-captures.md) |
|
||||
| تجميعات .NET | البيانات الوصفية، وتعليمات CIL، واعتماديات الشيفرة الأصلية المعلنة، ومقارنات البناء | فحص ثابت؛ [دليل الشيفرة المُدارة](docs/managed-code-analysis.md) |
|
||||
| حزم Android APK | تصريحات ملف manifest، والأصناف، والدوال الناتجة عن فك الترجمة، والمراجع | JADX دون واجهة رسومية وJDK كامل على Linux/macOS/Windows x64؛ [دليل Android](docs/android-analysis.md) |
|
||||
|
|
@ -157,26 +157,26 @@ npx rea-agents@latest setup
|
|||
|
||||
## دراسات الحالة
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/ar/showcase/)
|
||||
|
||||
### DX-Ball: إعادة بناء حساب توزيع الصوت بين القناتين
|
||||
|
||||
تتبّع استدعاء صوت إلى الدالة المساعدة التي تحوّل الموضع إلى توزيع بين القناتين، وافحص التعليمات، وحوّل الشيفرة شبه البرمجية غير المكتملة إلى C. تجتاز إعادة البناء 3,205 حالات اختبار على x86 الأصلي، وتعيد إنتاج جميع بايتات الدالة المترجمة البالغ عددها 63 بايتًا.
|
||||
|
||||
[اقرأ دراسة الحالة](https://rea.tools/showcase/dx-ball/) ·
|
||||
[اقرأ دراسة الحالة](https://rea.tools/ar/showcase/dx-ball/) ·
|
||||
[مستودع إعادة البناء](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: تتبّع جسر الحافظة في Electron
|
||||
|
||||
اعثر على API الحافظة في عملية العرض، وتتبّعه عبر preload وIPC إلى العملية الرئيسية، وافحص صيغة الحافظة ذات التنسيق الغني.
|
||||
|
||||
[اقرأ دراسة الحالة](https://rea.tools/showcase/notion/)
|
||||
[اقرأ دراسة الحالة](https://rea.tools/ar/showcase/notion/)
|
||||
|
||||
### TH04: استعادة حساب حلقة المقذوفات في DOS
|
||||
|
||||
افحص تعليمات اللعبة الأصلية على PC-98 ذات 16 بت، واستعد حساب الزوايا الثابتة والموجّهة نحو الهدف، وقارن شيفرة C++ المعاد بناؤها بمخرجات المترجم المستخدم آنذاك.
|
||||
|
||||
[اقرأ دراسة الحالة](https://rea.tools/showcase/th04/) ·
|
||||
[اقرأ دراسة الحالة](https://rea.tools/ar/showcase/th04/) ·
|
||||
[مستودع إعادة البناء](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
إذا استخدمت REA لفحص هدف مثير للاهتمام، فنود الاطلاع عليه. شارك حالتك في [issue](https://github.com/morluto/rea/issues) أو [pull request](https://github.com/morluto/rea/pulls)، مع ذكر الهدف، وسؤالك، وكيف ساعدك REA، وما توصلت إليه.
|
||||
|
|
@ -248,7 +248,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## التوثيق
|
||||
|
||||
ابدأ بـ [الأدلة العملية](https://rea.tools/guides/) على الموقع. للخيارات الدقيقة والمتطلبات وعقود النتائج:
|
||||
ابدأ بـ [الأدلة العملية](https://rea.tools/ar/guides/) على الموقع. للخيارات الدقيقة والمتطلبات وعقود النتائج:
|
||||
|
||||
- [التثبيت والإعداد](docs/installation.md): تسجيل الوكلاء، وتهيئة الموفّرين، والتحديثات، وإلغاء التثبيت.
|
||||
- [الجاهزية واستكشاف الأخطاء](docs/installation.md#check-readiness-for-your-task): تشخيص وكيل أو محرك تحليل محدد.
|
||||
|
|
|
|||
20
README_de.md
20
README_de.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Website](https://rea.tools/) · [Anleitungen](https://rea.tools/guides/) · [Fallstudien](https://rea.tools/showcase/)**
|
||||
**[Website](https://rea.tools/de/) · [Anleitungen](https://rea.tools/de/guides/) · [Fallstudien](https://rea.tools/de/showcase/)**
|
||||
|
||||
[Schnellstart](#schnellstart) · [So funktioniert REA](#so-funktioniert-rea) · [Was du analysieren kannst](#was-du-analysieren-kannst) · [Fallstudien](#fallstudien) · [Häufige Fragen](#häufige-fragen) · [Dokumentation](#dokumentation)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA verbindet deinen Agenten mit Werkzeugen zum Untersuchen nativer Binärdateie
|
|||
|
||||
Die Einrichtung registriert REA bei deinem Agenten und installiert passende Workflow-Anweisungen. Für native Analysen kannst du eine vorhandene Hopper- oder Ghidra-Installation verwenden. Mit deiner Zustimmung kann die Einrichtung auch Hopper installieren. Statische JavaScript-Analysen benötigen keines der beiden Programme.
|
||||
|
||||
> **[Besuche die REA-Website](https://rea.tools/)** für Einrichtungshinweise, bebilderte Anleitungen und echte Fallstudien.
|
||||
> **[Besuche die REA-Website](https://rea.tools/de/)** für Einrichtungshinweise, bebilderte Anleitungen und echte Fallstudien.
|
||||
|
||||
## Schnellstart
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA benötigt Node.js 22.x (>=22.19), 24.x (>=24.11) oder 26+ sowie npm. Zusätz
|
|||
|
||||
| Ziel | Was REA zurückgibt | Voraussetzungen und Anleitung |
|
||||
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Native Binärdateien | Pseudocode, Assemblercode, Zeichenketten, Symbole, Aufrufe und Verweise | Hopper, Ghidra oder IDA; [native Analyse](https://rea.tools/guides/native/) |
|
||||
| Native Binärdateien | Pseudocode, Assemblercode, Zeichenketten, Symbole, Aufrufe und Verweise | Hopper, Ghidra oder IDA; [native Analyse](https://rea.tools/de/guides/native/) |
|
||||
| Offline-ELF-Struktur | Sektionen, Segmente, ursprüngliche Symbole/Relokationen und mögliche Schutzmaßnahmen aus statischer Analyse | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; [Binärdiagnostik](docs/binary-diagnostics.md) |
|
||||
| EVM-Bytecode | Dispatch-Selektoren, Byte-Offsets, abgeleitete Argumente und Veränderbarkeit des Zustands | Lokale Eingabe mit Rohbytes oder Hexdarstellung unter Linux x64; [Offline-EVM-Leitfaden](docs/evm-bytecode.md) |
|
||||
| Aufgezeichnete Linux-Abstürze | Unverarbeitete Note-Einträge, Register/Signale aller aufgezeichneten Threads und optionale Zuordnungskandidaten | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; optional GDB/pwndbg; [aufgezeichnete Abstürze](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Module, Imports, Source Maps, Routen, IPC und Beziehungen zu nativen Add-ons | Node.js und npm; [Anwendungsanalyse](https://rea.tools/guides/javascript/) |
|
||||
| Websites | Seitenstruktur, Skripte, Netzwerkbeobachtungen und angeforderte Screenshots | Ein Browser aus der Chrome-Familie; [Browseranalyse](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Module, Imports, Source Maps, Routen, IPC und Beziehungen zu nativen Add-ons | Node.js und npm; [Anwendungsanalyse](https://rea.tools/de/guides/javascript/) |
|
||||
| Websites | Seitenstruktur, Skripte, Netzwerkbeobachtungen und angeforderte Screenshots | Ein Browser aus der Chrome-Familie; [Browseranalyse](https://rea.tools/de/guides/browser/) |
|
||||
| Gespeicherte Netzwerkaufzeichnungen | Anfragen, Antworten, zugängliche Nutzdaten und Quellpositionen | HAR; mitmdump unter Linux für Aufzeichnungen im nativen mitmproxy-Format; [Leitfaden zu Netzwerkaufzeichnungen](docs/web-network-captures.md) |
|
||||
| .NET-Assemblies | Metadaten, CIL-Anweisungen, deklarierte native Abhängigkeiten und Build-Vergleiche | Statische Untersuchung; [Leitfaden für verwalteten Code](docs/managed-code-analysis.md) |
|
||||
| Android-APKs | Manifest-Deklarationen, Klassen, dekompilierte Methoden und Verweise | JADX ohne grafische Oberfläche und ein vollständiges JDK unter Linux/macOS/Windows x64; [Android-Leitfaden](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ Native Formate und unterstützte Hostsysteme unterscheiden sich je nach Provider
|
|||
|
||||
## Fallstudien
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/de/showcase/)
|
||||
|
||||
### DX-Ball: Eine Stereo-Panning-Berechnung rekonstruieren
|
||||
|
||||
Verfolge einen Sound-Aufruf zur Hilfsfunktion, die Positionen in Panning-Werte umrechnet, untersuche die Anweisungen und überführe unvollständigen Pseudocode in C. Die Rekonstruktion besteht 3.205 Tests mit dem ursprünglichen x86-Code und reproduziert alle 63 Bytes der kompilierten Funktion.
|
||||
|
||||
[Fallstudie lesen](https://rea.tools/showcase/dx-ball/) · [Rekonstruktionsrepository](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Fallstudie lesen](https://rea.tools/de/showcase/dx-ball/) · [Rekonstruktionsrepository](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: Die Electron-Zwischenablagebrücke verfolgen
|
||||
|
||||
Finde die Zwischenablage-API des Renderers, verfolge sie über preload und IPC bis zum Hauptprozess und untersuche das Zwischenablageformat samt Formatierungsdaten.
|
||||
|
||||
[Fallstudie lesen](https://rea.tools/showcase/notion/)
|
||||
[Fallstudie lesen](https://rea.tools/de/showcase/notion/)
|
||||
|
||||
### TH04: Eine DOS-Geschossring-Berechnung wiederherstellen
|
||||
|
||||
Untersuche die 16-Bit-Anweisungen des ursprünglichen PC-98-Spiels, rekonstruiere die festen und zielgerichteten Winkelberechnungen und vergleiche das rekonstruierte C++ mit der Ausgabe des damaligen Compilers.
|
||||
|
||||
[Fallstudie lesen](https://rea.tools/showcase/th04/) · [Rekonstruktionsrepository](https://github.com/N0zoM1z0/th04)
|
||||
[Fallstudie lesen](https://rea.tools/de/showcase/th04/) · [Rekonstruktionsrepository](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Wenn du mit REA etwas Interessantes untersucht hast, würden wir es gern sehen. Teile deine Fallstudie in einem [Issue](https://github.com/morluto/rea/issues) oder [Pull Request](https://github.com/morluto/rea/pulls) und beschreibe das Ziel, deine Frage, wie REA geholfen hat und was du herausgefunden hast.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ Wenn du einen Agenten verwendest, schließe die [Aktualisierung der Einrichtung]
|
|||
|
||||
## Dokumentation
|
||||
|
||||
Beginne mit den [praxisnahen Anleitungen](https://rea.tools/guides/) auf der Website. Genaue Optionen, Voraussetzungen und Ergebniskontrakte findest du hier:
|
||||
Beginne mit den [praxisnahen Anleitungen](https://rea.tools/de/guides/) auf der Website. Genaue Optionen, Voraussetzungen und Ergebniskontrakte findest du hier:
|
||||
|
||||
- [Installation und Einrichtung](docs/installation.md): Agentenregistrierung, Provider-Konfiguration, Updates und Deinstallation.
|
||||
- [Bereitschaft und Fehlerbehebung](docs/installation.md#check-readiness-for-your-task): Diagnose eines bestimmten Agenten oder einer Analyse-Engine.
|
||||
|
|
|
|||
20
README_es.md
20
README_es.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Sitio web](https://rea.tools/) · [Guías](https://rea.tools/guides/) · [Casos prácticos](https://rea.tools/showcase/)**
|
||||
**[Sitio web](https://rea.tools/es/) · [Guías](https://rea.tools/es/guides/) · [Casos prácticos](https://rea.tools/es/showcase/)**
|
||||
|
||||
[Inicio rápido](#inicio-rápido) · [Cómo funciona REA](#cómo-funciona-rea) · [Qué puedes analizar](#qué-puedes-analizar) · [Casos prácticos](#casos-prácticos) · [Preguntas frecuentes](#preguntas-frecuentes) · [Documentación](#documentación)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA conecta tu agente con herramientas para inspeccionar binarios nativos, aplic
|
|||
|
||||
La configuración registra REA en tu agente e instala las instrucciones de trabajo correspondientes. El análisis nativo puede usar una instalación existente de Hopper o Ghidra; la configuración también puede instalar Hopper, si lo autorizas. El análisis estático de JavaScript no necesita ninguno de los dos motores.
|
||||
|
||||
> **[Visita el sitio web de REA](https://rea.tools/)** para encontrar instrucciones de configuración, guías ilustradas y casos reales.
|
||||
> **[Visita el sitio web de REA](https://rea.tools/es/)** para encontrar instrucciones de configuración, guías ilustradas y casos reales.
|
||||
|
||||
## Inicio rápido
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA requiere Node.js 22.x (>=22.19), 24.x (>=24.11) o 26+, además de npm. Las h
|
|||
|
||||
| Objetivo | Qué devuelve REA | Requisitos y guía |
|
||||
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Binarios nativos | Pseudocódigo, ensamblador, cadenas, símbolos, llamadas y referencias | Hopper, Ghidra o IDA; [análisis nativo](https://rea.tools/guides/native/) |
|
||||
| Binarios nativos | Pseudocódigo, ensamblador, cadenas, símbolos, llamadas y referencias | Hopper, Ghidra o IDA; [análisis nativo](https://rea.tools/es/guides/native/) |
|
||||
| Estructura ELF sin ejecutar | Secciones, segmentos, símbolos/reubicaciones originales y posibles medidas de mitigación detectadas mediante análisis estático | pwntools proporcionado por quien llama, en Linux x64; [diagnóstico de binarios](docs/binary-diagnostics.md) |
|
||||
| Bytecode EVM | Selectores de despacho, desplazamientos en bytes, argumentos inferidos y mutabilidad | Entrada local con bytes sin procesar o representación hexadecimal, en Linux x64; [guía de EVM sin ejecutar](docs/evm-bytecode.md) |
|
||||
| Fallos de Linux registrados | Registros note sin procesar, registros/señales de cada hilo registrado y posibles correspondencias de memoria opcionales | pwntools proporcionado por quien llama, en Linux x64; GDB/pwndbg opcionales; [fallos registrados](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Módulos, importaciones, mapas de código fuente, rutas, IPC y relaciones con complementos nativos | Node.js y npm; [análisis de aplicaciones](https://rea.tools/guides/javascript/) |
|
||||
| Sitios web | Estructura de la página, scripts, observaciones de red y capturas de pantalla solicitadas | Un navegador de la familia Chrome; [análisis del navegador](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Módulos, importaciones, mapas de código fuente, rutas, IPC y relaciones con complementos nativos | Node.js y npm; [análisis de aplicaciones](https://rea.tools/es/guides/javascript/) |
|
||||
| Sitios web | Estructura de la página, scripts, observaciones de red y capturas de pantalla solicitadas | Un navegador de la familia Chrome; [análisis del navegador](https://rea.tools/es/guides/browser/) |
|
||||
| Capturas de red guardadas | Solicitudes, respuestas, contenido accesible de las cargas útiles y ubicaciones de origen | HAR; mitmdump en Linux para capturas en formato nativo de mitmproxy; [guía de capturas](docs/web-network-captures.md) |
|
||||
| Ensamblados .NET | Metadatos, instrucciones CIL, dependencias nativas declaradas y comparaciones de compilaciones | Inspección estática; [guía de código administrado](docs/managed-code-analysis.md) |
|
||||
| APK de Android | Declaraciones del manifiesto, clases, métodos descompilados y referencias | JADX sin interfaz gráfica y un JDK completo en Linux/macOS/Windows x64; [guía de Android](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ Los formatos nativos y los sistemas anfitriones compatibles varían según el pr
|
|||
|
||||
## Casos prácticos
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/es/showcase/)
|
||||
|
||||
### DX-Ball: reconstruir un cálculo de panoramización de sonido
|
||||
|
||||
Sigue una llamada de sonido hasta la función auxiliar que convierte la posición en panoramización, inspecciona las instrucciones y transforma el pseudocódigo incompleto en C. La reconstrucción supera 3.205 casos con el x86 original y reproduce los 63 bytes de la función compilada.
|
||||
|
||||
[Lee el caso práctico](https://rea.tools/showcase/dx-ball/) · [Repositorio de reconstrucción](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Lee el caso práctico](https://rea.tools/es/showcase/dx-ball/) · [Repositorio de reconstrucción](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: seguir el puente del portapapeles de Electron
|
||||
|
||||
Encuentra la API del portapapeles del proceso de renderizado, síguela a través de preload e IPC hasta el proceso principal e inspecciona el formato enriquecido del portapapeles.
|
||||
|
||||
[Lee el caso práctico](https://rea.tools/showcase/notion/)
|
||||
[Lee el caso práctico](https://rea.tools/es/showcase/notion/)
|
||||
|
||||
### TH04: recuperar el cálculo de un anillo de proyectiles en DOS
|
||||
|
||||
Inspecciona las instrucciones de 16 bits del juego original para PC-98, recupera los cálculos de ángulos fijos y dirigidos, y compara el C++ reconstruido con la salida del compilador de la época.
|
||||
|
||||
[Lee el caso práctico](https://rea.tools/showcase/th04/) · [Repositorio de reconstrucción](https://github.com/N0zoM1z0/th04)
|
||||
[Lee el caso práctico](https://rea.tools/es/showcase/th04/) · [Repositorio de reconstrucción](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Si has usado REA para investigar algo interesante, nos gustaría verlo. Comparte tu caso en una [issue](https://github.com/morluto/rea/issues) o una [pull request](https://github.com/morluto/rea/pulls), incluyendo el objetivo, tu pregunta, cómo te ayudó REA y qué encontraste.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ Si usas un agente, completa la [actualización de la configuración](#actualiza-
|
|||
|
||||
## Documentación
|
||||
|
||||
Empieza con las [guías prácticas](https://rea.tools/guides/) del sitio web. Para opciones exactas, requisitos y contratos de resultados:
|
||||
Empieza con las [guías prácticas](https://rea.tools/es/guides/) del sitio web. Para opciones exactas, requisitos y contratos de resultados:
|
||||
|
||||
- [Instalación y configuración](docs/installation.md): registro de agentes, configuración de proveedores, actualizaciones y desinstalación.
|
||||
- [Preparación y resolución de problemas](docs/installation.md#check-readiness-for-your-task): diagnóstico de un agente o motor de análisis concreto.
|
||||
|
|
|
|||
20
README_fa.md
20
README_fa.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55" /></a>
|
||||
|
||||
**[وبسایت](https://rea.tools/) · [راهنماها](https://rea.tools/guides/) · [نمونههای عملی](https://rea.tools/showcase/)**
|
||||
**[وبسایت](https://rea.tools/fa/) · [راهنماها](https://rea.tools/fa/guides/) · [نمونههای عملی](https://rea.tools/fa/showcase/)**
|
||||
|
||||
[شروع سریع](#شروع-سریع) · [REA چگونه کار میکند؟](#rea-چگونه-کار-میکند) · [چه چیزهایی را میتوان تحلیل کرد؟](#چه-چیزهایی-را-میتوان-تحلیل-کرد) · [نمونههای عملی](#نمونههای-عملی) · [پرسشهای متداول](#پرسشهای-متداول) · [مستندات](#مستندات)
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ REA ایجنت شما را به ابزارهایی برای بررسی باین
|
|||
|
||||
فرایند راهاندازی، REA را در ایجنت شما ثبت میکند و دستورالعملهای گردشکار متناظر را نصب میکند. تحلیل بومی میتواند از نصب موجود Hopper یا Ghidra استفاده کند؛ همچنین راهاندازی میتواند با تأیید شما Hopper را بهصورت اختیاری نصب کند. تحلیل ایستای JavaScript به هیچیک از این موتورهای تحلیل نیاز ندارد.
|
||||
|
||||
> برای دستورالعملهای راهاندازی، راهنماهای تصویری و مطالعات موردی واقعی، **[به وبسایت REA مراجعه کنید](https://rea.tools/)**.
|
||||
> برای دستورالعملهای راهاندازی، راهنماهای تصویری و مطالعات موردی واقعی، **[به وبسایت REA مراجعه کنید](https://rea.tools/fa/)**.
|
||||
|
||||
## شروع سریع
|
||||
|
||||
|
|
@ -125,12 +125,12 @@ REA به Node.js 22.x (>=22.19)، 24.x (>=24.11) یا 26+، بههمراه np
|
|||
|
||||
| هدف | خروجی REA | پیشنیازها و راهنما |
|
||||
| --------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| باینریهای بومی | شبهکد، اسمبلی، رشتهها، نمادها، فراخوانیها و ارجاعات | Hopper، Ghidra یا IDA؛ [تحلیل بومی](https://rea.tools/guides/native/) |
|
||||
| باینریهای بومی | شبهکد، اسمبلی، رشتهها، نمادها، فراخوانیها و ارجاعات | Hopper، Ghidra یا IDA؛ [تحلیل بومی](https://rea.tools/fa/guides/native/) |
|
||||
| ساختار ELF آفلاین | بخشها، سگمنتها، نمادها و relocationهای اصلی و گزینههای احتمالی کاهش آسیبپذیری ایستا | pwntools تأمینشده توسط فراخواننده روی Linux x64؛ [تشخیص باینری](docs/binary-diagnostics.md) |
|
||||
| بایتکد EVM | selectorهای dispatch، offsetهای بایتی، آرگومانهای استنباطشده و قابلیت تغییر وضعیت | دادهٔ خام/hex محلی روی Linux x64؛ [راهنمای EVM آفلاین](docs/evm-bytecode.md) |
|
||||
| کرشهای ثبتشدهٔ لینوکس | یادداشتهای خام، رجیسترها/سیگنالهای تمام threadهای ثبتشده و گزینههای احتمالی نگاشت | pwntools تأمینشده توسط فراخواننده روی Linux x64؛ GDB/pwndbg اختیاری؛ [کرشهای ثبتشده](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | ماژولها، importها، source mapها، مسیرها، IPC و ارتباط افزونههای بومی | Node.js و npm؛ [تحلیل برنامه](https://rea.tools/guides/javascript/) |
|
||||
| وبسایتها | ساختار صفحه، اسکریپتها، مشاهدات شبکه و اسکرینشاتهای درخواستی | مرورگر مبتنی بر Chrome؛ [تحلیل مرورگر](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | ماژولها، importها، source mapها، مسیرها، IPC و ارتباط افزونههای بومی | Node.js و npm؛ [تحلیل برنامه](https://rea.tools/fa/guides/javascript/) |
|
||||
| وبسایتها | ساختار صفحه، اسکریپتها، مشاهدات شبکه و اسکرینشاتهای درخواستی | مرورگر مبتنی بر Chrome؛ [تحلیل مرورگر](https://rea.tools/fa/guides/browser/) |
|
||||
| دادههای ضبطشدهٔ شبکه | درخواستها، پاسخها، payloadهای آشکارشده و مکان آنها در منبع | HAR؛ ابزار mitmdump در لینوکس برای ضبطهای بومی mitmproxy؛ [راهنمای ضبط شبکه](docs/web-network-captures.md) |
|
||||
| اسمبلیهای .NET | فراداده، دستورالعملهای CIL، وابستگیهای بومی اعلامشده و مقایسهٔ buildها | بررسی ایستا؛ [راهنمای کد مدیریتشده](docs/managed-code-analysis.md) |
|
||||
| فایلهای APK اندروید | تعاریف Manifest، کلاسها، متدهای دیکامپایلشده و ارجاعات | JADX بدون رابط گرافیکی و JDK کامل در Linux/macOS/Windows x64؛ [راهنمای اندروید](docs/android-analysis.md) |
|
||||
|
|
@ -149,25 +149,25 @@ REA به Node.js 22.x (>=22.19)، 24.x (>=24.11) یا 26+، بههمراه np
|
|||
|
||||
## نمونههای عملی
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/fa/showcase/)
|
||||
|
||||
### DX-Ball: بازسازی محاسبهٔ موقعیت استریوی صدا
|
||||
|
||||
یک فراخوانی صوتی را تا تابع کمکی تبدیل موقعیت به pan دنبال کنید، دستورالعملها را بررسی کنید و شبهکد ناقص را به C تبدیل کنید. بازسازی حاصل، هر ۳٬۲۰۵ مورد آزمایش x86 اصلی را با موفقیت پشت سر میگذارد و هر ۶۳ بایت تابع کامپایلشده را دقیقاً بازتولید میکند.
|
||||
|
||||
[مطالعهٔ موردی](https://rea.tools/showcase/dx-ball/) · [مخزن بازسازی](https://github.com/N0zoM1z0/dx-ball)
|
||||
[مطالعهٔ موردی](https://rea.tools/fa/showcase/dx-ball/) · [مخزن بازسازی](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: ردیابی پل کلیپبورد Electron
|
||||
|
||||
API کلیپبورد در renderer را پیدا کنید، مسیر آن را از preload و IPC تا فرایند اصلی دنبال کنید و قالب غنی کلیپبورد را بررسی کنید.
|
||||
|
||||
[مطالعهٔ موردی](https://rea.tools/showcase/notion/)
|
||||
[مطالعهٔ موردی](https://rea.tools/fa/showcase/notion/)
|
||||
|
||||
### TH04: بازیابی محاسبهٔ حلقهٔ گلوله در DOS
|
||||
|
||||
دستورالعملهای ۱۶بیتی بازی اصلی PC-98 را بررسی کنید، محاسبات زاویهٔ ثابت و هدفگیریشده را بازیابی کنید و کد C++ بازسازیشده را با خروجی کامپایلر تاریخی مقایسه کنید.
|
||||
|
||||
[مطالعهٔ موردی](https://rea.tools/showcase/th04/) · [مخزن بازسازی](https://github.com/N0zoM1z0/th04)
|
||||
[مطالعهٔ موردی](https://rea.tools/fa/showcase/th04/) · [مخزن بازسازی](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
اگر از REA برای بررسی موضوع جالبی استفاده کردهاید، خوشحال میشویم آن را به اشتراک بگذارید. یک [issue](https://github.com/morluto/rea/issues) یا [pull request](https://github.com/morluto/rea/pulls) ثبت کنید و هدف، پرسش خود، نقش REA و یافتههایتان را توضیح دهید.
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## مستندات
|
||||
|
||||
از [راهنماهای عملی وبسایت](https://rea.tools/guides/) شروع کنید. برای گزینههای دقیق، پیشنیازها و قراردادهای خروجی:
|
||||
از [راهنماهای عملی وبسایت](https://rea.tools/fa/guides/) شروع کنید. برای گزینههای دقیق، پیشنیازها و قراردادهای خروجی:
|
||||
|
||||
- [نصب و راهاندازی](docs/installation.md): ثبت ایجنت، پیکربندی ارائهدهنده، بهروزرسانی و حذف نصب.
|
||||
- [آمادگی و رفع اشکال](docs/installation.md#check-readiness-for-your-task): عیبیابی یک ایجنت یا موتور تحلیل.
|
||||
|
|
|
|||
20
README_fr.md
20
README_fr.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Site web](https://rea.tools/) · [Guides](https://rea.tools/guides/) · [Études de cas](https://rea.tools/showcase/)**
|
||||
**[Site web](https://rea.tools/fr/) · [Guides](https://rea.tools/fr/guides/) · [Études de cas](https://rea.tools/fr/showcase/)**
|
||||
|
||||
[Démarrage rapide](#démarrage-rapide) · [Comment fonctionne REA](#comment-fonctionne-rea) · [Ce que vous pouvez analyser](#ce-que-vous-pouvez-analyser) · [Études de cas](#études-de-cas) · [Questions fréquentes](#questions-fréquentes) · [Documentation](#documentation)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA connecte votre agent à des outils d'inspection de binaires natifs, d'applic
|
|||
|
||||
Setup enregistre REA auprès de votre agent et installe les instructions de workflow correspondantes. L'analyse native peut utiliser une installation existante de Hopper ou de Ghidra ; Setup peut aussi installer Hopper après votre accord. L'analyse statique JavaScript ne nécessite aucun de ces moteurs.
|
||||
|
||||
> **[Visitez le site web de REA](https://rea.tools/)** pour les instructions d'installation, des guides illustrés et des études de cas réelles.
|
||||
> **[Visitez le site web de REA](https://rea.tools/fr/)** pour les instructions d'installation, des guides illustrés et des études de cas réelles.
|
||||
|
||||
## Démarrage rapide
|
||||
|
||||
|
|
@ -134,12 +134,12 @@ REA nécessite Node.js 22.x (>=22.19), 24.x (>=24.11) ou 26+, ainsi que npm. Les
|
|||
|
||||
| Cible | Ce que REA renvoie | Prérequis et guide |
|
||||
| ---------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Binaires natifs | Pseudo-code, assembleur, chaînes, symboles, appels et références | Hopper, Ghidra ou IDA ; [analyse native](https://rea.tools/guides/native/) |
|
||||
| Binaires natifs | Pseudo-code, assembleur, chaînes, symboles, appels et références | Hopper, Ghidra ou IDA ; [analyse native](https://rea.tools/fr/guides/native/) |
|
||||
| Structure ELF hors ligne | Sections, segments, symboles et relocations d'origine, et protections statiques candidates | pwntools fourni par l'utilisateur sous Linux x64 ; [diagnostics binaires](docs/binary-diagnostics.md) |
|
||||
| Bytecode EVM | Sélecteurs de dispatch, offsets en octets, arguments inférés et mutabilité | Fichier local brut ou hexadécimal sous Linux x64 ; [guide EVM hors ligne](docs/evm-bytecode.md) |
|
||||
| Crashs Linux enregistrés | Notes brutes, registres et signaux de chaque thread enregistré, et correspondances de mappings facultatives | pwntools fourni par l'utilisateur sous Linux x64 ; GDB/pwndbg en option ; [crashs enregistrés](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Modules, imports, source maps, routes, IPC et relations avec les modules natifs | Node.js et npm ; [analyse d'applications](https://rea.tools/guides/javascript/) |
|
||||
| Sites web | Structure des pages, scripts, observations réseau et captures d'écran demandées | Un navigateur de la famille Chrome ; [analyse du navigateur](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Modules, imports, source maps, routes, IPC et relations avec les modules natifs | Node.js et npm ; [analyse d'applications](https://rea.tools/fr/guides/javascript/) |
|
||||
| Sites web | Structure des pages, scripts, observations réseau et captures d'écran demandées | Un navigateur de la famille Chrome ; [analyse du navigateur](https://rea.tools/fr/guides/browser/) |
|
||||
| Captures réseau enregistrées | Requêtes, réponses, payloads exposés et emplacements dans le code source | HAR ; mitmdump sous Linux pour les captures mitmproxy natives ; [guide des captures](docs/web-network-captures.md) |
|
||||
| Assemblys .NET | Métadonnées, instructions CIL, dépendances natives déclarées et comparaisons de builds | Inspection statique ; [guide du code managé](docs/managed-code-analysis.md) |
|
||||
| APK Android | Déclarations du manifeste, classes, méthodes décompilées et références | JADX headless et un JDK complet sous Linux/macOS/Windows x64 ; [guide Android](docs/android-analysis.md) |
|
||||
|
|
@ -158,25 +158,25 @@ Les formats natifs et les hôtes pris en charge varient selon le fournisseur. Co
|
|||
|
||||
## Études de cas
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/fr/showcase/)
|
||||
|
||||
### DX-Ball : reconstruire un calcul de panoramique sonore
|
||||
|
||||
Suivez un appel sonore jusqu'à la fonction qui convertit une position en panoramique, inspectez ses instructions et transformez un pseudo-code incomplet en C. La reconstruction réussit 3 205 cas issus du x86 d'origine et reproduit à l'identique les 63 octets de la fonction compilée.
|
||||
|
||||
[Lire l'étude de cas](https://rea.tools/showcase/dx-ball/) · [Dépôt de la reconstruction](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Lire l'étude de cas](https://rea.tools/fr/showcase/dx-ball/) · [Dépôt de la reconstruction](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion : suivre le pont du presse-papiers d'Electron
|
||||
|
||||
Trouvez l'API de presse-papiers du renderer, suivez-la à travers le preload et l'IPC jusqu'au processus principal, puis inspectez le format de presse-papiers enrichi.
|
||||
|
||||
[Lire l'étude de cas](https://rea.tools/showcase/notion/)
|
||||
[Lire l'étude de cas](https://rea.tools/fr/showcase/notion/)
|
||||
|
||||
### TH04 : retrouver un calcul d'anneau de projectiles sous DOS
|
||||
|
||||
Inspectez les instructions 16 bits du jeu PC-98 d'origine, retrouvez les calculs d'angles fixes et visés, et comparez le C++ reconstruit avec la sortie du compilateur d'époque.
|
||||
|
||||
[Lire l'étude de cas](https://rea.tools/showcase/th04/) · [Dépôt de la reconstruction](https://github.com/N0zoM1z0/th04)
|
||||
[Lire l'étude de cas](https://rea.tools/fr/showcase/th04/) · [Dépôt de la reconstruction](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Si vous avez utilisé REA sur un projet intéressant, nous serions ravis de le découvrir. Partagez votre cas dans une [issue](https://github.com/morluto/rea/issues) ou une [pull request](https://github.com/morluto/rea/pulls), en précisant la cible, votre question, la manière dont REA vous a aidé et ce que vous avez découvert.
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ Si vous utilisez un agent, terminez l'[actualisation de la configuration](#mettr
|
|||
|
||||
## Documentation
|
||||
|
||||
Commencez par les [guides pas à pas](https://rea.tools/guides/) du site web. Pour les options exactes, les prérequis et les contrats de résultats :
|
||||
Commencez par les [guides pas à pas](https://rea.tools/fr/guides/) du site web. Pour les options exactes, les prérequis et les contrats de résultats :
|
||||
|
||||
- [Installation et configuration](docs/installation.md) : enregistrement des agents, configuration des fournisseurs, mises à jour et désinstallation.
|
||||
- [Vérification et dépannage](docs/installation.md#check-readiness-for-your-task) : diagnostiquer un agent ou un moteur d'analyse précis.
|
||||
|
|
|
|||
20
README_id.md
20
README_id.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Situs Web](https://rea.tools/) · [Panduan](https://rea.tools/guides/) · [Contoh Penggunaan](https://rea.tools/showcase/)**
|
||||
**[Situs Web](https://rea.tools/id/) · [Panduan](https://rea.tools/id/guides/) · [Contoh Penggunaan](https://rea.tools/id/showcase/)**
|
||||
|
||||
[Mulai Cepat](#mulai-cepat) · [Cara Kerja REA](#cara-kerja-rea) · [Hal yang Dapat Anda Analisis](#hal-yang-dapat-anda-analisis) · [Contoh Penggunaan](#contoh-penggunaan) · [FAQ](#faq) · [Dokumentasi](#dokumentasi)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA menghubungkan agen Anda dengan berbagai alat untuk memeriksa biner native, a
|
|||
|
||||
Proses penyiapan mendaftarkan REA ke agen Anda dan memasang instruksi alur kerja yang sesuai. Analisis native dapat menggunakan instalasi Hopper, Ghidra, atau IDA yang sudah ada. Proses penyiapan juga dapat memasang Hopper secara opsional setelah mendapatkan persetujuan. Analisis JavaScript statis tidak memerlukan mesin analisis native.
|
||||
|
||||
> **[Kunjungi situs web REA](https://rea.tools/)** untuk mendapatkan petunjuk penyiapan, panduan bergambar, dan studi kasus nyata.
|
||||
> **[Kunjungi situs web REA](https://rea.tools/id/)** untuk mendapatkan petunjuk penyiapan, panduan bergambar, dan studi kasus nyata.
|
||||
|
||||
## Mulai Cepat
|
||||
|
||||
|
|
@ -137,12 +137,12 @@ Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
|
|||
|
||||
| Target | Hasil yang diberikan REA | Persyaratan dan panduan |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Biner native | Pseudocode, assembly, string, simbol, pemanggilan, dan referensi | Hopper, Ghidra, atau IDA; [analisis native](https://rea.tools/guides/native/) |
|
||||
| Biner native | Pseudocode, assembly, string, simbol, pemanggilan, dan referensi | Hopper, Ghidra, atau IDA; [analisis native](https://rea.tools/id/guides/native/) |
|
||||
| Tata letak ELF offline | Bagian, segmen, simbol/relokasi asli, dan kandidat mitigasi statis | pwntools yang disediakan pemanggil pada Linux x64; [diagnostik biner](docs/binary-diagnostics.md) |
|
||||
| Bytecode EVM | Selector dispatch, offset byte, argumen yang disimpulkan, dan sifat mutabilitas | Pembawa data raw/hex lokal; [panduan EVM offline](docs/evm-bytecode.md) |
|
||||
| Crash Linux yang direkam | Catatan mentah, register/sinyal setiap thread yang direkam, dan kandidat pemetaan opsional | pwntools yang disediakan pemanggil; GDB/pwndbg opsional; [crash yang direkam](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Modul, impor, source map, rute, IPC, dan hubungan add-on native | Node.js dan npm; [analisis aplikasi](https://rea.tools/guides/javascript/) |
|
||||
| Situs web | Struktur halaman, skrip, pengamatan jaringan, dan tangkapan layar yang diminta | Peramban berbasis Chrome; [analisis peramban](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Modul, impor, source map, rute, IPC, dan hubungan add-on native | Node.js dan npm; [analisis aplikasi](https://rea.tools/id/guides/javascript/) |
|
||||
| Situs web | Struktur halaman, skrip, pengamatan jaringan, dan tangkapan layar yang diminta | Peramban berbasis Chrome; [analisis peramban](https://rea.tools/id/guides/browser/) |
|
||||
| Rekaman jaringan tersimpan | Permintaan, respons, payload yang terekspos, dan lokasi sumber | HAR; mitmdump di Linux untuk rekaman native mitmproxy; [panduan rekaman](docs/web-network-captures.md) |
|
||||
| Assembly .NET | Metadata, instruksi CIL, dependensi native yang dideklarasikan, dan perbandingan build | Tidak ada (hanya analisis statis); [panduan kode terkelola](docs/managed-code-analysis.md) |
|
||||
| APK Android | Deklarasi manifest, kelas, metode hasil dekompilasi, dan referensi | JADX mode headless dan JDK lengkap di Linux/macOS/Windows x64; [panduan Android](docs/android-analysis.md) |
|
||||
|
|
@ -169,25 +169,25 @@ Periksa [ketersediaan rilis](docs/installation.md#released-package-and-main) unt
|
|||
|
||||
## Contoh Penggunaan
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/id/showcase/)
|
||||
|
||||
### DX-Ball: merekonstruksi perhitungan sound-pan
|
||||
|
||||
Ikuti pemanggilan suara hingga ke fungsi pembantu yang mengubah posisi menjadi nilai pan, periksa instruksinya, lalu ubah pseudocode yang belum lengkap menjadi C. Hasil rekonstruksi tersebut lolos pada 3.205 kasus x86 asli dan mereproduksi seluruh 63 byte fungsi hasil kompilasi.
|
||||
|
||||
[Baca studi kasus](https://rea.tools/showcase/dx-ball/) · [Repositori rekonstruksi](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Baca studi kasus](https://rea.tools/id/showcase/dx-ball/) · [Repositori rekonstruksi](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: menelusuri jembatan clipboard Electron
|
||||
|
||||
Temukan API clipboard pada renderer, telusuri jalurnya melalui preload dan IPC hingga ke proses utama, lalu periksa format clipboard kaya.
|
||||
|
||||
[Baca studi kasus](https://rea.tools/showcase/notion/)
|
||||
[Baca studi kasus](https://rea.tools/id/showcase/notion/)
|
||||
|
||||
### TH04: memulihkan perhitungan bullet-ring DOS
|
||||
|
||||
Periksa instruksi 16-bit dari gim PC-98 asli, pulihkan perhitungan sudut tetap dan sudut yang diarahkan, lalu bandingkan C++ hasil rekonstruksi dengan keluaran historis kompiler.
|
||||
|
||||
[Baca studi kasus](https://rea.tools/showcase/th04/) · [Repositori rekonstruksi](https://github.com/N0zoM1z0/th04)
|
||||
[Baca studi kasus](https://rea.tools/id/showcase/th04/) · [Repositori rekonstruksi](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Jika Anda telah menggunakan REA untuk menganalisis sesuatu yang menarik, kami ingin melihat hasilnya. Bagikan kasus Anda melalui [issue](https://github.com/morluto/rea/issues) atau [pull request](https://github.com/morluto/rea/pulls), sertakan target, pertanyaan Anda, bagaimana REA membantu, dan apa yang Anda temukan.
|
||||
|
||||
|
|
@ -266,7 +266,7 @@ Coba kembali tugas yang sama. Jika masalah masih terjadi, [buat issue](https://g
|
|||
|
||||
## Dokumentasi
|
||||
|
||||
Mulailah dengan [panduan praktik di situs web](https://rea.tools/guides/).
|
||||
Mulailah dengan [panduan praktik di situs web](https://rea.tools/id/guides/).
|
||||
|
||||
Untuk mengetahui opsi, prasyarat, dan kontrak hasil secara tepat:
|
||||
|
||||
|
|
|
|||
20
README_it.md
20
README_it.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Sito web](https://rea.tools/) · [Guide](https://rea.tools/guides/) · [Showcase](https://rea.tools/showcase/)**
|
||||
**[Sito web](https://rea.tools/it/) · [Guide](https://rea.tools/it/guides/) · [Showcase](https://rea.tools/it/showcase/)**
|
||||
|
||||
[Quick start](#quick-start) · [Come funziona REA](#come-funziona-rea) · [Cosa puoi analizzare](#cosa-puoi-analizzare) · [Showcase](#showcase) · [FAQ](#faq) · [Documentazione](#documentazione)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA collega il tuo agente a strumenti per ispezionare binari nativi, app JavaScr
|
|||
|
||||
La configurazione registra REA con il tuo agente e installa le istruzioni di workflow corrispondenti. L'analisi nativa può usare un'installazione esistente di Hopper, Ghidra o IDA; la configurazione può installare opzionalmente Hopper previa approvazione. L'analisi statica JavaScript non richiede alcun motore di analisi nativo.
|
||||
|
||||
> **[Visita il sito web di REA](https://rea.tools/)** per istruzioni di configurazione, guide illustrate e veri casi studio.
|
||||
> **[Visita il sito web di REA](https://rea.tools/it/)** per istruzioni di configurazione, guide illustrate e veri casi studio.
|
||||
|
||||
## Quick start
|
||||
|
||||
|
|
@ -134,12 +134,12 @@ REA richiede Node.js 22.x (>=22.19), 24.x (>=24.11) o 26+, oltre a npm. Strument
|
|||
|
||||
| Obiettivo | Cosa restituisce REA | Requisiti e guida |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Binari nativi | Pseudocodice, assembly, stringhe, simboli, chiamate e riferimenti | Hopper, Ghidra o IDA; [analisi nativa](https://rea.tools/guides/native/) |
|
||||
| Binari nativi | Pseudocodice, assembly, stringhe, simboli, chiamate e riferimenti | Hopper, Ghidra o IDA; [analisi nativa](https://rea.tools/it/guides/native/) |
|
||||
| Layout ELF offline | Sezioni, segmenti, simboli/relocazioni originali e candidati mitigazioni statiche | pwntools fornito dal chiamante su Linux x64; [diagnostica binaria](docs/binary-diagnostics.md) |
|
||||
| Bytecode EVM | Selettori di dispatch, offset dei byte, argomenti inferiti e mutabilità | Carrier raw/hex locale; [guida EVM offline](docs/evm-bytecode.md) |
|
||||
| Crash Linux registrati | Note grezze, registri/segnai di ogni thread registrato e candidati mapping opzionali | pwntools fornito dal chiamante; GDB/pwndbg opzionale; [crash registrati](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Moduli, import, source map, route, IPC e relazioni con add-on nativi | Node.js e npm; [analisi delle applicazioni](https://rea.tools/guides/javascript/) |
|
||||
| Siti web | Struttura della pagina, script, osservazioni di rete e screenshot richiesti | Un browser della famiglia Chrome; [analisi browser](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Moduli, import, source map, route, IPC e relazioni con add-on nativi | Node.js e npm; [analisi delle applicazioni](https://rea.tools/it/guides/javascript/) |
|
||||
| Siti web | Struttura della pagina, script, osservazioni di rete e screenshot richiesti | Un browser della famiglia Chrome; [analisi browser](https://rea.tools/it/guides/browser/) |
|
||||
| Acquisizioni di rete salvate | Richieste, risposte, payload esposti e posizioni sorgente | HAR; mitmdump su Linux per acquisizioni mitmproxy native; [guida alle acquisizioni](docs/web-network-captures.md) |
|
||||
| Assembly .NET | Metadati, istruzioni CIL, dipendenze native dichiarate e confronti di build | Nessuno (solo statico); [guida managed-code](docs/managed-code-analysis.md) |
|
||||
| APK Android | Dichiarazioni manifest, classi, metodi decompilati e riferimenti | JADX headless e un JDK completo su Linux/macOS/Windows x64; [guida Android](docs/android-analysis.md) |
|
||||
|
|
@ -158,25 +158,25 @@ I formati nativi e il supporto host variano in base al provider. Vedi la [config
|
|||
|
||||
## Showcase
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/it/showcase/)
|
||||
|
||||
### DX-Ball: ricostruisci un calcolo sound-pan
|
||||
|
||||
Segui una chiamata sonora fino al suo helper posizione-to-pan, ispeziona le istruzioni e trasforma il pseudocodice incompleto in C. La ricostruzione supera 3.205 casi x86 originali e riproduce tutti i 63 byte di funzione compilati.
|
||||
|
||||
[Leggi il case study](https://rea.tools/showcase/dx-ball/) · [Repository di ricostruzione](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Leggi il case study](https://rea.tools/it/showcase/dx-ball/) · [Repository di ricostruzione](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: traccia il clipboard bridge di Electron
|
||||
|
||||
Trova l'API clipboard del renderer, seguila attraverso preload e IPC fino al processo principale e ispeziona il formato rich clipboard.
|
||||
|
||||
[Leggi il case study](https://rea.tools/showcase/notion/)
|
||||
[Leggi il case study](https://rea.tools/it/showcase/notion/)
|
||||
|
||||
### TH04: recupera un calcolo dell'anello di proiettili DOS
|
||||
|
||||
Ispeziona le istruzioni a 16 bit del gioco PC-98 originale, recupera i calcoli dell'angolo fisso e mirato e confronta il C++ ricostruito con l'output del compilatore storico.
|
||||
|
||||
[Leggi il case study](https://rea.tools/showcase/th04/) · [Repository di ricostruzione](https://github.com/N0zoM1z0/th04)
|
||||
[Leggi il case study](https://rea.tools/it/showcase/th04/) · [Repository di ricostruzione](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Se hai usato REA su qualcosa di interessante, ci piacerebbe vederlo. Condividi il tuo caso in una [issue](https://github.com/morluto/rea/issues) o in una [pull request](https://github.com/morluto/rea/pulls), includendo il bersaglio, la tua domanda, come REA ti ha aiutato e cosa hai scoperto.
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ Se stai usando un agente, completa l'[aggiornamento della configurazione](#aggio
|
|||
|
||||
## Documentazione
|
||||
|
||||
Inizia dalle [guide pratiche](https://rea.tools/guides/) del sito web. Per opzioni esatte, prerequisiti e contratti dei risultati:
|
||||
Inizia dalle [guide pratiche](https://rea.tools/it/guides/) del sito web. Per opzioni esatte, prerequisiti e contratti dei risultati:
|
||||
|
||||
- [Installazione e configurazione](docs/installation.md): registrazione agente, configurazione provider, aggiornamenti e disinstallazione.
|
||||
- [Pronto all'uso e risoluzione dei problemi](docs/installation.md#check-readiness-for-your-task): diagnostica un agente o un motore di analisi.
|
||||
|
|
|
|||
20
README_ja.md
20
README_ja.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[ウェブサイト](https://rea.tools/) · [ガイド](https://rea.tools/guides/) · [事例](https://rea.tools/showcase/)**
|
||||
**[ウェブサイト](https://rea.tools/ja/) · [ガイド](https://rea.tools/ja/guides/) · [事例](https://rea.tools/ja/showcase/)**
|
||||
|
||||
[クイックスタート](#クイックスタート) · [REA の仕組み](#rea-の仕組み) · [分析できる対象](#分析できる対象) · [事例](#事例) · [よくある質問](#よくある質問) · [ドキュメント](#ドキュメント)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA はエージェントを分析ツールにつなぎ、ネイティブバイ
|
|||
|
||||
セットアップはエージェントに REA を登録し、対応するワークフローの手順をインストールします。ネイティブ分析には既存の Hopper または Ghidra を使えます。承認すれば、セットアップで Hopper をインストールすることもできます。静的な JavaScript 分析には、どちらのエンジンも必要ありません。
|
||||
|
||||
> **[REA のウェブサイト](https://rea.tools/)**で、セットアップ手順、図解ガイド、実際の事例を確認できます。
|
||||
> **[REA のウェブサイト](https://rea.tools/ja/)**で、セットアップ手順、図解ガイド、実際の事例を確認できます。
|
||||
|
||||
## クイックスタート
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA には Node.js 22.x(>=22.19)、24.x(>=24.11)、または 26+ と npm
|
|||
|
||||
| 対象 | REA が返すもの | 要件とガイド |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ネイティブバイナリ | 疑似コード、アセンブリ、文字列、シンボル、呼び出し、参照 | Hopper、Ghidra、または IDA;[ネイティブ分析](https://rea.tools/guides/native/) |
|
||||
| ネイティブバイナリ | 疑似コード、アセンブリ、文字列、シンボル、呼び出し、参照 | Hopper、Ghidra、または IDA;[ネイティブ分析](https://rea.tools/ja/guides/native/) |
|
||||
| オフライン ELF レイアウト | セクション、セグメント、元のシンボル/再配置情報、静的解析によるセキュリティ対策の候補 | Linux x64 で利用者が用意する pwntools;[バイナリ診断](docs/binary-diagnostics.md) |
|
||||
| EVM バイトコード | ディスパッチセレクター、バイトオフセット、推定された引数と状態変更の可否 | Linux x64 上のローカルの生バイト/16 進数の入力ファイル;[オフライン EVM ガイド](docs/evm-bytecode.md) |
|
||||
| 記録済みの Linux クラッシュ | 生の note レコード、記録された全スレッドのレジスター/シグナル、任意のマッピング候補 | Linux x64 で利用者が用意する pwntools;GDB/pwndbg は任意;[記録済みクラッシュ](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | モジュール、インポート、ソースマップ、ルート、IPC、ネイティブアドオンの関係 | Node.js と npm;[アプリケーション分析](https://rea.tools/guides/javascript/) |
|
||||
| ウェブサイト | ページ構造、スクリプト、ネットワークの観測結果、依頼されたスクリーンショット | Chrome 系ブラウザー;[ブラウザー分析](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | モジュール、インポート、ソースマップ、ルート、IPC、ネイティブアドオンの関係 | Node.js と npm;[アプリケーション分析](https://rea.tools/ja/guides/javascript/) |
|
||||
| ウェブサイト | ページ構造、スクリプト、ネットワークの観測結果、依頼されたスクリーンショット | Chrome 系ブラウザー;[ブラウザー分析](https://rea.tools/ja/guides/browser/) |
|
||||
| 保存済みのネットワークキャプチャ | リクエスト、レスポンス、取得可能なペイロード、ソース内の位置 | HAR;mitmproxy ネイティブ形式のキャプチャには Linux 上の mitmdump;[キャプチャガイド](docs/web-network-captures.md) |
|
||||
| .NET アセンブリ | メタデータ、CIL 命令、宣言されたネイティブ依存関係、ビルドの比較 | 静的な検査;[マネージドコードのガイド](docs/managed-code-analysis.md) |
|
||||
| Android APK | マニフェストの宣言、クラス、逆コンパイルされたメソッド、参照 | Linux/macOS/Windows x64 上のヘッドレス JADX と完全な JDK;[Android ガイド](docs/android-analysis.md) |
|
||||
|
|
@ -157,26 +157,26 @@ REA には Node.js 22.x(>=22.19)、24.x(>=24.11)、または 26+ と npm
|
|||
|
||||
## 事例
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/ja/showcase/)
|
||||
|
||||
### DX-Ball:音声のパン計算を再構築する
|
||||
|
||||
音声の呼び出しから位置をパンに変換する補助関数をたどり、命令を調べ、不完全な疑似コードを C に書き直します。再構築した実装は、元の x86 に対する 3,205 ケースの検証を通過し、コンパイル後の関数の全 63 バイトを再現しています。
|
||||
|
||||
[事例を読む](https://rea.tools/showcase/dx-ball/) ·
|
||||
[事例を読む](https://rea.tools/ja/showcase/dx-ball/) ·
|
||||
[再構築リポジトリ](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion:Electron のクリップボードブリッジを追跡する
|
||||
|
||||
レンダラーのクリップボード API を見つけ、preload と IPC を経由してメインプロセスまでたどり、リッチなクリップボード形式を調べます。
|
||||
|
||||
[事例を読む](https://rea.tools/showcase/notion/)
|
||||
[事例を読む](https://rea.tools/ja/showcase/notion/)
|
||||
|
||||
### TH04:DOS の弾幕リングの計算を復元する
|
||||
|
||||
元の PC-98 ゲームの 16 ビット命令を調べ、固定角度と自機を狙う角度の計算を復元し、再構築した C++ を当時のコンパイラーの出力と比較します。
|
||||
|
||||
[事例を読む](https://rea.tools/showcase/th04/) ·
|
||||
[事例を読む](https://rea.tools/ja/showcase/th04/) ·
|
||||
[再構築リポジトリ](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
REA で興味深い対象を調べたら、ぜひ共有してください。[issue](https://github.com/morluto/rea/issues) または [pull request](https://github.com/morluto/rea/pulls) に、対象、調べたかったこと、REA がどう役立ったか、何が分かったかを記載してください。
|
||||
|
|
@ -248,7 +248,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## ドキュメント
|
||||
|
||||
まずはウェブサイトの[実践ガイド](https://rea.tools/guides/)を参照してください。正確なオプション、前提条件、結果の契約については、以下を参照してください。
|
||||
まずはウェブサイトの[実践ガイド](https://rea.tools/ja/guides/)を参照してください。正確なオプション、前提条件、結果の契約については、以下を参照してください。
|
||||
|
||||
- [インストールとセットアップ](docs/installation.md):エージェントの登録、プロバイダーの設定、更新、アンインストール。
|
||||
- [準備状況の確認とトラブルシューティング](docs/installation.md#check-readiness-for-your-task):特定のエージェントや分析エンジンを診断。
|
||||
|
|
|
|||
20
README_ko.md
20
README_ko.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[웹사이트](https://rea.tools/) · [가이드](https://rea.tools/guides/) · [사례](https://rea.tools/showcase/)**
|
||||
**[웹사이트](https://rea.tools/ko/) · [가이드](https://rea.tools/ko/guides/) · [사례](https://rea.tools/ko/showcase/)**
|
||||
|
||||
[빠른 시작](#빠른-시작) · [REA의 작동 방식](#rea의-작동-방식) · [분석할 수 있는 대상](#분석할-수-있는-대상) · [사례](#사례) · [자주 묻는 질문](#자주-묻는-질문) · [문서](#문서)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA는 에이전트를 분석 도구에 연결해 네이티브 바이너리, Jav
|
|||
|
||||
설정 과정은 에이전트에 REA를 등록하고 해당 버전에 맞는 워크플로 지침을 설치합니다. 네이티브 분석에는 기존 Hopper 또는 Ghidra 설치를 사용할 수 있습니다. 승인하면 설정 과정에서 Hopper를 설치할 수도 있습니다. 정적 JavaScript 분석에는 두 엔진 모두 필요하지 않습니다.
|
||||
|
||||
> **[REA 웹사이트](https://rea.tools/)**에서 설정 방법, 그림으로 설명한 가이드, 실제 사례를 확인하세요.
|
||||
> **[REA 웹사이트](https://rea.tools/ko/)**에서 설정 방법, 그림으로 설명한 가이드, 실제 사례를 확인하세요.
|
||||
|
||||
## 빠른 시작
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA에는 Node.js 22.x(>=22.19), 24.x(>=24.11) 또는 26+와 npm이 필요합니
|
|||
|
||||
| 대상 | REA가 반환하는 내용 | 요구 사항 및 가이드 |
|
||||
| --------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 네이티브 바이너리 | 의사 코드, 어셈블리, 문자열, 심볼, 호출, 참조 | Hopper, Ghidra 또는 IDA; [네이티브 분석](https://rea.tools/guides/native/) |
|
||||
| 네이티브 바이너리 | 의사 코드, 어셈블리, 문자열, 심볼, 호출, 참조 | Hopper, Ghidra 또는 IDA; [네이티브 분석](https://rea.tools/ko/guides/native/) |
|
||||
| 오프라인 ELF 레이아웃 | 섹션, 세그먼트, 원본 심볼/재배치 정보, 정적 분석으로 얻은 보안 완화 기법 후보 | Linux x64에서 호출자가 제공하는 pwntools; [바이너리 진단](docs/binary-diagnostics.md) |
|
||||
| EVM 바이트코드 | 디스패치 선택자, 바이트 오프셋, 추론한 인자와 상태 변경 가능 여부 | Linux x64의 로컬 원시 바이트/16진수 입력 파일; [오프라인 EVM 가이드](docs/evm-bytecode.md) |
|
||||
| 기록된 Linux 크래시 | 원시 note 레코드, 기록된 모든 스레드의 레지스터/시그널, 선택적 매핑 후보 | Linux x64에서 호출자가 제공하는 pwntools; GDB/pwndbg는 선택 사항; [기록된 크래시](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | 모듈, 임포트, 소스 맵, 라우트, IPC, 네이티브 애드온 관계 | Node.js와 npm; [애플리케이션 분석](https://rea.tools/guides/javascript/) |
|
||||
| 웹사이트 | 페이지 구조, 스크립트, 네트워크 관찰 결과, 요청한 스크린샷 | Chrome 계열 브라우저; [브라우저 분석](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | 모듈, 임포트, 소스 맵, 라우트, IPC, 네이티브 애드온 관계 | Node.js와 npm; [애플리케이션 분석](https://rea.tools/ko/guides/javascript/) |
|
||||
| 웹사이트 | 페이지 구조, 스크립트, 네트워크 관찰 결과, 요청한 스크린샷 | Chrome 계열 브라우저; [브라우저 분석](https://rea.tools/ko/guides/browser/) |
|
||||
| 저장된 네트워크 캡처 | 요청, 응답, 접근 가능한 페이로드, 소스 위치 | HAR; mitmproxy 네이티브 캡처에는 Linux의 mitmdump; [캡처 가이드](docs/web-network-captures.md) |
|
||||
| .NET 어셈블리 | 메타데이터, CIL 명령, 선언된 네이티브 의존성, 빌드 비교 | 정적 검사; [관리 코드 가이드](docs/managed-code-analysis.md) |
|
||||
| Android APK | 매니페스트 선언, 클래스, 디컴파일된 메서드, 참조 | Linux/macOS/Windows x64의 헤드리스 JADX와 전체 JDK; [Android 가이드](docs/android-analysis.md) |
|
||||
|
|
@ -157,26 +157,26 @@ REA에는 Node.js 22.x(>=22.19), 24.x(>=24.11) 또는 26+와 npm이 필요합니
|
|||
|
||||
## 사례
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/ko/showcase/)
|
||||
|
||||
### DX-Ball: 사운드 패닝 계산 재구현
|
||||
|
||||
사운드 호출에서 위치를 패닝 값으로 변환하는 보조 함수까지 추적하고, 명령을 검사하여 불완전한 의사 코드를 C로 옮깁니다. 재구현한 코드는 원본 x86에 대한 3,205개 테스트 케이스를 통과했으며, 컴파일된 함수의 63바이트 전체를 재현합니다.
|
||||
|
||||
[사례 읽기](https://rea.tools/showcase/dx-ball/) ·
|
||||
[사례 읽기](https://rea.tools/ko/showcase/dx-ball/) ·
|
||||
[재구현 저장소](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: Electron 클립보드 브리지 추적
|
||||
|
||||
렌더러의 클립보드 API를 찾고, preload와 IPC를 거쳐 메인 프로세스까지 추적한 뒤, 서식 있는 클립보드 형식을 검사합니다.
|
||||
|
||||
[사례 읽기](https://rea.tools/showcase/notion/)
|
||||
[사례 읽기](https://rea.tools/ko/showcase/notion/)
|
||||
|
||||
### TH04: DOS 원형 탄막 계산 복원
|
||||
|
||||
원본 PC-98 게임의 16비트 명령을 검사하고 고정 각도와 조준 각도의 계산을 복원합니다. 재구현한 C++를 당시 컴파일러의 출력과 비교합니다.
|
||||
|
||||
[사례 읽기](https://rea.tools/showcase/th04/) ·
|
||||
[사례 읽기](https://rea.tools/ko/showcase/th04/) ·
|
||||
[재구현 저장소](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
REA로 흥미로운 대상을 분석했다면 알려 주세요. [issue](https://github.com/morluto/rea/issues) 또는 [pull request](https://github.com/morluto/rea/pulls)에 대상, 조사하려던 질문, REA가 어떻게 도움이 되었는지, 무엇을 알아냈는지를 담아 공유하세요.
|
||||
|
|
@ -248,7 +248,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## 문서
|
||||
|
||||
웹사이트의 [실습 가이드](https://rea.tools/guides/)부터 읽어 보세요. 정확한 옵션, 사전 요구 사항, 결과 계약은 다음 문서를 참고하세요.
|
||||
웹사이트의 [실습 가이드](https://rea.tools/ko/guides/)부터 읽어 보세요. 정확한 옵션, 사전 요구 사항, 결과 계약은 다음 문서를 참고하세요.
|
||||
|
||||
- [설치 및 설정](docs/installation.md): 에이전트 등록, 제공자 설정, 업데이트, 제거.
|
||||
- [준비 상태 확인 및 문제 해결](docs/installation.md#check-readiness-for-your-task): 특정 에이전트 또는 분석 엔진 진단.
|
||||
|
|
|
|||
20
README_pl.md
20
README_pl.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Strona internetowa](https://rea.tools/) · [Przewodniki](https://rea.tools/guides/) · [Przykłady zastosowań](https://rea.tools/showcase/)**
|
||||
**[Strona internetowa](https://rea.tools/pl/) · [Przewodniki](https://rea.tools/pl/guides/) · [Przykłady zastosowań](https://rea.tools/pl/showcase/)**
|
||||
|
||||
[Szybki start](#szybki-start) · [Jak działa REA](#jak-działa-rea) · [Co możesz analizować](#co-możesz-analizować) · [Przykłady zastosowań](#przykłady-zastosowań) · [FAQ](#faq) · [Dokumentacja](#dokumentacja)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA łączy Twojego agenta z narzędziami do analizy natywnych plików binarnych
|
|||
|
||||
Konfigurator rejestruje REA w Twoim agencie i instaluje pasujące instrukcje pracy. Analiza kodu natywnego może korzystać z istniejącej instalacji Hoppera lub Ghidry; konfigurator może też zainstalować Hoppera po uzyskaniu zgody. Statyczna analiza JavaScript nie wymaga żadnego z tych silników.
|
||||
|
||||
> **[Odwiedź stronę REA](https://rea.tools/)**, aby znaleźć instrukcje konfiguracji, ilustrowane przewodniki i rzeczywiste studia przypadków.
|
||||
> **[Odwiedź stronę REA](https://rea.tools/pl/)**, aby znaleźć instrukcje konfiguracji, ilustrowane przewodniki i rzeczywiste studia przypadków.
|
||||
|
||||
## Szybki start
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA wymaga Node.js 22.x (>=22.19), 24.x (>=24.11) lub 26+ oraz npm. Dodatkowe na
|
|||
|
||||
| Cel | Co zwraca REA | Wymagania i przewodnik |
|
||||
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Natywne pliki binarne | Pseudokod, kod asemblera, ciągi znaków, symbole, wywołania i odwołania | Hopper, Ghidra lub IDA; [analiza kodu natywnego](https://rea.tools/guides/native/) |
|
||||
| Natywne pliki binarne | Pseudokod, kod asemblera, ciągi znaków, symbole, wywołania i odwołania | Hopper, Ghidra lub IDA; [analiza kodu natywnego](https://rea.tools/pl/guides/native/) |
|
||||
| Układ pliku ELF w trybie offline | Sekcje, segmenty, oryginalne symbole/relokacje i potencjalne mechanizmy zabezpieczeń wskazane przez analizę statyczną | pwntools dostarczone przez użytkownika w systemie Linux x64; [diagnostyka plików binarnych](docs/binary-diagnostics.md) |
|
||||
| Kod bajtowy EVM | Selektory wywołań, przesunięcia bajtowe, wywnioskowane argumenty i mutowalność | Lokalny plik z surowymi bajtami lub zapisem szesnastkowym w systemie Linux x64; [przewodnik EVM offline](docs/evm-bytecode.md) |
|
||||
| Zarejestrowane awarie systemu Linux | Surowe rekordy note, rejestry/sygnały każdego zarejestrowanego wątku i opcjonalni kandydaci na mapowania | pwntools dostarczone przez użytkownika w systemie Linux x64; opcjonalnie GDB/pwndbg; [zarejestrowane awarie](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Moduły, importy, mapy źródeł, trasy, IPC i powiązania z natywnymi dodatkami | Node.js i npm; [analiza aplikacji](https://rea.tools/guides/javascript/) |
|
||||
| Strony internetowe | Struktura strony, skrypty, obserwacje sieciowe i zamówione zrzuty ekranu | Przeglądarka z rodziny Chrome; [analiza w przeglądarce](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Moduły, importy, mapy źródeł, trasy, IPC i powiązania z natywnymi dodatkami | Node.js i npm; [analiza aplikacji](https://rea.tools/pl/guides/javascript/) |
|
||||
| Strony internetowe | Struktura strony, skrypty, obserwacje sieciowe i zamówione zrzuty ekranu | Przeglądarka z rodziny Chrome; [analiza w przeglądarce](https://rea.tools/pl/guides/browser/) |
|
||||
| Zapisane przechwycenia ruchu sieciowego | Żądania, odpowiedzi, dostępne dane przesyłane i lokalizacje źródłowe | HAR; mitmdump w systemie Linux dla natywnych przechwyceń mitmproxy; [przewodnik przechwytywania](docs/web-network-captures.md) |
|
||||
| Zestawy .NET | Metadane, instrukcje CIL, zadeklarowane zależności natywne i porównania kompilacji | Analiza statyczna; [przewodnik kodu zarządzanego](docs/managed-code-analysis.md) |
|
||||
| Pakiety APK dla Androida | Deklaracje manifestu, klasy, zdekompilowane metody i odwołania | JADX bez interfejsu graficznego i pełny JDK w systemach Linux/macOS/Windows x64; [przewodnik Androida](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ Obsługiwane formaty natywne i platformy zależą od dostawcy analizy. Zobacz [k
|
|||
|
||||
## Przykłady zastosowań
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/pl/showcase/)
|
||||
|
||||
### DX-Ball: odtworzenie obliczania panoramy dźwięku
|
||||
|
||||
Prześledź wywołanie dźwięku do funkcji pomocniczej przeliczającej pozycję na panoramę, sprawdź instrukcje i przekształć niepełny pseudokod w C. Odtworzona implementacja przechodzi 3 205 przypadków dla oryginalnego x86 i odtwarza wszystkie 63 bajty skompilowanej funkcji.
|
||||
|
||||
[Przeczytaj studium przypadku](https://rea.tools/showcase/dx-ball/) · [Repozytorium odtworzonej implementacji](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Przeczytaj studium przypadku](https://rea.tools/pl/showcase/dx-ball/) · [Repozytorium odtworzonej implementacji](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: śledzenie mostu schowka w Electron
|
||||
|
||||
Znajdź API schowka w procesie renderującym, prześledź je przez preload i IPC do procesu głównego, a następnie sprawdź format schowka wraz z danymi formatowania.
|
||||
|
||||
[Przeczytaj studium przypadku](https://rea.tools/showcase/notion/)
|
||||
[Przeczytaj studium przypadku](https://rea.tools/pl/showcase/notion/)
|
||||
|
||||
### TH04: odtworzenie obliczania pierścienia pocisków w DOS-ie
|
||||
|
||||
Sprawdź 16-bitowe instrukcje oryginalnej gry na PC-98, odtwórz obliczenia kątów stałych i skierowanych na cel oraz porównaj odtworzony C++ z wynikiem historycznego kompilatora.
|
||||
|
||||
[Przeczytaj studium przypadku](https://rea.tools/showcase/th04/) · [Repozytorium odtworzonej implementacji](https://github.com/N0zoM1z0/th04)
|
||||
[Przeczytaj studium przypadku](https://rea.tools/pl/showcase/th04/) · [Repozytorium odtworzonej implementacji](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Jeśli użyłeś REA do czegoś ciekawego, chętnie to zobaczymy. Opisz swój przypadek w [zgłoszeniu](https://github.com/morluto/rea/issues) lub [pull requeście](https://github.com/morluto/rea/pulls), podając cel analizy, pytanie, sposób, w jaki REA pomogło, i swoje ustalenia.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ Jeśli używasz agenta, wykonaj [odświeżenie konfiguracji](#zaktualizuj-rea) i
|
|||
|
||||
## Dokumentacja
|
||||
|
||||
Zacznij od [przewodników z przykładami](https://rea.tools/guides/) na stronie internetowej. Dokładne opcje, wymagania wstępne i kontrakty wyników opisano tutaj:
|
||||
Zacznij od [przewodników z przykładami](https://rea.tools/pl/guides/) na stronie internetowej. Dokładne opcje, wymagania wstępne i kontrakty wyników opisano tutaj:
|
||||
|
||||
- [Instalacja i konfiguracja](docs/installation.md): rejestracja agentów, konfiguracja dostawców analizy, aktualizacje i odinstalowanie.
|
||||
- [Gotowość i rozwiązywanie problemów](docs/installation.md#check-readiness-for-your-task): diagnostyka jednego agenta lub silnika analizy.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Site](https://rea.tools/) · [Guias](https://rea.tools/guides/) · [Casos de uso](https://rea.tools/showcase/)**
|
||||
**[Site](https://rea.tools/pt-BR/) · [Guias](https://rea.tools/pt-BR/guides/) · [Casos de uso](https://rea.tools/pt-BR/showcase/)**
|
||||
|
||||
[Início rápido](#início-rápido) · [Como o REA funciona](#como-o-rea-funciona) · [O que você pode analisar](#o-que-você-pode-analisar) · [Casos de uso](#casos-de-uso) · [Perguntas frequentes](#perguntas-frequentes) · [Documentação](#documentação)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ O REA conecta seu agente a ferramentas para inspecionar binários nativos, aplic
|
|||
|
||||
A configuração registra o REA no seu agente e instala as instruções de fluxo de trabalho correspondentes. A análise nativa pode usar uma instalação existente do Hopper ou do Ghidra; a configuração também pode instalar o Hopper opcionalmente, mediante aprovação. A análise estática de JavaScript não precisa de nenhum dos dois motores.
|
||||
|
||||
> **[Visite o site do REA](https://rea.tools/)** para instruções de configuração, guias ilustrados e estudos de caso reais.
|
||||
> **[Visite o site do REA](https://rea.tools/pt-BR/)** para instruções de configuração, guias ilustrados e estudos de caso reais.
|
||||
|
||||
## Início rápido
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ O REA requer Node.js 22.x (>=22.19), 24.x (>=24.11) ou 26+, além do npm. As fer
|
|||
|
||||
| Alvo | O que o REA retorna | Requisitos e guia |
|
||||
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Binários nativos | Pseudocódigo, assembly, strings, símbolos, chamadas e referências | Hopper, Ghidra ou IDA; [análise nativa](https://rea.tools/guides/native/) |
|
||||
| Binários nativos | Pseudocódigo, assembly, strings, símbolos, chamadas e referências | Hopper, Ghidra ou IDA; [análise nativa](https://rea.tools/pt-BR/guides/native/) |
|
||||
| Estrutura ELF sem execução | Seções, segmentos, símbolos/relocações originais e possíveis mecanismos de mitigação identificados por análise estática | pwntools fornecido pelo chamador no Linux x64; [diagnóstico de binários](docs/binary-diagnostics.md) |
|
||||
| Bytecode EVM | Seletores de despacho, offsets de bytes, argumentos inferidos e mutabilidade | Entrada local com bytes brutos ou representação hexadecimal no Linux x64; [guia de EVM sem execução](docs/evm-bytecode.md) |
|
||||
| Falhas do Linux registradas | Registros note brutos, registradores/sinais de cada thread registrada e candidatos opcionais a mapeamentos | pwntools fornecido pelo chamador no Linux x64; GDB/pwndbg opcionais; [falhas registradas](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Módulos, importações, source maps, rotas, IPC e relações com complementos nativos | Node.js e npm; [análise de aplicativos](https://rea.tools/guides/javascript/) |
|
||||
| Sites | Estrutura da página, scripts, observações de rede e capturas de tela solicitadas | Um navegador da família Chrome; [análise do navegador](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Módulos, importações, source maps, rotas, IPC e relações com complementos nativos | Node.js e npm; [análise de aplicativos](https://rea.tools/pt-BR/guides/javascript/) |
|
||||
| Sites | Estrutura da página, scripts, observações de rede e capturas de tela solicitadas | Um navegador da família Chrome; [análise do navegador](https://rea.tools/pt-BR/guides/browser/) |
|
||||
| Capturas de rede salvas | Requisições, respostas, payloads acessíveis e localizações de origem | HAR; mitmdump no Linux para capturas no formato nativo do mitmproxy; [guia de capturas](docs/web-network-captures.md) |
|
||||
| Assemblies .NET | Metadados, instruções CIL, dependências nativas declaradas e comparações de builds | Inspeção estática; [guia de código gerenciado](docs/managed-code-analysis.md) |
|
||||
| APKs Android | Declarações do manifesto, classes, métodos descompilados e referências | JADX sem interface gráfica e um JDK completo no Linux/macOS/Windows x64; [guia de Android](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ Os formatos nativos e os sistemas anfitriões compatíveis variam por provedor.
|
|||
|
||||
## Casos de uso
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/pt-BR/showcase/)
|
||||
|
||||
### DX-Ball: reconstruir um cálculo de panorâmica de áudio
|
||||
|
||||
Siga uma chamada de áudio até a função auxiliar que converte posição em panorâmica, inspecione as instruções e transforme pseudocódigo incompleto em C. A reconstrução passa em 3.205 casos com o x86 original e reproduz todos os 63 bytes da função compilada.
|
||||
|
||||
[Leia o estudo de caso](https://rea.tools/showcase/dx-ball/) · [Repositório da reconstrução](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Leia o estudo de caso](https://rea.tools/pt-BR/showcase/dx-ball/) · [Repositório da reconstrução](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: rastrear a ponte da área de transferência do Electron
|
||||
|
||||
Encontre a API da área de transferência do renderizador, siga-a por preload e IPC até o processo principal e inspecione o formato da área de transferência com seus dados de formatação.
|
||||
|
||||
[Leia o estudo de caso](https://rea.tools/showcase/notion/)
|
||||
[Leia o estudo de caso](https://rea.tools/pt-BR/showcase/notion/)
|
||||
|
||||
### TH04: recuperar o cálculo de um anel de projéteis no DOS
|
||||
|
||||
Inspecione as instruções de 16 bits do jogo original para PC-98, recupere os cálculos de ângulos fixos e direcionados e compare o C++ reconstruído com a saída do compilador da época.
|
||||
|
||||
[Leia o estudo de caso](https://rea.tools/showcase/th04/) · [Repositório da reconstrução](https://github.com/N0zoM1z0/th04)
|
||||
[Leia o estudo de caso](https://rea.tools/pt-BR/showcase/th04/) · [Repositório da reconstrução](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Se você usou o REA em algo interessante, gostaríamos de conhecer. Compartilhe seu caso em uma [issue](https://github.com/morluto/rea/issues) ou um [pull request](https://github.com/morluto/rea/pulls), incluindo o alvo, sua pergunta, como o REA ajudou e o que descobriu.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ Se você usa um agente, conclua a [atualização da configuração](#atualize-o-
|
|||
|
||||
## Documentação
|
||||
|
||||
Comece pelos [guias práticos](https://rea.tools/guides/) do site. Para opções exatas, pré-requisitos e contratos dos resultados:
|
||||
Comece pelos [guias práticos](https://rea.tools/pt-BR/guides/) do site. Para opções exatas, pré-requisitos e contratos dos resultados:
|
||||
|
||||
- [Instalação e configuração](docs/installation.md): registro de agentes, configuração de provedores, atualizações e desinstalação.
|
||||
- [Prontidão e solução de problemas](docs/installation.md#check-readiness-for-your-task): diagnóstico de um agente ou motor de análise específico.
|
||||
|
|
|
|||
20
README_ru.md
20
README_ru.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Сайт](https://rea.tools/) · [Руководства](https://rea.tools/guides/) · [Примеры](https://rea.tools/showcase/)**
|
||||
**[Сайт](https://rea.tools/ru/) · [Руководства](https://rea.tools/ru/guides/) · [Примеры](https://rea.tools/ru/showcase/)**
|
||||
|
||||
[Быстрый старт](#быстрый-старт) · [Как работает REA](#как-работает-rea) · [Что можно анализировать](#что-можно-анализировать) · [Примеры](#примеры) · [Частые вопросы](#частые-вопросы) · [Документация](#документация)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA подключает вашего агента к инструментам
|
|||
|
||||
Настройка регистрирует REA в вашем агенте и устанавливает соответствующие инструкции по работе. Для нативного анализа можно использовать уже установленный Hopper или Ghidra; настройка также может установить Hopper с вашего согласия. Для статического анализа JavaScript не нужен ни один из этих движков.
|
||||
|
||||
> **[Посетите сайт REA](https://rea.tools/)**: там есть инструкции по настройке, иллюстрированные руководства и реальные исследования.
|
||||
> **[Посетите сайт REA](https://rea.tools/ru/)**: там есть инструкции по настройке, иллюстрированные руководства и реальные исследования.
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA требует Node.js 22.x (>=22.19), 24.x (>=24.11) или 26+, а так
|
|||
|
||||
| Цель | Что возвращает REA | Требования и руководство |
|
||||
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Нативные бинарные файлы | Псевдокод, ассемблер, строки, символы, вызовы и ссылки | Hopper, Ghidra или IDA; [нативный анализ](https://rea.tools/guides/native/) |
|
||||
| Нативные бинарные файлы | Псевдокод, ассемблер, строки, символы, вызовы и ссылки | Hopper, Ghidra или IDA; [нативный анализ](https://rea.tools/ru/guides/native/) |
|
||||
| Структура ELF без запуска | Секции, сегменты, исходные символы/релокации и возможные механизмы защиты по данным статического анализа | pwntools, предоставленный вызывающей стороной, в Linux x64; [диагностика бинарных файлов](docs/binary-diagnostics.md) |
|
||||
| Байт-код EVM | Селекторы диспетчеризации, смещения байтов, предполагаемые аргументы и изменяемость состояния | Локальные необработанные байты или шестнадцатеричное представление в Linux x64; [руководство по EVM без запуска](docs/evm-bytecode.md) |
|
||||
| Записанные сбои Linux | Необработанные записи note, регистры/сигналы каждого записанного потока и необязательные кандидаты сопоставления с памятью | pwntools, предоставленный вызывающей стороной, в Linux x64; необязательные GDB/pwndbg; [записанные сбои](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Модули, импорты, карты исходного кода, маршруты, IPC и связи с нативными дополнениями | Node.js и npm; [анализ приложений](https://rea.tools/guides/javascript/) |
|
||||
| Сайты | Структура страницы, скрипты, наблюдения за сетью и запрошенные снимки экрана | Браузер семейства Chrome; [анализ браузера](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Модули, импорты, карты исходного кода, маршруты, IPC и связи с нативными дополнениями | Node.js и npm; [анализ приложений](https://rea.tools/ru/guides/javascript/) |
|
||||
| Сайты | Структура страницы, скрипты, наблюдения за сетью и запрошенные снимки экрана | Браузер семейства Chrome; [анализ браузера](https://rea.tools/ru/guides/browser/) |
|
||||
| Сохранённые сетевые захваты | Запросы, ответы, доступные полезные данные и позиции в источнике | HAR; mitmdump в Linux для захватов в собственном формате mitmproxy; [руководство по сетевым захватам](docs/web-network-captures.md) |
|
||||
| Сборки .NET | Метаданные, инструкции CIL, объявленные нативные зависимости и сравнения сборок | Статическое исследование; [руководство по управляемому коду](docs/managed-code-analysis.md) |
|
||||
| Android APK | Объявления манифеста, классы, декомпилированные методы и ссылки | JADX без графического интерфейса и полный JDK в Linux/macOS/Windows x64; [руководство по Android](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ REA требует Node.js 22.x (>=22.19), 24.x (>=24.11) или 26+, а так
|
|||
|
||||
## Примеры
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/ru/showcase/)
|
||||
|
||||
### DX-Ball: восстановление расчёта звуковой панорамы
|
||||
|
||||
Проследите звуковой вызов до функции, преобразующей координату в значение панорамы, изучите инструкции и превратите неполный псевдокод в C. Восстановленная реализация проходит 3 205 тестов с исходным x86-кодом и воспроизводит все 63 байта скомпилированной функции.
|
||||
|
||||
[Прочитать исследование](https://rea.tools/showcase/dx-ball/) · [Репозиторий реконструкции](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Прочитать исследование](https://rea.tools/ru/showcase/dx-ball/) · [Репозиторий реконструкции](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: исследование моста буфера обмена Electron
|
||||
|
||||
Найдите API буфера обмена в процессе рендеринга, проследите его через preload и IPC до основного процесса и изучите формат буфера обмена с форматированием.
|
||||
|
||||
[Прочитать исследование](https://rea.tools/showcase/notion/)
|
||||
[Прочитать исследование](https://rea.tools/ru/showcase/notion/)
|
||||
|
||||
### TH04: восстановление расчёта кольца пуль в DOS
|
||||
|
||||
Изучите 16-битные инструкции оригинальной игры для PC-98, восстановите расчёты фиксированных и прицельных углов и сравните восстановленный C++ с выводом компилятора того времени.
|
||||
|
||||
[Прочитать исследование](https://rea.tools/showcase/th04/) · [Репозиторий реконструкции](https://github.com/N0zoM1z0/th04)
|
||||
[Прочитать исследование](https://rea.tools/ru/showcase/th04/) · [Репозиторий реконструкции](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Если вы исследовали с REA что-то интересное, поделитесь результатом. Создайте [issue](https://github.com/morluto/rea/issues) или [pull request](https://github.com/morluto/rea/pulls) и укажите цель, ваш вопрос, как помог REA и что удалось узнать.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## Документация
|
||||
|
||||
Начните с [практических руководств](https://rea.tools/guides/) на сайте. Точные параметры, требования и контракты результатов описаны здесь:
|
||||
Начните с [практических руководств](https://rea.tools/ru/guides/) на сайте. Точные параметры, требования и контракты результатов описаны здесь:
|
||||
|
||||
- [Установка и настройка](docs/installation.md): регистрация агентов, настройка провайдеров, обновление и удаление.
|
||||
- [Готовность и устранение неполадок](docs/installation.md#check-readiness-for-your-task): диагностика конкретного агента или движка анализа.
|
||||
|
|
|
|||
20
README_th.md
20
README_th.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[เว็บไซต์](https://rea.tools/) · [คู่มือ](https://rea.tools/guides/) · [ตัวอย่างการใช้งาน](https://rea.tools/showcase/)**
|
||||
**[เว็บไซต์](https://rea.tools/th/) · [คู่มือ](https://rea.tools/th/guides/) · [ตัวอย่างการใช้งาน](https://rea.tools/th/showcase/)**
|
||||
|
||||
[เริ่มต้นอย่างรวดเร็ว](#เริ่มต้นอย่างรวดเร็ว) · [REA ทำงานอย่างไร](#rea-ทำงานอย่างไร) · [สิ่งที่วิเคราะห์ได้](#สิ่งที่วิเคราะห์ได้) · [ตัวอย่างการใช้งาน](#ตัวอย่างการใช้งาน) · [คำถามที่พบบ่อย](#คำถามที่พบบ่อย) · [เอกสาร](#เอกสาร)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA เชื่อมเอเจนต์ของคุณกับเคร
|
|||
|
||||
ขั้นตอนตั้งค่าจะลงทะเบียน REA กับเอเจนต์และติดตั้งคำแนะนำการทำงานที่ตรงกัน การวิเคราะห์เนทีฟใช้ Hopper หรือ Ghidra ที่ติดตั้งอยู่แล้วได้ และขั้นตอนตั้งค่าสามารถติดตั้ง Hopper เพิ่มเติมเมื่อได้รับอนุมัติ การวิเคราะห์ JavaScript แบบสถิตไม่ต้องใช้เอนจินทั้งสองนี้
|
||||
|
||||
> **[เยี่ยมชมเว็บไซต์ REA](https://rea.tools/)** เพื่อดูคำแนะนำการตั้งค่า คู่มือพร้อมภาพประกอบ และกรณีศึกษาจริง
|
||||
> **[เยี่ยมชมเว็บไซต์ REA](https://rea.tools/th/)** เพื่อดูคำแนะนำการตั้งค่า คู่มือพร้อมภาพประกอบ และกรณีศึกษาจริง
|
||||
|
||||
## เริ่มต้นอย่างรวดเร็ว
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA ต้องใช้ Node.js 22.x (>=22.19), 24.x (>=24.11) หรือ 26
|
|||
|
||||
| เป้าหมาย | สิ่งที่ REA ส่งกลับ | ข้อกำหนดและคู่มือ |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| ไบนารีเนทีฟ | โค้ดเทียม แอสเซมบลี สตริง สัญลักษณ์ การเรียก และการอ้างอิง | Hopper, Ghidra หรือ IDA; [การวิเคราะห์เนทีฟ](https://rea.tools/guides/native/) |
|
||||
| ไบนารีเนทีฟ | โค้ดเทียม แอสเซมบลี สตริง สัญลักษณ์ การเรียก และการอ้างอิง | Hopper, Ghidra หรือ IDA; [การวิเคราะห์เนทีฟ](https://rea.tools/th/guides/native/) |
|
||||
| โครงสร้าง ELF แบบออฟไลน์ | เซกชัน เซกเมนต์ สัญลักษณ์/รีโลเคชันต้นฉบับ และตัวเลือกกลไกป้องกันที่พบจากการวิเคราะห์แบบสถิต | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; [การวินิจฉัยไบนารี](docs/binary-diagnostics.md) |
|
||||
| ไบต์โค้ด EVM | ตัวเลือกฟังก์ชันสำหรับการเรียก ออฟเซ็ตไบต์ อาร์กิวเมนต์และความสามารถในการเปลี่ยนสถานะที่อนุมานได้ | ไฟล์บนเครื่องที่มีไบต์ดิบหรือข้อมูลเลขฐานสิบหกบน Linux x64; [คู่มือ EVM แบบออฟไลน์](docs/evm-bytecode.md) |
|
||||
| ข้อมูลการแครชของ Linux ที่บันทึกไว้ | ระเบียน note ดิบ รีจิสเตอร์/สัญญาณของทุกเธรดที่บันทึกไว้ และตัวเลือกการแมปเพิ่มเติม | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; เลือกใช้ GDB/pwndbg เพิ่มเติมได้; [การแครชที่บันทึกไว้](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | โมดูล การนำเข้า ซอร์สแมป เส้นทาง IPC และความสัมพันธ์กับส่วนเสริมเนทีฟ | Node.js และ npm; [การวิเคราะห์แอปพลิเคชัน](https://rea.tools/guides/javascript/) |
|
||||
| เว็บไซต์ | โครงสร้างหน้า สคริปต์ ข้อมูลเครือข่ายที่สังเกตได้ และภาพหน้าจอที่ร้องขอ | เบราว์เซอร์ในตระกูล Chrome; [การวิเคราะห์ผ่านเบราว์เซอร์](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | โมดูล การนำเข้า ซอร์สแมป เส้นทาง IPC และความสัมพันธ์กับส่วนเสริมเนทีฟ | Node.js และ npm; [การวิเคราะห์แอปพลิเคชัน](https://rea.tools/th/guides/javascript/) |
|
||||
| เว็บไซต์ | โครงสร้างหน้า สคริปต์ ข้อมูลเครือข่ายที่สังเกตได้ และภาพหน้าจอที่ร้องขอ | เบราว์เซอร์ในตระกูล Chrome; [การวิเคราะห์ผ่านเบราว์เซอร์](https://rea.tools/th/guides/browser/) |
|
||||
| ข้อมูลเครือข่ายที่บันทึกไว้ | คำขอ คำตอบ เพย์โหลดที่ปรากฏ และตำแหน่งต้นทาง | HAR; mitmdump บน Linux สำหรับข้อมูลที่บันทึกในรูปแบบเนทีฟของ mitmproxy; [คู่มือการบันทึกข้อมูล](docs/web-network-captures.md) |
|
||||
| แอสเซมบลี .NET | เมทาดาทา คำสั่ง CIL การพึ่งพาเนทีฟที่ประกาศไว้ และการเปรียบเทียบผลการบิลด์ | การตรวจสอบแบบสถิต; [คู่มือโค้ดแบบจัดการ](docs/managed-code-analysis.md) |
|
||||
| APK ของ Android | การประกาศใน manifest คลาส เมธอดที่ดีคอมไพล์ และการอ้างอิง | JADX แบบไม่มี GUI และ JDK แบบเต็มบน Linux/macOS/Windows x64; [คู่มือ Android](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ REA ต้องใช้ Node.js 22.x (>=22.19), 24.x (>=24.11) หรือ 26
|
|||
|
||||
## ตัวอย่างการใช้งาน
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/th/showcase/)
|
||||
|
||||
### DX-Ball: สร้างการคำนวณแพนเสียงขึ้นใหม่
|
||||
|
||||
ติดตามการเรียกเสียงไปยังฟังก์ชันช่วยแปลงตำแหน่งเป็นค่าแพน ตรวจสอบคำสั่ง และแปลงโค้ดเทียมที่ยังไม่สมบูรณ์เป็น C การสร้างขึ้นใหม่นี้ผ่านการทดสอบ 3,205 กรณีเทียบกับ x86 ต้นฉบับ และสร้างไบต์ทั้ง 63 ไบต์ของฟังก์ชันที่คอมไพล์แล้วได้ตรงกัน
|
||||
|
||||
[อ่านกรณีศึกษา](https://rea.tools/showcase/dx-ball/) · [รีโพซิทอรีการสร้างขึ้นใหม่](https://github.com/N0zoM1z0/dx-ball)
|
||||
[อ่านกรณีศึกษา](https://rea.tools/th/showcase/dx-ball/) · [รีโพซิทอรีการสร้างขึ้นใหม่](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: ติดตามบริดจ์คลิปบอร์ดของ Electron
|
||||
|
||||
ค้นหา API คลิปบอร์ดของ renderer ติดตามผ่าน preload และ IPC ไปยังโปรเซสหลัก แล้วตรวจสอบรูปแบบคลิปบอร์ดที่มีข้อมูลการจัดรูปแบบ
|
||||
|
||||
[อ่านกรณีศึกษา](https://rea.tools/showcase/notion/)
|
||||
[อ่านกรณีศึกษา](https://rea.tools/th/showcase/notion/)
|
||||
|
||||
### TH04: กู้คืนการคำนวณวงแหวนกระสุนของ DOS
|
||||
|
||||
ตรวจสอบคำสั่ง 16 บิตของเกมต้นฉบับบน PC-98 กู้คืนการคำนวณมุมคงที่และมุมเล็งเป้าหมาย แล้วเปรียบเทียบ C++ ที่สร้างขึ้นใหม่กับผลลัพธ์จากคอมไพเลอร์ในยุคนั้น
|
||||
|
||||
[อ่านกรณีศึกษา](https://rea.tools/showcase/th04/) · [รีโพซิทอรีการสร้างขึ้นใหม่](https://github.com/N0zoM1z0/th04)
|
||||
[อ่านกรณีศึกษา](https://rea.tools/th/showcase/th04/) · [รีโพซิทอรีการสร้างขึ้นใหม่](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
หากคุณใช้ REA กับสิ่งที่น่าสนใจ เราอยากเห็นผลงานของคุณ แบ่งปันกรณีของคุณผ่าน [issue](https://github.com/morluto/rea/issues) หรือ [pull request](https://github.com/morluto/rea/pulls) พร้อมระบุเป้าหมาย คำถามของคุณ REA ช่วยอย่างไร และสิ่งที่คุณค้นพบ
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## เอกสาร
|
||||
|
||||
เริ่มจาก[คู่มือพร้อมตัวอย่าง](https://rea.tools/guides/) บนเว็บไซต์ สำหรับตัวเลือก ข้อกำหนดเบื้องต้น และสัญญาผลลัพธ์ที่แน่นอน:
|
||||
เริ่มจาก[คู่มือพร้อมตัวอย่าง](https://rea.tools/th/guides/) บนเว็บไซต์ สำหรับตัวเลือก ข้อกำหนดเบื้องต้น และสัญญาผลลัพธ์ที่แน่นอน:
|
||||
|
||||
- [การติดตั้งและตั้งค่า](docs/installation.md): การลงทะเบียนเอเจนต์ การตั้งค่าผู้ให้บริการ การอัปเดต และการถอนการติดตั้ง
|
||||
- [ความพร้อมใช้งานและการแก้ไขปัญหา](docs/installation.md#check-readiness-for-your-task): ตรวจวินิจฉัยเอเจนต์หรือเอนจินวิเคราะห์หนึ่งตัว
|
||||
|
|
|
|||
20
README_tr.md
20
README_tr.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Web sitesi](https://rea.tools/) · [Rehberler](https://rea.tools/guides/) · [Örnek çalışmalar](https://rea.tools/showcase/)**
|
||||
**[Web sitesi](https://rea.tools/tr/) · [Rehberler](https://rea.tools/tr/guides/) · [Örnek çalışmalar](https://rea.tools/tr/showcase/)**
|
||||
|
||||
[Hızlı başlangıç](#hızlı-başlangıç) · [REA nasıl çalışır](#rea-nasıl-çalışır) · [Neleri analiz edebilirsiniz](#neleri-analiz-edebilirsiniz) · [Örnek çalışmalar](#örnek-çalışmalar) · [Sık sorulan sorular](#sık-sorulan-sorular) · [Belgeler](#belgeler)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA, ajanınızı yerel makine kodu içeren ikili dosyaları, JavaScript ve Elec
|
|||
|
||||
Kurulum, REA'yı ajanınıza kaydeder ve uyumlu iş akışı talimatlarını yükler. Yerel makine kodu analizi mevcut bir Hopper veya Ghidra kurulumunu kullanabilir; kurulum işlemi, onayınızla isteğe bağlı olarak Hopper da yükleyebilir. Statik JavaScript analizi bu iki motora da ihtiyaç duymaz.
|
||||
|
||||
> Kurulum talimatları, görselli rehberler ve gerçek örnek çalışmalar için **[REA web sitesini ziyaret edin](https://rea.tools/)**.
|
||||
> Kurulum talimatları, görselli rehberler ve gerçek örnek çalışmalar için **[REA web sitesini ziyaret edin](https://rea.tools/tr/)**.
|
||||
|
||||
## Hızlı başlangıç
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA; Node.js 22.x (>=22.19), 24.x (>=24.11) veya 26+ ve npm gerektirir. Ek araç
|
|||
|
||||
| Hedef | REA'nın döndürdükleri | Gereksinimler ve rehber |
|
||||
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Yerel makine kodu içeren ikili dosyalar | Sözde kod, assembly kodu, dizeler, semboller, çağrılar ve referanslar | Hopper, Ghidra veya IDA; [yerel kod analizi](https://rea.tools/guides/native/) |
|
||||
| Yerel makine kodu içeren ikili dosyalar | Sözde kod, assembly kodu, dizeler, semboller, çağrılar ve referanslar | Hopper, Ghidra veya IDA; [yerel kod analizi](https://rea.tools/tr/guides/native/) |
|
||||
| Çevrimdışı ELF yapısı | Bölümler, segmentler, özgün semboller/yeniden konumlandırmalar ve statik analizden olası güvenlik önlemleri | Linux x64 üzerinde çağıranın sağladığı pwntools; [ikili dosya tanılama](docs/binary-diagnostics.md) |
|
||||
| EVM bayt kodu | Yönlendirme seçicileri, bayt ofsetleri, çıkarımla belirlenen argümanlar ve durum değiştirilebilirliği | Linux x64 üzerinde yerel ham bayt/onaltılık girdi; [çevrimdışı EVM rehberi](docs/evm-bytecode.md) |
|
||||
| Kaydedilmiş Linux çökmeleri | Ham note kayıtları, kaydedilen her iş parçacığının yazmaçları/sinyalleri ve isteğe bağlı eşleme adayları | Linux x64 üzerinde çağıranın sağladığı pwntools; isteğe bağlı GDB/pwndbg; [kaydedilmiş çökmeler](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Modüller, içe aktarmalar, kaynak haritaları, rotalar, IPC ve yerel eklenti ilişkileri | Node.js ve npm; [uygulama analizi](https://rea.tools/guides/javascript/) |
|
||||
| Web siteleri | Sayfa yapısı, betikler, ağ gözlemleri ve istenen ekran görüntüleri | Chrome ailesinden bir tarayıcı; [tarayıcı analizi](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Modüller, içe aktarmalar, kaynak haritaları, rotalar, IPC ve yerel eklenti ilişkileri | Node.js ve npm; [uygulama analizi](https://rea.tools/tr/guides/javascript/) |
|
||||
| Web siteleri | Sayfa yapısı, betikler, ağ gözlemleri ve istenen ekran görüntüleri | Chrome ailesinden bir tarayıcı; [tarayıcı analizi](https://rea.tools/tr/guides/browser/) |
|
||||
| Kaydedilmiş ağ yakalamaları | İstekler, yanıtlar, erişilebilir yük içerikleri ve kaynak konumları | HAR; mitmproxy'nin kendi biçimindeki yakalamalar için Linux üzerinde mitmdump; [ağ yakalama rehberi](docs/web-network-captures.md) |
|
||||
| .NET derlemeleri | Meta veriler, CIL talimatları, bildirilmiş yerel bağımlılıklar ve derleme karşılaştırmaları | Statik inceleme; [yönetilen kod rehberi](docs/managed-code-analysis.md) |
|
||||
| Android APK'leri | Manifest bildirimleri, sınıflar, tersine derlenmiş metotlar ve referanslar | Linux/macOS/Windows x64 üzerinde arayüzsüz JADX ve tam bir JDK; [Android rehberi](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ Yerel makine kodu içeren ikili dosya biçimleri ve ana bilgisayar desteği sağ
|
|||
|
||||
## Örnek çalışmalar
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/tr/showcase/)
|
||||
|
||||
### DX-Ball: Sesin stereo konumlandırma hesabını yeniden oluşturma
|
||||
|
||||
Bir ses çağrısından konumu stereo konumlandırmaya dönüştüren yardımcı fonksiyona ilerleyin, talimatları inceleyin ve eksik sözde kodu C'ye dönüştürün. Yeniden oluşturulan kod, özgün x86 üzerinde 3.205 test durumunu geçer ve derlenmiş fonksiyonun 63 baytının tamamını yeniden üretir.
|
||||
|
||||
[Örnek çalışmayı okuyun](https://rea.tools/showcase/dx-ball/) · [Yeniden oluşturma deposu](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Örnek çalışmayı okuyun](https://rea.tools/tr/showcase/dx-ball/) · [Yeniden oluşturma deposu](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: Electron pano köprüsünü izleme
|
||||
|
||||
İşleyici sürecin pano API'sini bulun, preload ve IPC üzerinden ana sürece kadar izleyin ve zengin pano biçimini inceleyin.
|
||||
|
||||
[Örnek çalışmayı okuyun](https://rea.tools/showcase/notion/)
|
||||
[Örnek çalışmayı okuyun](https://rea.tools/tr/showcase/notion/)
|
||||
|
||||
### TH04: DOS mermi halkası hesabını geri çıkarma
|
||||
|
||||
Özgün PC-98 oyununun 16 bit talimatlarını inceleyin, sabit ve hedefe yönelik açı hesaplarını geri çıkarın ve yeniden oluşturulan C++ kodunu dönemin derleyici çıktısıyla karşılaştırın.
|
||||
|
||||
[Örnek çalışmayı okuyun](https://rea.tools/showcase/th04/) · [Yeniden oluşturma deposu](https://github.com/N0zoM1z0/th04)
|
||||
[Örnek çalışmayı okuyun](https://rea.tools/tr/showcase/th04/) · [Yeniden oluşturma deposu](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
REA'yı ilginç bir konuda kullandıysanız görmek isteriz. Hedefi, sorunuzu, REA'nın nasıl yardımcı olduğunu ve bulgularınızı bir [issue](https://github.com/morluto/rea/issues) veya [pull request](https://github.com/morluto/rea/pulls) ile paylaşın.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ Ajan kullanıyorsanız [kurulum yenilemesini](#reayı-güncelleyin) tamamlayın
|
|||
|
||||
## Belgeler
|
||||
|
||||
Web sitesindeki [uygulamalı rehberlerden](https://rea.tools/guides/) başlayın. Kesin seçenekler, ön koşullar ve sonuç sözleşmeleri için:
|
||||
Web sitesindeki [uygulamalı rehberlerden](https://rea.tools/tr/guides/) başlayın. Kesin seçenekler, ön koşullar ve sonuç sözleşmeleri için:
|
||||
|
||||
- [Yükleme ve kurulum](docs/installation.md): ajan kaydı, sağlayıcı yapılandırması, güncellemeler ve kaldırma.
|
||||
- [Hazırlık ve sorun giderme](docs/installation.md#check-readiness-for-your-task): belirli bir ajanı veya analiz motorunu tanılama.
|
||||
|
|
|
|||
20
README_uk.md
20
README_uk.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Сайт](https://rea.tools/) · [Посібники](https://rea.tools/guides/) · [Приклади](https://rea.tools/showcase/)**
|
||||
**[Сайт](https://rea.tools/uk/) · [Посібники](https://rea.tools/uk/guides/) · [Приклади](https://rea.tools/uk/showcase/)**
|
||||
|
||||
[Швидкий старт](#швидкий-старт) · [Як працює REA](#як-працює-rea) · [Що можна аналізувати](#що-можна-аналізувати) · [Приклади](#приклади) · [Поширені запитання](#поширені-запитання) · [Документація](#документація)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA підключає вашого агента до інструментів
|
|||
|
||||
Налаштування реєструє REA у вашому агенті та встановлює відповідні інструкції робочих процесів. Для нативного аналізу можна використати вже встановлений Hopper або Ghidra; налаштування також може встановити Hopper за вашою згодою. Статичному аналізу JavaScript не потрібен жоден із цих рушіїв.
|
||||
|
||||
> **[Відвідайте сайт REA](https://rea.tools/)**, щоб знайти інструкції налаштування, ілюстровані посібники та реальні дослідження.
|
||||
> **[Відвідайте сайт REA](https://rea.tools/uk/)**, щоб знайти інструкції налаштування, ілюстровані посібники та реальні дослідження.
|
||||
|
||||
## Швидкий старт
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA потребує Node.js 22.x (>=22.19), 24.x (>=24.11) або 26+, а та
|
|||
|
||||
| Ціль | Що повертає REA | Вимоги й посібник |
|
||||
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Нативні бінарні файли | Псевдокод, асемблерний код, рядки, символи, виклики й посилання | Hopper, Ghidra або IDA; [нативний аналіз](https://rea.tools/guides/native/) |
|
||||
| Нативні бінарні файли | Псевдокод, асемблерний код, рядки, символи, виклики й посилання | Hopper, Ghidra або IDA; [нативний аналіз](https://rea.tools/uk/guides/native/) |
|
||||
| Структура ELF без запуску | Секції, сегменти, початкові символи/релокації та можливі захисні механізми за даними статичного аналізу | pwntools, наданий стороною, що викликає інструмент, у Linux x64; [діагностика бінарних файлів](docs/binary-diagnostics.md) |
|
||||
| Байт-код EVM | Селектори диспетчеризації, зміщення байтів, виведені припущення про аргументи та змінюваність стану | Локальні необроблені байти або шістнадцяткове представлення у Linux x64; [посібник EVM без запуску](docs/evm-bytecode.md) |
|
||||
| Записані аварійні завершення в Linux | Необроблені записи note, регістри/сигнали кожного записаного потоку й необов'язкові кандидати зіставлення пам'яті | pwntools, наданий стороною, що викликає інструмент, у Linux x64; необов'язкові GDB/pwndbg; [записані аварійні завершення](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Модулі, імпорти, карти вихідного коду, маршрути, IPC і зв'язки з нативними доповненнями | Node.js і npm; [аналіз застосунків](https://rea.tools/guides/javascript/) |
|
||||
| Сайти | Структура сторінки, скрипти, мережеві спостереження й запитані знімки екрана | Браузер сімейства Chrome; [аналіз браузера](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Модулі, імпорти, карти вихідного коду, маршрути, IPC і зв'язки з нативними доповненнями | Node.js і npm; [аналіз застосунків](https://rea.tools/uk/guides/javascript/) |
|
||||
| Сайти | Структура сторінки, скрипти, мережеві спостереження й запитані знімки екрана | Браузер сімейства Chrome; [аналіз браузера](https://rea.tools/uk/guides/browser/) |
|
||||
| Збережені мережеві захоплення | Запити, відповіді, доступні корисні дані та місця в джерелі | HAR; mitmdump у Linux для захоплень у власному форматі mitmproxy; [посібник мережевих захоплень](docs/web-network-captures.md) |
|
||||
| Збірки .NET | Метадані, інструкції CIL, оголошені нативні залежності й порівняння збірок | Статична перевірка; [посібник керованого коду](docs/managed-code-analysis.md) |
|
||||
| Android APK | Оголошення маніфесту, класи, декомпільовані методи й посилання | JADX без графічного інтерфейсу й повний JDK у Linux/macOS/Windows x64; [посібник Android](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ REA потребує Node.js 22.x (>=22.19), 24.x (>=24.11) або 26+, а та
|
|||
|
||||
## Приклади
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/uk/showcase/)
|
||||
|
||||
### DX-Ball: відновлення розрахунку звукової панорами
|
||||
|
||||
Простежте звуковий виклик до допоміжної функції, що перетворює координату на панорамування, перевірте інструкції та перетворіть неповний псевдокод на C. Відновлена реалізація проходить 3 205 тестів з оригінальним x86-кодом і відтворює всі 63 байти скомпільованої функції.
|
||||
|
||||
[Прочитати дослідження](https://rea.tools/showcase/dx-ball/) · [Репозиторій реконструкції](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Прочитати дослідження](https://rea.tools/uk/showcase/dx-ball/) · [Репозиторій реконструкції](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: відстеження мосту буфера обміну Electron
|
||||
|
||||
Знайдіть API буфера обміну в процесі рендерингу, простежте його через preload та IPC до головного процесу й перевірте формат буфера обміну з даними форматування.
|
||||
|
||||
[Прочитати дослідження](https://rea.tools/showcase/notion/)
|
||||
[Прочитати дослідження](https://rea.tools/uk/showcase/notion/)
|
||||
|
||||
### TH04: відновлення розрахунку кільця куль у DOS
|
||||
|
||||
Перевірте 16-бітні інструкції оригінальної гри для PC-98, відновіть розрахунки фіксованих і прицільних кутів та порівняйте відновлений C++ із виводом тогочасного компілятора.
|
||||
|
||||
[Прочитати дослідження](https://rea.tools/showcase/th04/) · [Репозиторій реконструкції](https://github.com/N0zoM1z0/th04)
|
||||
[Прочитати дослідження](https://rea.tools/uk/showcase/th04/) · [Репозиторій реконструкції](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Якщо ви дослідили з REA щось цікаве, поділіться результатом. Створіть [issue](https://github.com/morluto/rea/issues) або [pull request](https://github.com/morluto/rea/pulls) і вкажіть ціль, ваше запитання, як допоміг REA та що ви з'ясували.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## Документація
|
||||
|
||||
Почніть із [практичних посібників](https://rea.tools/guides/) на сайті. Точні параметри, передумови й контракти результатів описано тут:
|
||||
Почніть із [практичних посібників](https://rea.tools/uk/guides/) на сайті. Точні параметри, передумови й контракти результатів описано тут:
|
||||
|
||||
- [Встановлення й налаштування](docs/installation.md): реєстрація агентів, конфігурація провайдерів, оновлення та видалення.
|
||||
- [Готовність та усунення неполадок](docs/installation.md#check-readiness-for-your-task): діагностика конкретного агента або рушія аналізу.
|
||||
|
|
|
|||
20
README_vi.md
20
README_vi.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Trang web](https://rea.tools/) · [Hướng dẫn](https://rea.tools/guides/) · [Các nghiên cứu điển hình](https://rea.tools/showcase/)**
|
||||
**[Trang web](https://rea.tools/vi/) · [Hướng dẫn](https://rea.tools/vi/guides/) · [Các nghiên cứu điển hình](https://rea.tools/vi/showcase/)**
|
||||
|
||||
[Bắt đầu nhanh](#bắt-đầu-nhanh) · [Cách REA hoạt động](#cách-rea-hoạt-động) · [Những gì bạn có thể phân tích](#những-gì-bạn-có-thể-phân-tích) · [Các nghiên cứu điển hình](#các-nghiên-cứu-điển-hình) · [Câu hỏi thường gặp](#câu-hỏi-thường-gặp) · [Tài liệu](#tài-liệu)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA kết nối tác nhân của bạn với các công cụ kiểm tra tệp nh
|
|||
|
||||
Quá trình thiết lập đăng ký REA với tác nhân và cài đặt các hướng dẫn quy trình tương ứng. Phân tích mã máy có thể sử dụng Hopper hoặc Ghidra đã cài sẵn; quá trình thiết lập cũng có thể cài Hopper nếu bạn chấp thuận. Phân tích tĩnh JavaScript không cần công cụ nào trong hai công cụ này.
|
||||
|
||||
> **[Truy cập trang web REA](https://rea.tools/)** để xem cách thiết lập, hướng dẫn có hình minh họa và các nghiên cứu điển hình thực tế.
|
||||
> **[Truy cập trang web REA](https://rea.tools/vi/)** để xem cách thiết lập, hướng dẫn có hình minh họa và các nghiên cứu điển hình thực tế.
|
||||
|
||||
## Bắt đầu nhanh
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA yêu cầu Node.js 22.x (>=22.19), 24.x (>=24.11) hoặc 26+, cùng với np
|
|||
|
||||
| Mục tiêu | REA trả về gì | Yêu cầu và hướng dẫn |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Tệp nhị phân mã máy | Mã giả, hợp ngữ, chuỗi, ký hiệu, lời gọi và tham chiếu | Hopper, Ghidra hoặc IDA; [phân tích mã máy](https://rea.tools/guides/native/) |
|
||||
| Tệp nhị phân mã máy | Mã giả, hợp ngữ, chuỗi, ký hiệu, lời gọi và tham chiếu | Hopper, Ghidra hoặc IDA; [phân tích mã máy](https://rea.tools/vi/guides/native/) |
|
||||
| Bố cục ELF ngoại tuyến | Các section, segment, ký hiệu/thông tin tái định vị gốc và các biện pháp giảm thiểu có thể có từ phân tích tĩnh | pwntools do bên gọi cung cấp trên Linux x64; [chẩn đoán tệp nhị phân](docs/binary-diagnostics.md) |
|
||||
| Bytecode EVM | Bộ chọn điều phối, độ lệch byte, tham số suy luận và khả năng thay đổi trạng thái | Đầu vào cục bộ chứa byte thô hoặc dạng thập lục phân trên Linux x64; [hướng dẫn EVM ngoại tuyến](docs/evm-bytecode.md) |
|
||||
| Sự cố Linux đã ghi lại | Bản ghi note thô, thanh ghi/tín hiệu của mọi luồng được ghi lại và các ứng viên ánh xạ tùy chọn | pwntools do bên gọi cung cấp trên Linux x64; GDB/pwndbg tùy chọn; [sự cố đã ghi lại](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | Mô-đun, các khai báo import, source map, tuyến, IPC và quan hệ với tiện ích mở rộng mã máy | Node.js và npm; [phân tích ứng dụng](https://rea.tools/guides/javascript/) |
|
||||
| Trang web | Cấu trúc trang, script, quan sát mạng và ảnh chụp màn hình được yêu cầu | Trình duyệt thuộc họ Chrome; [phân tích trình duyệt](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | Mô-đun, các khai báo import, source map, tuyến, IPC và quan hệ với tiện ích mở rộng mã máy | Node.js và npm; [phân tích ứng dụng](https://rea.tools/vi/guides/javascript/) |
|
||||
| Trang web | Cấu trúc trang, script, quan sát mạng và ảnh chụp màn hình được yêu cầu | Trình duyệt thuộc họ Chrome; [phân tích trình duyệt](https://rea.tools/vi/guides/browser/) |
|
||||
| Bản ghi lưu lượng mạng đã lưu | Yêu cầu, phản hồi, payload có thể truy cập và vị trí nguồn | HAR; mitmdump trên Linux cho bản ghi định dạng gốc của mitmproxy; [hướng dẫn bản ghi mạng](docs/web-network-captures.md) |
|
||||
| Assembly .NET | Siêu dữ liệu, lệnh CIL, các phụ thuộc mã máy được khai báo và so sánh bản dựng | Kiểm tra tĩnh; [hướng dẫn mã được quản lý](docs/managed-code-analysis.md) |
|
||||
| APK Android | Khai báo manifest, lớp, phương thức được dịch ngược và tham chiếu | JADX không giao diện đồ họa và JDK đầy đủ trên Linux/macOS/Windows x64; [hướng dẫn Android](docs/android-analysis.md) |
|
||||
|
|
@ -157,25 +157,25 @@ Kiểm tra tĩnh JavaScript và .NET đọc các tệp được cung cấp mà k
|
|||
|
||||
## Các nghiên cứu điển hình
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/vi/showcase/)
|
||||
|
||||
### DX-Ball: tái tạo phép tính phân bố âm thanh trái phải
|
||||
|
||||
Lần theo lời gọi âm thanh đến hàm hỗ trợ chuyển vị trí thành giá trị phân bố âm thanh, kiểm tra các lệnh và chuyển mã giả chưa đầy đủ sang C. Bản tái tạo vượt qua 3.205 trường hợp kiểm thử với x86 gốc và tái tạo đủ 63 byte của hàm đã biên dịch.
|
||||
|
||||
[Đọc nghiên cứu điển hình](https://rea.tools/showcase/dx-ball/) · [Kho mã tái tạo](https://github.com/N0zoM1z0/dx-ball)
|
||||
[Đọc nghiên cứu điển hình](https://rea.tools/vi/showcase/dx-ball/) · [Kho mã tái tạo](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: lần theo cầu nối clipboard của Electron
|
||||
|
||||
Tìm API clipboard trong tiến trình kết xuất, lần theo qua preload và IPC đến tiến trình chính, rồi kiểm tra định dạng clipboard có dữ liệu định dạng phong phú.
|
||||
|
||||
[Đọc nghiên cứu điển hình](https://rea.tools/showcase/notion/)
|
||||
[Đọc nghiên cứu điển hình](https://rea.tools/vi/showcase/notion/)
|
||||
|
||||
### TH04: khôi phục phép tính vòng đạn trong DOS
|
||||
|
||||
Kiểm tra các lệnh 16 bit của trò chơi PC-98 gốc, khôi phục phép tính góc cố định và góc nhắm mục tiêu, rồi so sánh C++ được tái tạo với đầu ra của trình biên dịch thời đó.
|
||||
|
||||
[Đọc nghiên cứu điển hình](https://rea.tools/showcase/th04/) · [Kho mã tái tạo](https://github.com/N0zoM1z0/th04)
|
||||
[Đọc nghiên cứu điển hình](https://rea.tools/vi/showcase/th04/) · [Kho mã tái tạo](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Nếu bạn dùng REA cho một mục tiêu thú vị, chúng tôi muốn biết. Chia sẻ trường hợp của bạn qua [issue](https://github.com/morluto/rea/issues) hoặc [pull request](https://github.com/morluto/rea/pulls), nêu mục tiêu, câu hỏi, cách REA giúp bạn và những gì tìm được.
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ Nếu dùng tác nhân, hãy hoàn tất [làm mới thiết lập](#cập-nhậ
|
|||
|
||||
## Tài liệu
|
||||
|
||||
Bắt đầu với [hướng dẫn thực hành](https://rea.tools/guides/) trên trang web. Để biết tùy chọn cụ thể, điều kiện tiên quyết và hợp đồng kết quả:
|
||||
Bắt đầu với [hướng dẫn thực hành](https://rea.tools/vi/guides/) trên trang web. Để biết tùy chọn cụ thể, điều kiện tiên quyết và hợp đồng kết quả:
|
||||
|
||||
- [Cài đặt và thiết lập](docs/installation.md): đăng ký tác nhân, cấu hình trình phân tích, cập nhật và gỡ cài đặt.
|
||||
- [Kiểm tra mức sẵn sàng và khắc phục sự cố](docs/installation.md#check-readiness-for-your-task): chẩn đoán một tác nhân hoặc bộ máy phân tích cụ thể.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[網站](https://rea.tools/) · [指南](https://rea.tools/guides/) · [案例](https://rea.tools/showcase/)**
|
||||
**[網站](https://rea.tools/zh-TW/) · [指南](https://rea.tools/zh-TW/guides/) · [案例](https://rea.tools/zh-TW/showcase/)**
|
||||
|
||||
[快速開始](#快速開始) · [REA 的工作原理](#rea-的工作原理) · [可以分析什麼](#可以分析什麼) · [案例](#案例) · [常見問題](#常見問題) · [文件](#文件)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA 將 AI 代理連接到分析工具,用於檢查原生二進位檔案、Jav
|
|||
|
||||
設定流程會向 AI 代理註冊 REA,並安裝對應的工作流程指引。原生分析可以使用已有的 Hopper 或 Ghidra;設定流程也可以在你核准後安裝 Hopper。靜態 JavaScript 分析不需要這兩個引擎。
|
||||
|
||||
> **[訪問 REA 網站](https://rea.tools/)**,查看設定說明、圖解指南和真實案例。
|
||||
> **[訪問 REA 網站](https://rea.tools/zh-TW/)**,查看設定說明、圖解指南和真實案例。
|
||||
|
||||
## 快速開始
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。
|
|||
|
||||
| 目標 | REA 返回的內容 | 要求與指南 |
|
||||
| --------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| 原生二進位檔案 | 偽程式碼、組合語言、字串、符號、呼叫和引用 | Hopper、Ghidra 或 IDA;[原生分析](https://rea.tools/guides/native/) |
|
||||
| 原生二進位檔案 | 偽程式碼、組合語言、字串、符號、呼叫和引用 | Hopper、Ghidra 或 IDA;[原生分析](https://rea.tools/zh-TW/guides/native/) |
|
||||
| 離線 ELF 佈局 | 節、段、原始符號/重定位資訊及靜態防護機制候選項 | Linux x64 上由呼叫方提供的 pwntools;[二進位診斷](docs/binary-diagnostics.md) |
|
||||
| EVM 位元組碼 | 分派選擇器、位元組偏移、推斷的參數和狀態可變性 | Linux x64 上的本地原始位元組/十六進位輸入載體;[離線 EVM 指南](docs/evm-bytecode.md) |
|
||||
| 已記錄的 Linux 崩潰 | 原始 note 記錄、每個已記錄執行緒的暫存器/訊號及可選的對映候選項 | Linux x64 上由呼叫方提供的 pwntools;可選的 GDB/pwndbg;[已記錄崩潰](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | 模組、匯入、source map、路由、IPC 和原生附加元件關係 | Node.js 和 npm;[應用分析](https://rea.tools/guides/javascript/) |
|
||||
| 網站 | 頁面結構、腳本、網路觀察結果和按請求獲取的螢幕擷取畫面 | Chrome 系瀏覽器;[瀏覽器分析](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | 模組、匯入、source map、路由、IPC 和原生附加元件關係 | Node.js 和 npm;[應用分析](https://rea.tools/zh-TW/guides/javascript/) |
|
||||
| 網站 | 頁面結構、腳本、網路觀察結果和按請求獲取的螢幕擷取畫面 | Chrome 系瀏覽器;[瀏覽器分析](https://rea.tools/zh-TW/guides/browser/) |
|
||||
| 已保存的網路擷取 | 請求、回應、可訪問的酬載和來源位置 | HAR;原生 mitmproxy 擷取需要 Linux 上的 mitmdump;[擷取指南](docs/web-network-captures.md) |
|
||||
| .NET 程式集 | 中繼資料、CIL 指令、聲明的原生依賴和建置對比 | 靜態檢查;[托管程式碼指南](docs/managed-code-analysis.md) |
|
||||
| Android APK | 清單聲明、類別、反編譯的方法和引用 | Linux/macOS/Windows x64 上的無界面 JADX 和完整 JDK;[Android 指南](docs/android-analysis.md) |
|
||||
|
|
@ -157,26 +157,26 @@ REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。
|
|||
|
||||
## 案例
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/zh-TW/showcase/)
|
||||
|
||||
### DX-Ball:重建聲像計算
|
||||
|
||||
沿聲音呼叫追蹤到根據位置計算聲像的輔助函數,檢查指令,將不完整的偽程式碼轉為 C。重建結果通過了 3,205 個原始 x86 測試用例,並復現了編譯後函數的全部 63 個位元組。
|
||||
|
||||
[閱讀案例](https://rea.tools/showcase/dx-ball/) ·
|
||||
[閱讀案例](https://rea.tools/zh-TW/showcase/dx-ball/) ·
|
||||
[重建專案儲存庫](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion:追蹤 Electron 剪貼簿橋
|
||||
|
||||
找到渲染處理程序的剪貼簿 API,沿 preload 和 IPC 追蹤到主處理程序,並檢查富格式剪貼簿資料。
|
||||
|
||||
[閱讀案例](https://rea.tools/showcase/notion/)
|
||||
[閱讀案例](https://rea.tools/zh-TW/showcase/notion/)
|
||||
|
||||
### TH04:恢復 DOS 環形子彈的計算
|
||||
|
||||
檢查原始 PC-98 遊戲的 16 位指令,恢復固定角度和瞄準角度的計算,並將重建的 C++ 與當年的編譯器輸出進行對比。
|
||||
|
||||
[閱讀案例](https://rea.tools/showcase/th04/) ·
|
||||
[閱讀案例](https://rea.tools/zh-TW/showcase/th04/) ·
|
||||
[重建專案儲存庫](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
如果你用 REA 分析了有趣的目標,我們很想瞭解。歡迎通過 [issue](https://github.com/morluto/rea/issues) 或 [pull request](https://github.com/morluto/rea/pulls) 分享案例,說明目標、你的問題、REA 如何提供幫助,以及你的發現。
|
||||
|
|
@ -248,7 +248,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## 文件
|
||||
|
||||
可以先閱讀網站上的[實操指南](https://rea.tools/guides/)。具體選項、前提條件和結果契約見:
|
||||
可以先閱讀網站上的[實操指南](https://rea.tools/zh-TW/guides/)。具體選項、前提條件和結果契約見:
|
||||
|
||||
- [安裝與設定](docs/installation.md):AI 代理註冊、提供者組態、更新和卸載。
|
||||
- [就緒檢查與故障排查](docs/installation.md#check-readiness-for-your-task):診斷特定 AI 代理或分析引擎。
|
||||
|
|
|
|||
20
README_zh.md
20
README_zh.md
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[网站](https://rea.tools/) · [指南](https://rea.tools/guides/) · [案例](https://rea.tools/showcase/)**
|
||||
**[网站](https://rea.tools/zh-CN/) · [指南](https://rea.tools/zh-CN/guides/) · [案例](https://rea.tools/zh-CN/showcase/)**
|
||||
|
||||
[快速开始](#快速开始) · [REA 的工作原理](#rea-的工作原理) · [可以分析什么](#可以分析什么) · [案例](#案例) · [常见问题](#常见问题) · [文档](#文档)
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ REA 将智能体连接到分析工具,用于检查原生二进制文件、Java
|
|||
|
||||
设置流程会向智能体注册 REA,并安装匹配的工作流指引。原生分析可以使用已有的 Hopper 或 Ghidra;设置流程也可以在你批准后安装 Hopper。静态 JavaScript 分析不需要这两个引擎。
|
||||
|
||||
> **[访问 REA 网站](https://rea.tools/)**,查看设置说明、图解指南和真实案例。
|
||||
> **[访问 REA 网站](https://rea.tools/zh-CN/)**,查看设置说明、图解指南和真实案例。
|
||||
|
||||
## 快速开始
|
||||
|
||||
|
|
@ -133,12 +133,12 @@ REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。
|
|||
|
||||
| 目标 | REA 返回的内容 | 要求与指南 |
|
||||
| --------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| 原生二进制文件 | 伪代码、汇编、字符串、符号、调用和引用 | Hopper、Ghidra 或 IDA;[原生分析](https://rea.tools/guides/native/) |
|
||||
| 原生二进制文件 | 伪代码、汇编、字符串、符号、调用和引用 | Hopper、Ghidra 或 IDA;[原生分析](https://rea.tools/zh-CN/guides/native/) |
|
||||
| 离线 ELF 布局 | 节、段、原始符号/重定位信息及静态防护机制候选项 | Linux x64 上由调用方提供的 pwntools;[二进制诊断](docs/binary-diagnostics.md) |
|
||||
| EVM 字节码 | 分派选择器、字节偏移、推断的参数和状态可变性 | Linux x64 上的本地原始字节/十六进制输入载体;[离线 EVM 指南](docs/evm-bytecode.md) |
|
||||
| 已记录的 Linux 崩溃 | 原始 note 记录、每个已记录线程的寄存器/信号及可选的映射候选项 | Linux x64 上由调用方提供的 pwntools;可选的 GDB/pwndbg;[已记录崩溃](docs/recorded-crashes.md) |
|
||||
| JavaScript / Electron | 模块、导入、source map、路由、IPC 和原生扩展关系 | Node.js 和 npm;[应用分析](https://rea.tools/guides/javascript/) |
|
||||
| 网站 | 页面结构、脚本、网络观察结果和按请求获取的截图 | Chrome 系浏览器;[浏览器分析](https://rea.tools/guides/browser/) |
|
||||
| JavaScript / Electron | 模块、导入、source map、路由、IPC 和原生扩展关系 | Node.js 和 npm;[应用分析](https://rea.tools/zh-CN/guides/javascript/) |
|
||||
| 网站 | 页面结构、脚本、网络观察结果和按请求获取的截图 | Chrome 系浏览器;[浏览器分析](https://rea.tools/zh-CN/guides/browser/) |
|
||||
| 已保存的网络捕获 | 请求、响应、可访问的载荷和来源位置 | HAR;原生 mitmproxy 捕获需要 Linux 上的 mitmdump;[捕获指南](docs/web-network-captures.md) |
|
||||
| .NET 程序集 | 元数据、CIL 指令、声明的原生依赖和构建对比 | 静态检查;[托管代码指南](docs/managed-code-analysis.md) |
|
||||
| Android APK | 清单声明、类、反编译的方法和引用 | Linux/macOS/Windows x64 上的无界面 JADX 和完整 JDK;[Android 指南](docs/android-analysis.md) |
|
||||
|
|
@ -157,26 +157,26 @@ REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。
|
|||
|
||||
## 案例
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
[](https://rea.tools/zh-CN/showcase/)
|
||||
|
||||
### DX-Ball:重建声像计算
|
||||
|
||||
沿声音调用追踪到根据位置计算声像的辅助函数,检查指令,将不完整的伪代码转为 C。重建结果通过了 3,205 个原始 x86 测试用例,并复现了编译后函数的全部 63 个字节。
|
||||
|
||||
[阅读案例](https://rea.tools/showcase/dx-ball/) ·
|
||||
[阅读案例](https://rea.tools/zh-CN/showcase/dx-ball/) ·
|
||||
[重建项目仓库](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion:追踪 Electron 剪贴板桥
|
||||
|
||||
找到渲染进程的剪贴板 API,沿 preload 和 IPC 追踪到主进程,并检查富格式剪贴板数据。
|
||||
|
||||
[阅读案例](https://rea.tools/showcase/notion/)
|
||||
[阅读案例](https://rea.tools/zh-CN/showcase/notion/)
|
||||
|
||||
### TH04:恢复 DOS 环形子弹的计算
|
||||
|
||||
检查原始 PC-98 游戏的 16 位指令,恢复固定角度和瞄准角度的计算,并将重建的 C++ 与当年的编译器输出进行对比。
|
||||
|
||||
[阅读案例](https://rea.tools/showcase/th04/) ·
|
||||
[阅读案例](https://rea.tools/zh-CN/showcase/th04/) ·
|
||||
[重建项目仓库](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
如果你用 REA 分析了有趣的目标,我们很想了解。欢迎通过 [issue](https://github.com/morluto/rea/issues) 或 [pull request](https://github.com/morluto/rea/pulls) 分享案例,说明目标、你的问题、REA 如何提供帮助,以及你的发现。
|
||||
|
|
@ -248,7 +248,7 @@ npx rea-agents@latest setup
|
|||
|
||||
## 文档
|
||||
|
||||
可以先阅读网站上的[实操指南](https://rea.tools/guides/)。具体选项、前提条件和结果契约见:
|
||||
可以先阅读网站上的[实操指南](https://rea.tools/zh-CN/guides/)。具体选项、前提条件和结果契约见:
|
||||
|
||||
- [安装与设置](docs/installation.md):智能体注册、提供方配置、更新和卸载。
|
||||
- [就绪检查与故障排查](docs/installation.md#check-readiness-for-your-task):诊断特定智能体或分析引擎。
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ if (
|
|||
file.startsWith("docs/")
|
||||
) {
|
||||
selected.docs = true;
|
||||
selected.website ||= matchesAny(file, SCOPES.website);
|
||||
continue;
|
||||
}
|
||||
if (/^(src|tests)\/.*\.(?:test|spec)\.[cm]?[jt]sx?$/.test(file)) {
|
||||
|
|
|
|||
|
|
@ -222,6 +222,8 @@ export const SCOPES = {
|
|||
website: [
|
||||
"website/**",
|
||||
"scripts/*website*.py",
|
||||
"README*.md",
|
||||
".github/workflows/website-check.yml",
|
||||
".github/workflows/website-pages.yml",
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -76,9 +76,14 @@ def prepare_notes_example(site):
|
|||
print(f"Prepared examples/notes-example.zip ({len(EXAMPLE_FILES)} files).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
site = root / "website/public"
|
||||
def prepare_assets(site):
|
||||
"""Finish the shared publish artifact before it replaces the current preview."""
|
||||
prepare_sharing_image(site)
|
||||
prepare_sitemap(site)
|
||||
prepare_notes_example(site)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
from website_i18n import build_translations
|
||||
build_translations(root, root / "website/_site", finalize=prepare_assets)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import contextlib
|
||||
import importlib.util
|
||||
import io
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import tempfile
|
||||
|
|
@ -13,6 +14,9 @@ from urllib.error import HTTPError
|
|||
from urllib.request import urlopen
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import polib
|
||||
from website_i18n import Document, build_translations, checked_catalog, extract_catalogs, languages, reading_pages, read_runtime
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
|
@ -113,7 +117,7 @@ class WebsiteSearchChecks(unittest.TestCase):
|
|||
for name, old, new, message in cases:
|
||||
with self.subTest(name=name), tempfile.TemporaryDirectory() as directory:
|
||||
site = Path(directory) / "public"
|
||||
shutil.copytree(ROOT / "website/public", site)
|
||||
shutil.copytree(ROOT / "website/_site", site)
|
||||
path = site / name
|
||||
source = path.read_text()
|
||||
self.assertIn(old, source)
|
||||
|
|
@ -123,7 +127,7 @@ class WebsiteSearchChecks(unittest.TestCase):
|
|||
)
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
site = Path(directory) / "public"
|
||||
shutil.copytree(ROOT / "website/public", site)
|
||||
shutil.copytree(ROOT / "website/_site", site)
|
||||
(site / "assets/social-card.png").unlink()
|
||||
self.assertIn(
|
||||
"Social preview PNG is missing; run scripts/prepare-website.py",
|
||||
|
|
@ -162,6 +166,9 @@ class WebsiteMaintenanceChecks(unittest.TestCase):
|
|||
for name in ("public", "templates"):
|
||||
shutil.copytree(ROOT / "website" / name, root / "website" / name)
|
||||
site = root / "website/public"
|
||||
WEBSITE.sync_pages(root)
|
||||
shutil.copyfile(ROOT / "website/_site/assets/social-card.png", site / "assets/social-card.png")
|
||||
PREPARE.prepare_notes_example(site)
|
||||
page = WEBSITE.new_page(root, "blog/new-example", 'A <test> & "result"', 'Check "quotes" & <markup>.')
|
||||
source = page.read_text()
|
||||
self.assertIn('href="../../blog/" aria-current="page"', source)
|
||||
|
|
@ -182,7 +189,7 @@ class WebsiteMaintenanceChecks(unittest.TestCase):
|
|||
def test_links_in_prompts_fragments_and_copy_controls_are_verified(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
site = Path(directory) / "public"
|
||||
shutil.copytree(ROOT / "website/public", site)
|
||||
shutil.copytree(ROOT / "website/_site", site)
|
||||
page = site / "faq/index.html"
|
||||
original = page.read_text()
|
||||
cases = (
|
||||
|
|
@ -242,5 +249,158 @@ class WebsiteMaintenanceChecks(unittest.TestCase):
|
|||
worker.join()
|
||||
|
||||
|
||||
class WebsiteTranslationChecks(unittest.TestCase):
|
||||
"""Exercise source edits, translated evidence and language editions at their consumers."""
|
||||
|
||||
@contextlib.contextmanager
|
||||
def translated_project(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
for name in ("public", "templates", "locales"):
|
||||
shutil.copytree(ROOT / "website" / name, root / "website" / name)
|
||||
inventory = [item for item in languages(ROOT) if item["code"] in {"en", "zh-CN", "ar"}]
|
||||
(root / "website/locales/languages.json").write_text(json.dumps(inventory))
|
||||
for item in inventory:
|
||||
(root / item["readme"]).write_text("# REA\n")
|
||||
WEBSITE.sync_pages(root)
|
||||
extract_catalogs(root)
|
||||
yield root
|
||||
|
||||
def test_source_change_preserves_review_and_excludes_stale_translation_from_search(self):
|
||||
with self.translated_project() as root:
|
||||
path = root / "website/locales/zh-CN/messages.po"
|
||||
catalog = polib.pofile(path)
|
||||
old = catalog.find("How do I install REA?", msgctxt="page:faq/index.html")
|
||||
old.tcomment = "Reviewed installation wording."
|
||||
old_translation = old.msgstr
|
||||
catalog.save(path)
|
||||
page = root / "website/public/faq/index.html"
|
||||
page.write_text(page.read_text().replace("How do I install REA?", "How do I install REA today?"))
|
||||
with self.assertRaisesRegex(ValueError, "Translation sources changed"):
|
||||
extract_catalogs(root, check=True)
|
||||
extract_catalogs(root)
|
||||
updated = polib.pofile(path)
|
||||
archived = next(entry for entry in updated if entry.obsolete and entry.msgid == old.msgid)
|
||||
self.assertEqual((archived.msgstr, archived.tcomment), (old_translation, old.tcomment))
|
||||
new = updated.find("How do I install REA today?", msgctxt=old.msgctxt)
|
||||
self.assertEqual(new.msgstr, "")
|
||||
build_translations(root, root / "website/_site")
|
||||
site = root / "website/_site"
|
||||
PREPARE.prepare_sitemap(site)
|
||||
fallback = VERIFY.HtmlReferences()
|
||||
fallback.feed((site / "zh-CN/faq/index.html").read_text())
|
||||
self.assertTrue(fallback.translation_fallback)
|
||||
self.assertTrue(fallback.noindex())
|
||||
self.assertEqual(fallback.lang, "en")
|
||||
self.assertNotIn("https://rea.tools/zh-CN/faq/", (site / "sitemap.xml").read_text())
|
||||
self.assertNotIn('hreflang="zh-CN"', (site / "faq/index.html").read_text())
|
||||
new.msgstr = "现在如何安装 REA?"
|
||||
new.flags.append("fuzzy")
|
||||
updated.save(path)
|
||||
build_translations(root, site)
|
||||
self.assertIn('data-translation-fallback="true"', (site / "zh-CN/faq/index.html").read_text())
|
||||
new.flags.remove("fuzzy")
|
||||
updated.save(path)
|
||||
build_translations(root, site)
|
||||
PREPARE.prepare_sitemap(site)
|
||||
result = (site / "zh-CN/faq/index.html").read_text()
|
||||
self.assertIn("现在如何安装 REA?", result)
|
||||
self.assertNotIn("data-translation-fallback", result)
|
||||
self.assertIn('href="../assets/styles.css"', (site / "zh-CN/index.html").read_text())
|
||||
self.assertIn('hreflang="zh-CN"', (site / "faq/index.html").read_text())
|
||||
self.assertIn("https://rea.tools/zh-CN/faq/", (site / "sitemap.xml").read_text())
|
||||
|
||||
def test_broken_placeholders_and_inline_markup_fail_before_replacing_preview(self):
|
||||
with self.translated_project() as root:
|
||||
site = root / "website/_site"
|
||||
build_translations(root, site)
|
||||
before = (site / "zh-CN/index.html").read_bytes()
|
||||
path = root / "website/locales/zh-CN/messages.po"
|
||||
catalog = polib.pofile(path)
|
||||
entry = catalog.find("Already know RE? {ph0}Skip to analysis guides →{ph1}", msgctxt="page:index.html")
|
||||
original = entry.msgstr
|
||||
for bad, reason in (("丢失链接", "changed placeholders"), ("{ph1}错误的链接{ph0}", "invalid inline markup")):
|
||||
with self.subTest(reason=reason):
|
||||
entry.msgstr = bad
|
||||
catalog.save(path)
|
||||
with self.assertRaisesRegex(ValueError, reason):
|
||||
build_translations(root, site)
|
||||
self.assertEqual((site / "zh-CN/index.html").read_bytes(), before)
|
||||
entry.msgstr = original
|
||||
catalog.save(path)
|
||||
(root / "website/locales/languages.json").unlink()
|
||||
with self.assertRaisesRegex(ValueError, "Missing languages.json"):
|
||||
build_translations(root, site)
|
||||
self.assertEqual((site / "zh-CN/index.html").read_bytes(), before)
|
||||
|
||||
def test_runtime_message_drift_and_page_specific_completeness(self):
|
||||
with self.translated_project() as root:
|
||||
script = root / "website/public/assets/dino-demo.js"
|
||||
original = script.read_text()
|
||||
script.write_text(original.replace('t("Pause")', 't("Pause game")'))
|
||||
self.assertIn("Pause game", read_runtime(root))
|
||||
with self.assertRaisesRegex(ValueError, "Translation sources changed"):
|
||||
extract_catalogs(root, check=True)
|
||||
script.write_text(original.replace('t("Pause")', 't(dynamicMessage)'))
|
||||
with self.assertRaisesRegex(ValueError, "one literal message"):
|
||||
read_runtime(root)
|
||||
script.write_text(original)
|
||||
path = root / "website/locales/zh-CN/messages.po"
|
||||
catalog = polib.pofile(path)
|
||||
catalog.find("Pause", msgctxt="runtime").msgstr = ""
|
||||
catalog.save(path)
|
||||
site = root / "website/_site"
|
||||
build_translations(root, site)
|
||||
self.assertIn('data-translation-fallback="true"', (site / "zh-CN/examples/dino-lab/index.html").read_text())
|
||||
self.assertNotIn('data-translation-fallback="true"', (site / "zh-CN/faq/index.html").read_text())
|
||||
|
||||
def test_all_readme_editions_preserve_code_targets_downloads_and_reciprocal_routes(self):
|
||||
site = ROOT / "website/_site"
|
||||
english_pages = reading_pages(ROOT / "website/public")
|
||||
for language in languages(ROOT):
|
||||
code = language["code"]
|
||||
for original in english_pages:
|
||||
relative = original.relative_to(ROOT / "website/public")
|
||||
path = site / relative if code == "en" else site / code / relative
|
||||
with self.subTest(language=code, page=str(relative)):
|
||||
source = original.read_text()
|
||||
translated = path.read_text()
|
||||
def evidence(html):
|
||||
doc = Document(html)
|
||||
return sorted(doc.source[node.start:node.end] for node in doc.nodes if node.tag in {"pre", "code", "kbd"} or node.attrs.get("translate") == "no")
|
||||
self.assertEqual(evidence(source), evidence(translated))
|
||||
parser = VERIFY.HtmlReferences()
|
||||
parser.feed(translated)
|
||||
self.assertEqual(parser.lang, "en" if parser.translation_fallback else code)
|
||||
if code != "en" and not parser.translation_fallback:
|
||||
self.assertEqual(parser.direction, language["dir"])
|
||||
if parser.translation_fallback:
|
||||
self.assertTrue(parser.noindex())
|
||||
self.assertNotIn(code, parser.alternates)
|
||||
else:
|
||||
self.assertEqual(parser.alternates[code], WEBSITE.page_url(site, path))
|
||||
english = VERIFY.HtmlReferences()
|
||||
english.feed((site / relative).read_text())
|
||||
self.assertEqual(parser.alternates, english.alternates)
|
||||
self.assertTrue(set(parser.copy_targets) <= parser.ids)
|
||||
for fixture in WEBSITE.NOTES_FIXTURES:
|
||||
self.assertEqual((site / fixture).read_bytes(), (ROOT / "website/public" / fixture).read_bytes())
|
||||
with ThreadingHTTPServer(("127.0.0.1", 0), WEBSITE.preview_handler(site, "/rea/")) as server:
|
||||
worker = Thread(target=server.serve_forever, daemon=True)
|
||||
worker.start()
|
||||
try:
|
||||
base = f"http://127.0.0.1:{server.server_port}/rea/"
|
||||
with urlopen(base + "ar/faq?test=1") as response:
|
||||
self.assertEqual(response.url, base + "ar/faq/?test=1")
|
||||
self.assertIn(b'lang="ar"', response.read())
|
||||
with urlopen(base + "assets/i18n.js") as response:
|
||||
self.assertIn(b"export function t", response.read())
|
||||
with urlopen(base + "examples/notes-example.zip") as response:
|
||||
self.assertEqual(response.read(), (site / "examples/notes-example.zip").read_bytes())
|
||||
finally:
|
||||
server.shutdown()
|
||||
worker.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ class HtmlReferences(HTMLParser):
|
|||
self.properties = {}
|
||||
self.canonicals = []
|
||||
self.lang = None
|
||||
self.direction = None
|
||||
self.translation_fallback = False
|
||||
self.alternates = {}
|
||||
self.h1_count = 0
|
||||
self.text = []
|
||||
self.copy_targets = []
|
||||
|
|
@ -103,11 +106,18 @@ class HtmlReferences(HTMLParser):
|
|||
attributes = dict(attrs)
|
||||
if tag == "html":
|
||||
self.lang = attributes.get("lang")
|
||||
self.direction = attributes.get("dir")
|
||||
self.translation_fallback = attributes.get("data-translation-fallback") == "true"
|
||||
if tag == "h1":
|
||||
self.h1_count += 1
|
||||
if tag == "head":
|
||||
self.in_head = True
|
||||
if self.in_head:
|
||||
if tag == "link" and attributes.get("rel") == "alternate" and attributes.get("hreflang"):
|
||||
language = attributes["hreflang"]
|
||||
if language in self.alternates:
|
||||
self.duplicate_ids.append("hreflang:" + language)
|
||||
self.alternates[language] = attributes.get("href") or ""
|
||||
if tag == "title":
|
||||
self.titles.append("")
|
||||
self.in_title = True
|
||||
|
|
@ -167,8 +177,17 @@ def check_search_metadata(site, pages):
|
|||
title = page.titles[0].strip() if len(page.titles) == 1 else ""
|
||||
if not title:
|
||||
errors.append(f"{label}: needs exactly one nonempty head title")
|
||||
if page.lang != "en" or page.h1_count != 1:
|
||||
errors.append(f"{label}: needs lang=en and exactly one h1")
|
||||
first = path.relative_to(site).parts[0]
|
||||
expected_language = first if re.fullmatch(r"[a-z]{2}(?:-[A-Z]{2})?", first) else "en"
|
||||
if page.translation_fallback:
|
||||
if page.lang != "en" or not page.noindex():
|
||||
errors.append(f"{label}: English translation fallback needs lang=en and noindex")
|
||||
elif page.lang != expected_language:
|
||||
errors.append(f"{label}: needs lang={expected_language} and exactly one h1")
|
||||
if page.h1_count != 1:
|
||||
errors.append(f"{label}: needs exactly one h1")
|
||||
if expected_language in ("ar", "fa") and not page.translation_fallback and page.direction != "rtl":
|
||||
errors.append(f"{label}: needs dir=rtl")
|
||||
if label in NOTES_FIXTURES and not page.noindex():
|
||||
errors.append(
|
||||
f"{label}: example application must have a head noindex directive"
|
||||
|
|
@ -179,9 +198,10 @@ def check_search_metadata(site, pages):
|
|||
indexable.add(url)
|
||||
if page.canonicals != [url]:
|
||||
errors.append(f"{label}: needs exactly one head canonical for {url}")
|
||||
if title in titles:
|
||||
title_identity = (page.lang, title)
|
||||
if title_identity in titles:
|
||||
errors.append(f"{label}: duplicate search title {title!r}")
|
||||
titles.add(title)
|
||||
titles.add(title_identity)
|
||||
descriptions = page.meta.get("description", [])
|
||||
description = descriptions[0].strip() if len(descriptions) == 1 else ""
|
||||
if not description:
|
||||
|
|
@ -219,6 +239,22 @@ def check_search_metadata(site, pages):
|
|||
values = collection.get(key, [])
|
||||
if len(values) != 1 or not values[0].strip():
|
||||
errors.append(f"{label}: needs exactly one nonempty {key}")
|
||||
if page.alternates:
|
||||
if page.alternates.get(page.lang) != url:
|
||||
errors.append(f"{label}: hreflang must include its own canonical")
|
||||
for language, target in page.alternates.items():
|
||||
parsed = urlsplit(target)
|
||||
if parsed.scheme != "https" or parsed.netloc != "rea.tools":
|
||||
errors.append(f"{label}: hreflang needs absolute rea.tools URLs")
|
||||
continue
|
||||
target_path = (site / unquote(parsed.path).lstrip("/")).resolve()
|
||||
if target_path.is_dir():
|
||||
target_path /= "index.html"
|
||||
other = pages.get(target_path)
|
||||
if other is None or other.noindex() or other.alternates != page.alternates:
|
||||
errors.append(f"{label}: nonreciprocal or nonindexable hreflang: {target}")
|
||||
elif language != "x-default" and other.lang != language:
|
||||
errors.append(f"{label}: hreflang={language} points to lang={other.lang}")
|
||||
|
||||
sitemap_path = site / "sitemap.xml"
|
||||
try:
|
||||
|
|
@ -290,7 +326,7 @@ def check_site(site):
|
|||
parser.feed(path.read_text(encoding="utf-8"))
|
||||
pages[path] = parser
|
||||
if site / "index.html" not in pages:
|
||||
errors.append("website/public/index.html is missing")
|
||||
errors.append(f"{site}/index.html is missing; run scripts/prepare-website.py")
|
||||
|
||||
for path, page in pages.items():
|
||||
label = path.relative_to(site)
|
||||
|
|
@ -400,8 +436,8 @@ def check_example_archive(site):
|
|||
def main():
|
||||
"""Run the same checks locally, on website PRs and before publishing."""
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
pages, references, indexable, errors = check_site(root / "website/public")
|
||||
errors.extend(check_example_archive(root / "website/public"))
|
||||
pages, references, indexable, errors = check_site(root / "website/_site")
|
||||
errors.extend(check_example_archive(root / "website/_site"))
|
||||
errors.extend(check_publisher(root))
|
||||
errors.extend(check_repository_links(root))
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ def authored_markdown(root):
|
|||
path for path in sorted(site.rglob("*.md"))
|
||||
if not any(part.startswith(".") or part in ("node_modules", "__pycache__")
|
||||
for part in path.relative_to(site).parts)
|
||||
and "_site" not in path.relative_to(site).parts
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -111,6 +112,10 @@ def shared_blocks(root, path, source):
|
|||
"title": escape(metadata.titles[0].strip(), quote=True),
|
||||
"description": escape(metadata.descriptions[0].strip(), quote=True),
|
||||
}
|
||||
from website_i18n import language_markup
|
||||
selector, alternates = language_markup(root, path.relative_to(site).as_posix())
|
||||
values["language_picker"] = selector if not metadata.noindex else ""
|
||||
values["alternates"] = alternates if not metadata.noindex else ""
|
||||
templates = root / "website/templates"
|
||||
return {
|
||||
name: indent(Template((templates / f"{name}.html.tmpl").read_text(encoding="utf-8")).substitute(values), " ")
|
||||
|
|
@ -207,13 +212,29 @@ def main():
|
|||
create.add_argument("route")
|
||||
create.add_argument("--title", required=True)
|
||||
create.add_argument("--description", required=True)
|
||||
translations = commands.add_parser("translations", help="Maintain gettext catalogs")
|
||||
translations.add_argument("action", choices=("extract", "status", "check"))
|
||||
translations.add_argument("--language", help="Check one language, such as zh-CN")
|
||||
translations.add_argument("--strict", action="store_true", help="Fail on missing or fuzzy translations")
|
||||
serve = commands.add_parser("serve", help="Prepare and preview the static site")
|
||||
serve.add_argument("--port", type=int, default=4173)
|
||||
serve.add_argument("--base-path", choices=("/", "/rea/"), default="/")
|
||||
args = parser.parse_args()
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
try:
|
||||
if args.command == "new-page":
|
||||
if args.command == "translations":
|
||||
from website_i18n import checked_catalog, extract_catalogs, languages
|
||||
template = extract_catalogs(root, check=args.action != "extract")
|
||||
if args.action != "extract":
|
||||
inventory = languages(root)[1:]
|
||||
if args.language:
|
||||
inventory = [item for item in inventory if item["code"] == args.language]
|
||||
if not inventory:
|
||||
raise ValueError(f"Unknown translation language: {args.language}")
|
||||
for language in inventory:
|
||||
messages, missing = checked_catalog(root, language, template, strict=args.strict)
|
||||
print(f"{language['code']}: {len(messages)}/{len(template)} translated; {len(missing)} missing or fuzzy")
|
||||
elif args.command == "new-page":
|
||||
new_page(root, args.route, args.title, args.description)
|
||||
elif args.command == "sync":
|
||||
sync_pages(root, check=args.check)
|
||||
|
|
@ -228,7 +249,7 @@ def main():
|
|||
run_script(root, "prepare-website.py")
|
||||
prefix = args.base_path
|
||||
|
||||
handler = preview_handler(root / "website/public", prefix)
|
||||
handler = preview_handler(root / "website/_site", prefix)
|
||||
with ThreadingHTTPServer(("127.0.0.1", args.port), handler) as server:
|
||||
print(f"Preview: http://127.0.0.1:{server.server_port}{prefix}", flush=True)
|
||||
server.serve_forever()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,637 @@
|
|||
"""Extract gettext catalogs and render language editions of authored static HTML."""
|
||||
|
||||
from collections import Counter
|
||||
from html import escape, unescape
|
||||
from html.parser import HTMLParser
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
from string import Formatter
|
||||
from tempfile import TemporaryDirectory
|
||||
from urllib.parse import quote, unquote, urlsplit, urlunsplit
|
||||
|
||||
import polib
|
||||
|
||||
|
||||
VOID = {"area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"}
|
||||
INLINE = {"a", "abbr", "b", "bdi", "br", "cite", "code", "em", "i", "kbd", "mark", "s", "small", "span", "strong", "sub", "sup", "time", "u"}
|
||||
PROSE = {"a", "p", "h1", "h2", "h3", "h4", "h5", "h6", "li", "dt", "dd", "figcaption", "summary", "label", "button", "th", "td", "span", "strong", "small", "cite", "blockquote", "output"}
|
||||
PROTECTED = {"code", "kbd", "pre", "script", "style", "svg", "math"}
|
||||
ATTRIBUTES = {"alt", "aria-label", "aria-description", "title", "placeholder"}
|
||||
PLACEHOLDER = re.compile(r"\{([a-zA-Z][a-zA-Z0-9_]*)\}")
|
||||
LITERALS = {"REA", "Reverse Engineer Anything", "REA · Reverse Engineer Anything", "GitHub", "Discord", "FAQ", "MCP", "CLI", "CSV", "JSON", "HTML", "CSS", "JavaScript", "Electron", "Hopper", "Ghidra", "IDA", "Windows", "Linux", "macOS", "Notion", "DX-Ball", "TH04", "TH08", "TH095", "Aegis", "SHA-1", "HMAC", "Node.js", "npm", "npx", "DOS", "PC-98"}
|
||||
FALLBACK_NOTICE = "Translation is being updated. Read this page in English for now."
|
||||
|
||||
|
||||
def languages(root):
|
||||
"""Load the website language inventory and check it against README editions."""
|
||||
path = root / "website/locales/languages.json"
|
||||
if not path.exists():
|
||||
if any(root.glob("README_*.md")):
|
||||
raise ValueError("Missing languages.json for the translated README editions")
|
||||
return [{"code": "en", "name": "English", "readme": "README.md", "dir": "ltr"}]
|
||||
data = json.loads(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(data, list) or not data or not isinstance(data[0], dict) or data[0].get("code") != "en":
|
||||
raise ValueError("languages.json must start with English")
|
||||
codes, filenames = set(), set()
|
||||
for item in data:
|
||||
if not isinstance(item, dict) or set(item) != {"code", "name", "readme", "dir"}:
|
||||
raise ValueError("Each language needs code, name, readme and dir")
|
||||
if not all(isinstance(value, str) and value for value in item.values()):
|
||||
raise ValueError("Language fields must be nonempty strings")
|
||||
if not re.fullmatch(r"[a-z]{2}(?:-[A-Z]{2})?", item["code"]) or item["code"] in codes:
|
||||
raise ValueError(f"Invalid or duplicate language: {item['code']}")
|
||||
if item["dir"] not in ("ltr", "rtl"):
|
||||
raise ValueError(f"Invalid text direction: {item['code']}")
|
||||
if item["readme"] in filenames:
|
||||
raise ValueError(f"Duplicate README edition: {item['readme']}")
|
||||
codes.add(item["code"])
|
||||
filenames.add(item["readme"])
|
||||
readmes = {path.name for path in root.glob("README*.md")}
|
||||
if readmes and ({item["readme"] for item in data} != readmes):
|
||||
raise ValueError("Website languages must match the README language editions")
|
||||
return data
|
||||
|
||||
|
||||
def reading_pages(site):
|
||||
"""Discover authored reading pages, leaving target applications untouched."""
|
||||
from website import NOTES_FIXTURES, PageMetadata
|
||||
pages = []
|
||||
for path in sorted(site.rglob("*.html")):
|
||||
if path.relative_to(site).as_posix() in NOTES_FIXTURES:
|
||||
continue
|
||||
metadata = PageMetadata()
|
||||
metadata.feed(path.read_text(encoding="utf-8"))
|
||||
if not metadata.noindex:
|
||||
pages.append(path)
|
||||
return pages
|
||||
|
||||
|
||||
def localized_path(relative, code):
|
||||
"""Keep English's existing routes and prefix other editions with their language."""
|
||||
return Path(relative) if code == "en" else Path(code) / relative
|
||||
|
||||
|
||||
def language_markup(root, relative, code="en", available=None):
|
||||
"""Render a keyboard-accessible same-page selector and reciprocal hreflang links."""
|
||||
from website import SITE_ORIGIN, page_route
|
||||
inventory = languages(root)
|
||||
available = set(available) if available is not None else {item["code"] for item in inventory}
|
||||
current = next(item for item in inventory if item["code"] == code)
|
||||
route = page_route(Path("."), Path(".") / relative)
|
||||
depth = len(localized_path(relative, code).parent.parts)
|
||||
base = "../" * depth or "./"
|
||||
choices, alternates = [], []
|
||||
for item in inventory:
|
||||
target = ("" if item["code"] == "en" else item["code"] + "/") + route
|
||||
href = escape(base + target, quote=True)
|
||||
active = ' aria-current="true"' if item["code"] == code else ""
|
||||
fallback = " · English" if item["code"] not in available else ""
|
||||
choices.append(f'<a href="{href}" lang="{item["code"]}" dir="{item["dir"]}" data-language="{item["code"]}"{active}>{escape(item["name"])}{fallback}</a>')
|
||||
if item["code"] in available:
|
||||
alternates.append(f'<!-- prettier-ignore -->\n<link rel="alternate" hreflang="{item["code"]}" href="{SITE_ORIGIN}/{quote(target, safe="/")}" />')
|
||||
alternates.append(f'<!-- prettier-ignore -->\n<link rel="alternate" hreflang="x-default" href="{SITE_ORIGIN}/{quote(route, safe="/")}" />')
|
||||
selector = '<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>' + escape(current["name"]) + '</span></summary><nav aria-label="' + escape(current["name"], quote=True) + '">' + "".join(choices) + "</nav></details>"
|
||||
return selector, "\n".join(alternates)
|
||||
|
||||
|
||||
class Node:
|
||||
"""Keep exact source spans so translating prose cannot reserialize code blocks."""
|
||||
|
||||
def __init__(self, tag, attrs, start, open_end, line):
|
||||
self.tag, self.attrs, self.start, self.open_end = tag, dict(attrs), start, open_end
|
||||
self.end_start, self.end, self.line = open_end, open_end, line
|
||||
self.children = []
|
||||
self.parent = None
|
||||
|
||||
|
||||
class Document(HTMLParser):
|
||||
"""Parse structure while retaining original start tags, text and source positions."""
|
||||
|
||||
def __init__(self, source):
|
||||
super().__init__(convert_charrefs=False)
|
||||
self.source = source
|
||||
self.offsets = [0]
|
||||
for match in re.finditer("\n", source):
|
||||
self.offsets.append(match.end())
|
||||
self.root = Node("document", [], 0, 0, 1)
|
||||
self.root.end = self.root.end_start = len(source)
|
||||
self.stack, self.nodes = [self.root], []
|
||||
self.feed(source)
|
||||
self.close()
|
||||
if len(self.stack) != 1:
|
||||
raise ValueError(f"Unclosed HTML element: {self.stack[-1].tag}")
|
||||
|
||||
def position(self):
|
||||
line, column = self.getpos()
|
||||
return self.offsets[line - 1] + column
|
||||
|
||||
def handle_starttag(self, tag, attrs):
|
||||
start = self.position()
|
||||
node = Node(tag, attrs, start, start + len(self.get_starttag_text()), self.getpos()[0])
|
||||
node.parent = self.stack[-1]
|
||||
node.parent.children.append(node)
|
||||
self.nodes.append(node)
|
||||
if tag not in VOID:
|
||||
self.stack.append(node)
|
||||
|
||||
def handle_startendtag(self, tag, attrs):
|
||||
self.handle_starttag(tag, attrs)
|
||||
if tag not in VOID:
|
||||
self.stack.pop()
|
||||
|
||||
def handle_endtag(self, tag):
|
||||
if len(self.stack) < 2 or self.stack[-1].tag != tag:
|
||||
raise ValueError(f"Unbalanced HTML at line {self.getpos()[0]}: </{tag}>")
|
||||
node = self.stack.pop()
|
||||
node.end_start = self.position()
|
||||
node.end = self.source.index(">", node.end_start) + 1
|
||||
|
||||
def handle_data(self, data):
|
||||
self.stack[-1].children.append((self.position(), self.position() + len(data)))
|
||||
|
||||
def handle_entityref(self, name):
|
||||
self.handle_data("&" + name + ";")
|
||||
|
||||
def handle_charref(self, name):
|
||||
self.handle_data("&#" + name + ";")
|
||||
|
||||
|
||||
def skipped(node):
|
||||
"""Respect protected evidence and explicit exclusions throughout a subtree."""
|
||||
while node:
|
||||
if node.tag in PROTECTED or "data-i18n-skip" in node.attrs or node.attrs.get("translate") == "no":
|
||||
return True
|
||||
node = node.parent
|
||||
return False
|
||||
|
||||
|
||||
def translatable(text):
|
||||
"""Leave identifiers, product names and numeric evidence as literal source."""
|
||||
literal = re.fullmatch(r"0x[0-9a-fA-F]+|code\[\d+\]\s*=\s*\d+|× pan_scale", text)
|
||||
return bool(re.search(r"[a-zA-Z]", text)) and text not in LITERALS and not literal and not re.fullmatch(r"[\w./\\:-]+\.(?:exe|dll|js|json|html|asar|apk|zip|cpp|h|svg)", text, flags=re.IGNORECASE)
|
||||
|
||||
|
||||
def inline(node):
|
||||
return all(not isinstance(child, Node) or (child.tag in INLINE and inline(child)) for child in node.children)
|
||||
|
||||
|
||||
def unit_text(document, node):
|
||||
"""Represent inline markup and code as named placeholders in a complete sentence."""
|
||||
slots, parts = {}, []
|
||||
|
||||
def slot(value):
|
||||
key = f"ph{len(slots)}"
|
||||
slots[key] = value
|
||||
return "{" + key + "}"
|
||||
|
||||
def visit(child):
|
||||
if not isinstance(child, Node):
|
||||
parts.append(unescape(document.source[child[0]:child[1]]))
|
||||
elif child.tag in {"code", "kbd"} or "data-i18n-skip" in child.attrs or child.attrs.get("translate") == "no":
|
||||
parts.append(slot(document.source[child.start:child.end]))
|
||||
else:
|
||||
parts.append(slot(document.source[child.start:child.open_end]))
|
||||
for descendant in child.children:
|
||||
visit(descendant)
|
||||
if child.end > child.end_start:
|
||||
parts.append(slot(document.source[child.end_start:child.end]))
|
||||
for child in node.children:
|
||||
visit(child)
|
||||
return re.sub(r"\s+", " ", "".join(parts)).strip(), slots
|
||||
|
||||
|
||||
def prose_units(source, path):
|
||||
"""Extract paragraph-sized units, or individual orphan text when structure requires it."""
|
||||
document = Document(source)
|
||||
units = []
|
||||
|
||||
def context(start):
|
||||
for name in ("sharing", "header", "footer"):
|
||||
begin, end = source.find(f"<!-- website:{name}:start -->"), source.find(f"<!-- website:{name}:end -->")
|
||||
if begin >= 0 and begin < start < end:
|
||||
return "shared"
|
||||
return "page:" + path
|
||||
|
||||
def visit(node):
|
||||
if skipped(node) or node.tag in {"head", "document"}:
|
||||
if node.tag == "document":
|
||||
for child in node.children:
|
||||
if isinstance(child, Node):
|
||||
visit(child)
|
||||
return
|
||||
if node.tag in PROSE and inline(node) and node.children:
|
||||
text, slots = unit_text(document, node)
|
||||
if translatable(PLACEHOLDER.sub("", text).strip()):
|
||||
units.append((context(node.start), text, slots, node.open_end, node.end_start, node.line))
|
||||
return
|
||||
for child in node.children:
|
||||
if isinstance(child, Node):
|
||||
visit(child)
|
||||
else:
|
||||
raw = source[child[0]:child[1]]
|
||||
text = re.sub(r"\s+", " ", unescape(raw)).strip()
|
||||
if translatable(text):
|
||||
units.append((context(child[0]), text, {}, child[0], child[1], source.count("\n", 0, child[0]) + 1))
|
||||
visit(document.root)
|
||||
# The title is prose even though it lives in the head.
|
||||
for node in document.nodes:
|
||||
if node.tag == "title" and not skipped(node):
|
||||
text, slots = unit_text(document, node)
|
||||
if translatable(text):
|
||||
units.append(("page:" + path, text, slots, node.open_end, node.end_start, node.line))
|
||||
return units
|
||||
|
||||
|
||||
def attribute_units(source, path):
|
||||
"""Extract accessibility labels and authored metadata without translating URLs."""
|
||||
units = []
|
||||
document = Document(source)
|
||||
for node in document.nodes:
|
||||
if skipped(node):
|
||||
continue
|
||||
names = set(ATTRIBUTES)
|
||||
if node.tag == "meta" and (node.attrs.get("name") == "description" or node.attrs.get("property") == "og:image:alt" or node.attrs.get("name") == "twitter:image:alt"):
|
||||
names.add("content")
|
||||
for name in names:
|
||||
text = node.attrs.get(name)
|
||||
if text and translatable(text):
|
||||
context = "shared" if "<!-- website:header:start -->" in source[:node.start] and "<!-- website:header:end -->" not in source[:node.start] else "page:" + path
|
||||
if name == "content" and node.attrs.get("name") != "description":
|
||||
context = "shared"
|
||||
units.append((context, text, {}, node, name))
|
||||
return units
|
||||
|
||||
|
||||
def runtime_units(root):
|
||||
"""Extract the constrained t("literal", namedValues) authoring form directly."""
|
||||
yield "fallback", FALLBACK_NOTICE, "scripts/website_i18n.py", ""
|
||||
site = root / "website/public"
|
||||
for path in sorted((site / "assets").glob("*.js")):
|
||||
if path.name == "i18n.js": # Owns t itself, rather than reader-facing calls.
|
||||
continue
|
||||
source = path.read_text(encoding="utf-8")
|
||||
calls = list(re.finditer(r'\bt\(\s*("(?:[^"\\]|\\.)*")', source))
|
||||
if len(calls) != len(re.findall(r"\bt\(", source)):
|
||||
raise ValueError(f'{path.name}: use t("one literal message", namedValues)')
|
||||
script = path.relative_to(site).as_posix()
|
||||
for call in calls:
|
||||
yield script, json.loads(call[1]), "website/public/" + script, source.count("\n", 0, call.start()) + 1
|
||||
|
||||
|
||||
def read_runtime(root, page=None):
|
||||
"""Scope automatically extracted interaction messages to a page's scripts."""
|
||||
units = list(runtime_units(root))
|
||||
if page is None:
|
||||
return list(dict.fromkeys(text for _, text, _, _ in units))
|
||||
site = root / "website/public"
|
||||
scripts = set()
|
||||
for node in Document(page.read_text(encoding="utf-8")).nodes:
|
||||
if node.tag == "script" and node.attrs.get("src"):
|
||||
reference = urlsplit(node.attrs["src"])
|
||||
if not reference.scheme and not reference.netloc:
|
||||
scripts.add((page.parent / unquote(reference.path)).resolve().relative_to(site.resolve()).as_posix())
|
||||
return list(dict.fromkeys(text for script, text, _, _ in units if script in scripts))
|
||||
|
||||
|
||||
def source_catalog(root):
|
||||
"""Build a deterministic POT with source references and protected-placeholder notes."""
|
||||
site = root / "website/public"
|
||||
catalog = polib.POFile(wrapwidth=88)
|
||||
catalog.metadata = {"Project-Id-Version": "REA website", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit"}
|
||||
entries = {}
|
||||
|
||||
def add(context, text, slots, reference, line):
|
||||
key = context, text
|
||||
if key not in entries:
|
||||
entry = polib.POEntry(msgctxt=context, msgid=text, msgstr="", flags=["python-brace-format"] if PLACEHOLDER.search(text) else [])
|
||||
entry.comment = "\n".join(f"{{{key}}}: {re.sub(r'\s+', ' ', value)}" for key, value in slots.items())
|
||||
entries[key] = entry
|
||||
catalog.append(entry)
|
||||
occurrence = (reference, str(line))
|
||||
if occurrence not in entries[key].occurrences:
|
||||
entries[key].occurrences.append(occurrence)
|
||||
|
||||
for path in reading_pages(site):
|
||||
relative = path.relative_to(site).as_posix()
|
||||
source = path.read_text(encoding="utf-8")
|
||||
for context, text, slots, _, _, line in prose_units(source, relative):
|
||||
add(context, text, slots, "website/public/" + relative, line)
|
||||
for context, text, slots, node, _ in attribute_units(source, relative):
|
||||
add(context, text, slots, "website/public/" + relative, node.line)
|
||||
for _, text, reference, line in runtime_units(root):
|
||||
add("runtime", text, {}, reference, line)
|
||||
for path in sorted((site / "assets/figures").glob("*.svg")):
|
||||
source = path.read_text(encoding="utf-8")
|
||||
for node in Document(source).nodes:
|
||||
if node.tag in {"text", "title", "desc"} and not any(isinstance(child, Node) for child in node.children):
|
||||
text = unescape(source[node.open_end:node.end_start]).strip()
|
||||
if translatable(text):
|
||||
add("figure:" + path.name, text, {}, "website/public/assets/figures/" + path.name, node.line)
|
||||
return catalog
|
||||
|
||||
|
||||
def extract_catalogs(root, check=False):
|
||||
"""Refresh standard catalogs, preserving translations/comments and archiving removed text."""
|
||||
inventory = languages(root)
|
||||
template = source_catalog(root)
|
||||
directory = root / "website/locales"
|
||||
target = directory / "messages.pot"
|
||||
changed = []
|
||||
if not target.exists() or target.read_text(encoding="utf-8") != str(template):
|
||||
changed.append(target)
|
||||
if not check:
|
||||
template.save(target)
|
||||
expected = {(entry.msgctxt, entry.msgid) for entry in template}
|
||||
for language in inventory[1:]:
|
||||
path = directory / language["code"] / "messages.po"
|
||||
catalog = polib.pofile(path, encoding="utf-8") if path.exists() else polib.POFile(wrapwidth=88)
|
||||
active = {(entry.msgctxt, entry.msgid) for entry in catalog if not entry.obsolete}
|
||||
if active != expected:
|
||||
changed.append(path)
|
||||
if not check:
|
||||
catalog.merge(template)
|
||||
catalog.metadata.update(template.metadata)
|
||||
catalog.metadata["Language"] = language["code"]
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
catalog.save(path)
|
||||
if check and changed:
|
||||
raise ValueError("Translation sources changed: " + ", ".join(str(path.relative_to(root)) for path in changed[:8]) + ". Run python3 scripts/website.py translations extract, then update the affected msgstr entries.")
|
||||
print(f"{'Checked' if check else 'Extracted'} {len(template)} source messages for {len(inventory) - 1} translation catalogs.")
|
||||
return template
|
||||
|
||||
|
||||
def fields(text):
|
||||
"""Validate named format fields without accepting conversion or format instructions."""
|
||||
result = []
|
||||
for _, name, specification, conversion in Formatter().parse(text):
|
||||
if name is not None:
|
||||
if not re.fullmatch(r"[a-zA-Z][a-zA-Z0-9_]*", name) or specification or conversion:
|
||||
raise ValueError(f"Unsupported translation placeholder: {name}")
|
||||
result.append(name)
|
||||
return Counter(result)
|
||||
|
||||
|
||||
def checked_catalog(root, language, template, strict=False):
|
||||
"""Reject malformed catalogs and report missing or fuzzy messages independently."""
|
||||
path = root / "website/locales" / language["code"] / "messages.po"
|
||||
catalog = polib.pofile(path, encoding="utf-8", check_for_duplicates=True)
|
||||
if catalog.metadata.get("Language") != language["code"]:
|
||||
raise ValueError(f"{path}: wrong Language header")
|
||||
messages, missing = {}, []
|
||||
source = {(entry.msgctxt, entry.msgid): entry for entry in template}
|
||||
for entry in catalog:
|
||||
if entry.obsolete:
|
||||
continue
|
||||
key = entry.msgctxt, entry.msgid
|
||||
if key not in source:
|
||||
raise ValueError(f"{path}: obsolete source still active: {entry.msgid[:80]}")
|
||||
if entry.msgid_plural or entry.msgstr_plural:
|
||||
raise ValueError(f"{path}: use the declared named-count messages, not undeclared plural forms")
|
||||
if not entry.msgstr.strip() or "fuzzy" in entry.flags:
|
||||
missing.append(key)
|
||||
continue
|
||||
if fields(entry.msgid) != fields(entry.msgstr):
|
||||
raise ValueError(f"{path}: translation changed placeholders: {entry.msgid[:100]}")
|
||||
slots = dict(re.findall(r"^\{(ph\d+)\}: (.*)$", source[key].comment, re.MULTILINE))
|
||||
if slots:
|
||||
fragment = escape(entry.msgstr, quote=False)
|
||||
for name, value in slots.items():
|
||||
fragment = fragment.replace("{" + name + "}", value)
|
||||
try:
|
||||
Document("<div>" + fragment + "</div>")
|
||||
except ValueError as error:
|
||||
raise ValueError(f"{path}: {entry.msgctxt}: invalid inline markup in {entry.msgid[:100]!r}: {error}") from error
|
||||
messages[key] = entry.msgstr.strip()
|
||||
missing.extend(key for key in source if key not in messages and key not in missing)
|
||||
if strict and missing:
|
||||
raise ValueError(f"{path}: {len(missing)} untranslated/fuzzy messages; first: {missing[0][1][:100]}")
|
||||
return messages, missing
|
||||
|
||||
|
||||
def replace_attribute(raw, name, value):
|
||||
"""Change one parsed start-tag attribute without modifying adjacent markup."""
|
||||
pattern = re.compile(r"(\s" + re.escape(name) + r"\s*=\s*)([\"'])(.*?)\2", re.DOTALL | re.IGNORECASE)
|
||||
updated, count = pattern.subn(lambda match: match[1] + '"' + escape(value, quote=True) + '"', raw)
|
||||
if count != 1:
|
||||
raise ValueError(f"Expected one quoted {name} attribute: {raw[:100]}")
|
||||
return updated
|
||||
|
||||
|
||||
def apply_edits(source, edits):
|
||||
"""Apply non-overlapping spans from the end, preserving untouched evidence byte-for-byte."""
|
||||
end = len(source)
|
||||
for start, stop, replacement in sorted(edits, reverse=True):
|
||||
if stop > end:
|
||||
raise ValueError("Overlapping translation spans")
|
||||
source = source[:start] + replacement + source[stop:]
|
||||
end = start
|
||||
return source
|
||||
|
||||
|
||||
def render_prose(source, relative, messages):
|
||||
"""Translate complete units and restore validated original inline markup."""
|
||||
edits = []
|
||||
for context, text, slots, start, end, _ in prose_units(source, relative):
|
||||
translated = messages[(context, text)]
|
||||
if fields(text) != fields(translated):
|
||||
raise ValueError(f"{relative}: changed placeholders")
|
||||
rendered = escape(translated, quote=False)
|
||||
for key, value in slots.items():
|
||||
rendered = rendered.replace("{" + key + "}", value)
|
||||
# Check translator-reordered markup before accepting it into the document.
|
||||
try:
|
||||
Document("<div>" + rendered + "</div>")
|
||||
except ValueError as error:
|
||||
raise ValueError(f"{relative}: invalid translated markup in {text[:100]!r}: {error}") from error
|
||||
raw = source[start:end]
|
||||
leading = re.match(r"\s*", raw)[0]
|
||||
trailing = re.search(r"\s*$", raw)[0]
|
||||
edits.append((start, end, leading + rendered + trailing))
|
||||
return apply_edits(source, edits)
|
||||
|
||||
|
||||
def relative_reference(reference, source_path, output_path, site, available, code, figures, language_link=False):
|
||||
"""Resolve links once, keeping assets shared and reading links in the selected edition."""
|
||||
parsed = urlsplit(reference)
|
||||
if parsed.scheme or parsed.netloc or not parsed.path:
|
||||
return reference
|
||||
target = (source_path.parent / unquote(parsed.path)).resolve()
|
||||
if not target.is_relative_to(site.resolve()):
|
||||
raise ValueError(f"Reference leaves the website: {reference}")
|
||||
relative = target.relative_to(site.resolve())
|
||||
lookup = relative / "index.html" if target.is_dir() else relative
|
||||
if not language_link and lookup.as_posix() in available and code != "en":
|
||||
relative = Path(code) / relative
|
||||
if relative.as_posix() in figures and code != "en":
|
||||
relative = Path("assets/localized") / code / relative.relative_to("assets")
|
||||
destination = os.path.relpath(site / relative, output_path.parent).replace(os.sep, "/")
|
||||
if parsed.path.endswith("/") and not destination.endswith("/"):
|
||||
destination += "/"
|
||||
return urlunsplit(("", "", quote(destination, safe="/"), parsed.query, parsed.fragment))
|
||||
|
||||
|
||||
def replace_language_markup(source, root, relative, code, available):
|
||||
"""Derive selectors and alternates from the same page-level completeness decision."""
|
||||
selector, alternates = language_markup(root, relative, code, available)
|
||||
document = Document(source)
|
||||
picker = next(node for node in document.nodes if node.tag == "details" and node.attrs.get("class") == "language-picker")
|
||||
source = apply_edits(source, [(picker.start, picker.end, selector)])
|
||||
pattern = r"(<!-- website:languages:start -->).*?(<!-- website:languages:end -->)"
|
||||
return re.sub(pattern, lambda match: match[1] + "\n" + alternates + "\n" + match[2], source, flags=re.DOTALL)
|
||||
|
||||
|
||||
def render_page(root, source_path, language, messages, available, figures, page_languages):
|
||||
"""Create one complete translation, preserving routes, code, IDs and reference data."""
|
||||
from website import SITE_ORIGIN, PageMetadata, page_url
|
||||
site = root / "website/public"
|
||||
relative = source_path.relative_to(site).as_posix()
|
||||
code = language["code"]
|
||||
output_path = site / localized_path(relative, code)
|
||||
source = source_path.read_text(encoding="utf-8")
|
||||
source = render_prose(source, relative, messages)
|
||||
metadata = PageMetadata()
|
||||
# Translate attributes separately; units inside inline markup keep their source tags.
|
||||
replacements = {}
|
||||
for context, text, _, node, attribute in attribute_units(source, relative):
|
||||
raw = replacements.get(node.start, source[node.start:node.open_end])
|
||||
replacements[node.start] = replace_attribute(raw, attribute, messages[(context, text)])
|
||||
source = apply_edits(source, [(node.start, node.open_end, replacements[node.start]) for node in Document(source).nodes if node.start in replacements])
|
||||
metadata.feed(source)
|
||||
canonical = page_url(site, output_path)
|
||||
replacements = []
|
||||
for node in Document(source).nodes:
|
||||
raw = source[node.start:node.open_end]
|
||||
if node.tag == "html":
|
||||
raw = replace_attribute(raw, "lang", code)
|
||||
raw = raw[:-1] + f' dir="{language["dir"]}">'
|
||||
if node.tag == "meta":
|
||||
key = node.attrs.get("property") or node.attrs.get("name")
|
||||
if key in {"og:title", "twitter:title"}:
|
||||
raw = replace_attribute(raw, "content", metadata.titles[0])
|
||||
elif key in {"og:description", "twitter:description"}:
|
||||
raw = replace_attribute(raw, "content", metadata.descriptions[0])
|
||||
elif key == "og:url":
|
||||
raw = replace_attribute(raw, "content", canonical)
|
||||
for attribute in ("href", "src"):
|
||||
if attribute not in node.attrs:
|
||||
continue
|
||||
reference = node.attrs[attribute]
|
||||
if node.tag == "link" and node.attrs.get("rel") == "canonical":
|
||||
value = canonical
|
||||
else:
|
||||
value = relative_reference(reference, source_path, output_path, site, available, code, figures, "data-language" in node.attrs)
|
||||
raw = replace_attribute(raw, attribute, value)
|
||||
if raw != source[node.start:node.open_end]:
|
||||
replacements.append((node.start, node.open_end, raw))
|
||||
source = apply_edits(source, replacements)
|
||||
source = replace_language_markup(source, root, relative, code, page_languages)
|
||||
runtime = {text: messages[("runtime", text)] for text in read_runtime(root, source_path)}
|
||||
payload = json.dumps(runtime, ensure_ascii=False).replace("<", "\\u003c").replace("&", "\\u0026")
|
||||
source = source.replace("</head>", f'<script id="website-messages" type="application/json">{payload}</script>\n </head>')
|
||||
return source
|
||||
|
||||
|
||||
def required_messages(root, path, template):
|
||||
"""Bind a page to its prose, attributes, runtime labels and referenced figures."""
|
||||
site = root / "website/public"
|
||||
relative = path.relative_to(site).as_posix()
|
||||
source = path.read_text(encoding="utf-8")
|
||||
required = {(unit[0], unit[1]) for unit in prose_units(source, relative)}
|
||||
required.update((unit[0], unit[1]) for unit in attribute_units(source, relative))
|
||||
required.update(("runtime", text) for text in read_runtime(root, path))
|
||||
for node in Document(source).nodes:
|
||||
reference = node.attrs.get("src")
|
||||
if reference and not urlsplit(reference).scheme:
|
||||
target = (path.parent / unquote(urlsplit(reference).path)).resolve()
|
||||
if target.parent == (site / "assets/figures").resolve():
|
||||
required.update((entry.msgctxt, entry.msgid) for entry in template if entry.msgctxt == "figure:" + target.name)
|
||||
return required
|
||||
|
||||
|
||||
def render_fallback(root, path, language, page_languages, messages):
|
||||
"""Expose a clear English fallback instead of a stale or partially translated article."""
|
||||
from website import page_url
|
||||
site = root / "website/public"
|
||||
relative = path.relative_to(site).as_posix()
|
||||
code = language["code"]
|
||||
output_path = site / localized_path(relative, code)
|
||||
source = path.read_text(encoding="utf-8")
|
||||
edits = []
|
||||
canonical = page_url(site, output_path)
|
||||
for node in Document(source).nodes:
|
||||
raw = source[node.start:node.open_end]
|
||||
for attribute in ("href", "src"):
|
||||
if attribute in node.attrs:
|
||||
value = canonical if node.tag == "link" and node.attrs.get("rel") == "canonical" else relative_reference(node.attrs[attribute], path, output_path, site, set(), code, set(), "data-language" in node.attrs)
|
||||
raw = replace_attribute(raw, attribute, value)
|
||||
if node.tag == "meta" and node.attrs.get("property") == "og:url":
|
||||
raw = replace_attribute(raw, "content", canonical)
|
||||
if node.tag == "html":
|
||||
raw = raw[:-1] + ' data-translation-fallback="true">'
|
||||
if raw != source[node.start:node.open_end]:
|
||||
edits.append((node.start, node.open_end, raw))
|
||||
source = apply_edits(source, edits)
|
||||
source = source.replace("</head>", '<meta name="robots" content="noindex, follow" />\n </head>')
|
||||
source = replace_language_markup(source, root, relative, code, page_languages)
|
||||
notice = messages.get(("runtime", FALLBACK_NOTICE), FALLBACK_NOTICE)
|
||||
notice_lang = code if ("runtime", FALLBACK_NOTICE) in messages else "en"
|
||||
main = next(node for node in Document(source).nodes if node.tag == "main")
|
||||
source = source[:main.open_end] + f'<aside class="container translation-notice" lang="{notice_lang}" dir="{language["dir"]}">{escape(notice)}</aside>' + source[main.open_end:]
|
||||
return source
|
||||
|
||||
|
||||
def build_translations(root, destination, finalize=None):
|
||||
"""Build one clean publish directory from English sources and versioned PO catalogs."""
|
||||
site = root / "website/public"
|
||||
if destination.resolve() != (root / "website/_site").resolve():
|
||||
raise ValueError("Generated output must be website/_site")
|
||||
template = extract_catalogs(root, check=True)
|
||||
inventory = languages(root)
|
||||
pages = reading_pages(site)
|
||||
catalogs = {language["code"]: checked_catalog(root, language, template)[0] for language in inventory[1:]}
|
||||
required = {path.relative_to(site).as_posix(): required_messages(root, path, template) for path in pages}
|
||||
page_languages = {relative: {"en"} | {code for code, messages in catalogs.items() if keys <= messages.keys()} for relative, keys in required.items()}
|
||||
# Finish rendering before replacing the previous preview/publish artifact.
|
||||
with TemporaryDirectory(prefix=".i18n-", dir=root / "website") as directory:
|
||||
staging = Path(directory) / "site"
|
||||
shutil.copytree(site, staging, ignore=shutil.ignore_patterns("__pycache__"))
|
||||
for path in pages:
|
||||
relative = path.relative_to(site).as_posix()
|
||||
output = staging / relative
|
||||
output.write_text(replace_language_markup(path.read_text(encoding="utf-8"), root, relative, "en", page_languages[relative]), encoding="utf-8")
|
||||
for language in inventory[1:]:
|
||||
messages = catalogs[language["code"]]
|
||||
available = {relative for relative, codes in page_languages.items() if language["code"] in codes}
|
||||
figures = set()
|
||||
for path in sorted((site / "assets/figures").glob("*.svg")):
|
||||
source = path.read_text(encoding="utf-8")
|
||||
edits = []
|
||||
for node in Document(source).nodes:
|
||||
if node.tag in {"text", "title", "desc"} and not any(isinstance(child, Node) for child in node.children):
|
||||
text = unescape(source[node.open_end:node.end_start]).strip()
|
||||
if translatable(text) and ("figure:" + path.name, text) in messages:
|
||||
translated = messages[("figure:" + path.name, text)]
|
||||
edits.append((node.open_end, node.end_start, escape(translated, quote=False)))
|
||||
translated = apply_edits(source, edits)
|
||||
output = staging / "assets/localized" / language["code"] / path.relative_to(site / "assets")
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
output.write_text(translated, encoding="utf-8")
|
||||
figures.add(path.relative_to(site).as_posix())
|
||||
for path in pages:
|
||||
relative = path.relative_to(site).as_posix()
|
||||
output = staging / localized_path(relative, language["code"])
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
rendered = render_page(root, path, language, messages, available, figures, page_languages[relative]) if relative in available else render_fallback(root, path, language, page_languages[relative], messages)
|
||||
output.write_text(rendered, encoding="utf-8")
|
||||
fallback_count = len(pages) - len(available)
|
||||
if fallback_count:
|
||||
print(f"{language['code']}: {fallback_count} English fallback pages, marked noindex; run translations status.")
|
||||
print(f"Prepared {len(pages) * len(inventory)} reading pages in {len(inventory)} languages.")
|
||||
if finalize is not None:
|
||||
finalize(staging)
|
||||
if destination.exists():
|
||||
shutil.rmtree(destination)
|
||||
staging.rename(destination)
|
||||
|
|
@ -214,6 +214,16 @@ it.each([
|
|||
{ code: true, runtime: false, browser: false, package: false },
|
||||
],
|
||||
["website/src/index.ts", { code: false, website: true, package: false }],
|
||||
[
|
||||
"website/locales/zh-CN/messages.po",
|
||||
{ code: false, website: true, package: false },
|
||||
],
|
||||
["scripts/website_i18n.py", { code: false, website: true, package: false }],
|
||||
["README_ja.md", { code: false, docs: true, website: true, package: false }],
|
||||
[
|
||||
".github/workflows/website-pages.yml",
|
||||
{ code: false, website: true, package: false },
|
||||
],
|
||||
[
|
||||
"src/process/ProviderProcess.ts",
|
||||
{ code: true, package: true, evm: true, browser: true },
|
||||
|
|
|
|||
|
|
@ -8,8 +8,18 @@ Read [README.md](README.md) and [style-guide.md](style-guide.md) before changing
|
|||
website content, layout or figures. Use [figures.md](figures.md) and `evidence/`
|
||||
for asset notes and the source of case-study claims.
|
||||
|
||||
- Write English, direct headings and concrete instructions. Each paragraph
|
||||
should explain a new fact or action.
|
||||
- Author source pages in English. Use direct headings and concrete instructions
|
||||
in every language. Each paragraph should explain a new fact or action.
|
||||
- Follow [locales/README.md](locales/README.md) for translations. Edit standard PO
|
||||
catalogs, run `translations extract` after changing source text, and review
|
||||
translated setup prompts, terminology and case-study reasoning for readability.
|
||||
Keep code, commands, URLs, paths and Evidence unchanged. Use inline `code` or
|
||||
`translate="no"` for executable literals inside a translated sentence. Preserve
|
||||
named placeholders, source references and reviewer comments. Generated language
|
||||
HTML belongs in ignored `_site/`; do not author duplicate translated pages.
|
||||
- Keep the language inventory aligned with README editions. Review long headings,
|
||||
figures and right-to-left layouts. A missing or fuzzy translation produces a
|
||||
labeled, nonindexable English fallback; do not present stale text as current.
|
||||
- Reuse the shared styles, prompts, figures and code-step components. Keep a
|
||||
case study focused on one question, with further examples in native details.
|
||||
- Edit shared header, footer and sharing markup in `templates/`; run
|
||||
|
|
|
|||
|
|
@ -4,12 +4,15 @@
|
|||
>
|
||||
> — N0zoM1z0
|
||||
|
||||
An English static website with explanatory figures, worked guides and Aegis, DX-Ball, Notion, TH04 and CTF investigations.
|
||||
The public files are in `website/public/`. The site uses HTML, CSS and small
|
||||
An English website with translated editions in every README language, explanatory
|
||||
figures, worked guides and Aegis, DX-Ball, Notion, TH04 and CTF investigations.
|
||||
English sources are in `website/public/`; translations are standard gettext PO
|
||||
catalogs in `website/locales/`. The site uses HTML, CSS and small
|
||||
scripts for copying code, following code comparisons and playing the dinosaur
|
||||
speed reconstruction. Small Python commands maintain shared HTML, prepare
|
||||
downloads and check the site. There is no frontend framework, bundler or npm
|
||||
dependency. The checked-in HTML works as ordinary static files.
|
||||
dependency. A build generates all editions in `website/_site/`. The resulting
|
||||
files work as ordinary static files; language switching needs no JavaScript.
|
||||
|
||||
[style-guide.md](style-guide.md) explains the writing, page structure, figures,
|
||||
visual system and review process. Read it before adding or revising a page.
|
||||
|
|
@ -26,6 +29,8 @@ python3 scripts/website.py serve
|
|||
```
|
||||
|
||||
Open <http://127.0.0.1:4173/>. Refresh the browser after editing a file.
|
||||
After editing source HTML or a catalog, run `python3 scripts/prepare-website.py`
|
||||
to rebuild the preview. `serve` prepares the site once when it starts.
|
||||
Keep the virtual environment active when preparing assets. CairoSVG needs the
|
||||
native Cairo library; the sharing card uses DejaVu Sans. On Debian or Ubuntu,
|
||||
install them with `sudo apt-get install libcairo2 fonts-dejavu-core`. For other
|
||||
|
|
@ -49,6 +54,14 @@ applies to every page.
|
|||
| Main navigation | `NAVIGATION` in `scripts/website.py` | `sync`, then `check` |
|
||||
| Header, social links or footer | `templates/header.html.tmpl` or `templates/footer.html.tmpl` | `sync`, then `check` |
|
||||
| Shared link previews | `templates/sharing.html.tmpl` or `public/assets/social-card.svg` | `sync`, then `check` |
|
||||
| Translation | `locales/<language>/messages.po` | `translations check`, then `check` |
|
||||
|
||||
After changing English text, run `python3 scripts/website.py translations extract`
|
||||
before `check`. Existing translations and reviewer comments survive extraction;
|
||||
new or changed sentences need updated translations. See
|
||||
[the translation guide](locales/README.md) for the editing workflow, terminology
|
||||
and the handling of pages whose translations are being updated. Never edit
|
||||
generated HTML in `_site/`.
|
||||
|
||||
Create a reading page with:
|
||||
|
||||
|
|
@ -83,7 +96,8 @@ Before opening a PR:
|
|||
python3 scripts/website.py check
|
||||
```
|
||||
|
||||
This checks shared HTML without rewriting it, prepares generated assets, and
|
||||
This checks shared HTML and translation sources without rewriting them, prepares
|
||||
all language editions and generated assets, and
|
||||
checks page links, copied-text targets, repository documentation links, SEO
|
||||
metadata and the publishing configuration. It also runs the maintenance
|
||||
regressions. A stale shared region fails with the command needed to fix it.
|
||||
|
|
@ -145,8 +159,9 @@ Graph and Twitter fields and the canonical from those inputs and the file's
|
|||
route. Search results and link previews should follow the same clear, concise
|
||||
writing standard as the page.
|
||||
|
||||
`scripts/prepare-website.py` scans `public/**/*.html` and generates
|
||||
`public/sitemap.xml` with absolute rea.tools URLs. An `index.html` maps to its
|
||||
`scripts/prepare-website.py` renders `public/` and the PO catalogs into `_site/`,
|
||||
then scans `_site/**/*.html` and generates `_site/sitemap.xml` with absolute
|
||||
rea.tools URLs. An `index.html` maps to its
|
||||
directory route; other HTML filenames retain their extension. Pages with
|
||||
`noindex` or `none` in a head `robots` or `googlebot` meta directive are excluded.
|
||||
The two Notes example applications use `noindex`; their guides and the dinosaur
|
||||
|
|
@ -201,7 +216,7 @@ guide. Add a figure when it contributes a useful explanation; an opening flow
|
|||
is optional. Case studies remain focused on one inspected behavior. Keep engine
|
||||
details in supporting references unless they explain a relevant decision.
|
||||
|
||||
The Touhou article is an English essay. Its provenance,
|
||||
The Touhou article is authored in English and translated through the same catalogs. Its provenance,
|
||||
quoted README passage and milestone counting rules are in
|
||||
[evidence/touhou-reconstruction-method.md](evidence/touhou-reconstruction-method.md).
|
||||
The completed text has normal search metadata and is included in the generated
|
||||
|
|
@ -226,7 +241,7 @@ The Electron guide offers one ZIP containing the six source files under
|
|||
`notes-example/`. `scripts/prepare-website.py` generates this download from
|
||||
an explicit file list, with fixed timestamps and permissions. The ZIP is ignored
|
||||
by Git; website checks and each manual publication regenerate it before checking
|
||||
and uploading the public directory. The verifier checks that its entries match
|
||||
and uploading `_site/`. The verifier checks that its entries match
|
||||
the current source and contain no extra files.
|
||||
|
||||
The first-investigation page uses this same ZIP. Its prompt lets the agent
|
||||
|
|
@ -371,9 +386,9 @@ solver constants and evidence notes aligned when changing this case.
|
|||
|
||||
## Cloudflare Workers
|
||||
|
||||
`wrangler.toml` serves `website/public/` through Workers Static Assets. There is
|
||||
no Worker script or frontend build. Before a preview or deployment, Wrangler
|
||||
runs the existing Python scripts to prepare the example ZIP and verify the
|
||||
`wrangler.toml` serves `website/_site/` through Workers Static Assets. There is
|
||||
no Worker script or frontend framework. Before a preview or deployment, Wrangler
|
||||
runs the Python scripts to build the language editions, prepare the example ZIP and verify the
|
||||
website. Node.js and Python 3 must be available; the commands below use a pinned
|
||||
Wrangler version without adding it to REA's package dependencies.
|
||||
|
||||
|
|
@ -444,7 +459,7 @@ Local Wrangler commands above publish only the separate preview Worker.
|
|||
|
||||
## Synchronized production publishing
|
||||
|
||||
`.github/workflows/website-pages.yml` prepares `website/public` once and deploys
|
||||
`.github/workflows/website-pages.yml` prepares `website/_site` once and deploys
|
||||
the same artifact to Cloudflare (`rea.tools`) and GitHub Pages. It is the sole
|
||||
production publisher, manually triggered and restricted to `main`;
|
||||
ordinary pushes and pull requests do not publish the site.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
# Website translations
|
||||
|
||||
> A good website is like a good paper: easy to follow, clear and concise, with a clean, refined presentation.
|
||||
>
|
||||
> — N0zoM1z0
|
||||
|
||||
The same standard applies in every language. A translation should help someone
|
||||
understand the example and try it. Clear, accurate wording matters more than a
|
||||
literal imitation of English sentences.
|
||||
|
||||
## Edit a translation
|
||||
|
||||
Use the Python environment in [the website README](../README.md). Pick a language
|
||||
from `languages.json`, then edit its `messages.po` in a text editor, Poedit or
|
||||
another gettext editor. Each entry includes its source page and line:
|
||||
|
||||
```po
|
||||
#: website/public/faq/index.html:200
|
||||
msgctxt "page:faq/index.html"
|
||||
msgid "How do I install REA?"
|
||||
msgstr "如何安装 REA?"
|
||||
```
|
||||
|
||||
Change `msgstr`. Keep `msgid` and `msgctxt`. Add reviewer notes with `#` comments
|
||||
when useful. Shared navigation uses the `shared` context; page-specific wording
|
||||
has its own context. The same English sentence may need different wording in a
|
||||
different case study.
|
||||
|
||||
```sh
|
||||
python3 scripts/website.py translations status --language zh-CN
|
||||
python3 scripts/website.py translations check --language zh-CN
|
||||
python3 scripts/website.py serve
|
||||
```
|
||||
|
||||
Open <http://127.0.0.1:4173/zh-CN/>. The language selector opens the equivalent
|
||||
page in another edition. Check the page you edited, its figures and its copy
|
||||
buttons. Rebuild a running preview with `python3 scripts/prepare-website.py`.
|
||||
Before submitting a change, run `python3 scripts/website.py check`.
|
||||
Use `translations check --strict` to require every message to be translated.
|
||||
|
||||
## Keep complete sentences and protected evidence
|
||||
|
||||
Paragraphs remain complete translation units. Inline emphasis, links, code and
|
||||
literal commands use named placeholders:
|
||||
|
||||
```po
|
||||
#. {ph0}: <a href="guides/">
|
||||
#. {ph1}: </a>
|
||||
msgctxt "page:index.html"
|
||||
msgid "Already know RE? {ph0}Skip to analysis guides →{ph1}"
|
||||
msgstr "已经了解逆向工程?{ph0}直接看分析指南 →{ph1}"
|
||||
```
|
||||
|
||||
Move a linked or emphasized phrase when your language needs a different sentence
|
||||
order. Keep its opening and closing placeholders around that phrase. Preserve
|
||||
each placeholder exactly once per occurrence. Checks reject missing placeholders
|
||||
and broken tag nesting. Interaction messages use names such as `{speed}` and
|
||||
`{seconds}`; keep those names too.
|
||||
|
||||
Code blocks, inline code and `translate="no"` spans are copied from the source.
|
||||
Commands, filenames, paths, URLs, hashes and observed values must retain their
|
||||
meaning. Never translate `npx rea-agents@latest setup` into prose. Preserve product
|
||||
names such as REA, Codex, Claude Code, Ghidra and Homebrew. Explain technical terms
|
||||
in the surrounding text when needed.
|
||||
|
||||
In these articles, an **agent** is the reader's AI coding assistant. A **call** is
|
||||
a function call; a **library** is a software library. A **port** means adapting a
|
||||
program to another platform. An **oracle** is a concrete reference or checker
|
||||
used to verify a reconstruction. Translate those meanings rather than unrelated
|
||||
dictionary senses. Distinguish native machine-code analysis from local analysis,
|
||||
and .NET assemblies from assembly instructions.
|
||||
|
||||
Review the question, REA's findings, the agent's reasoning and the verification
|
||||
result together. Keep recorded versions, milestone counts, unknowns and source
|
||||
attribution accurate. Blog essays can use a personal voice. Translated quotes
|
||||
should be identifiable as translations and retain a link to the original.
|
||||
|
||||
## Update the English source
|
||||
|
||||
```sh
|
||||
python3 scripts/website.py sync
|
||||
python3 scripts/website.py translations extract
|
||||
python3 scripts/website.py translations status
|
||||
python3 scripts/website.py check
|
||||
```
|
||||
|
||||
Extraction generates `messages.pot` and merges it into each PO catalog. Unchanged
|
||||
sentences keep their translations and reviewer comments. Changed sentences start
|
||||
empty; removed entries are retained as obsolete translation memory. Nothing
|
||||
silently accepts a guessed match. An editor's `fuzzy` entry remains pending until
|
||||
someone reviews it and removes the flag.
|
||||
|
||||
If a page needs a missing or fuzzy message, its language route temporarily shows
|
||||
the complete English page with a visible notice. It has `noindex` and stays out
|
||||
of the sitemap and translated `hreflang` alternatives. Links from ready pages
|
||||
lead to ready editions or the English source. Completing the required entries
|
||||
restores the translated page and its search metadata at the next build. Runtime
|
||||
messages affect only pages that use their script; an untranslated dinosaur status
|
||||
does not turn the FAQ into an English fallback.
|
||||
|
||||
`public/` remains the authored English site. `_site/` is disposable generated
|
||||
output. The sitemap discovers every ready edition automatically. Pages and
|
||||
Cloudflare publish this same artifact. No translation API runs during a build
|
||||
or in a reader's browser.
|
||||
|
||||
Figure labels and accessibility descriptions are included in the catalogs under
|
||||
`figure:<filename>`. Keep labels short enough for the diagram. Interaction text
|
||||
is extracted directly from `t("message")` calls in `public/assets/*.js`, with
|
||||
source locations in the catalog. Keep named values instead of concatenating
|
||||
translated fragments.
|
||||
|
||||
## Language coverage and initial translations
|
||||
|
||||
`languages.json` lists the same editions as the root README, with native names,
|
||||
standard language tags and text direction. English keeps its existing routes;
|
||||
other editions use a language prefix such as `/ja/` or `/pt-BR/`. Arabic and
|
||||
Persian use right-to-left page layouts; code and numeric demos remain left to
|
||||
right. The two Notes target applications and the downloadable source archive
|
||||
remain the original investigation inputs.
|
||||
|
||||
The first catalogs started with machine-assisted drafts. They include editorial
|
||||
corrections to navigation, prompts and technical terminology. Traditional Chinese
|
||||
started from the Simplified Chinese draft and is maintained independently.
|
||||
Further language review and more natural phrasing are welcome. Submit the PO changes with
|
||||
the page and language you checked; a screenshot can help explain a layout issue.
|
||||
|
||||
## Why gettext
|
||||
|
||||
PO catalogs have source references, reviewer comments and explicit pending
|
||||
translations. They can be edited locally and can later be connected to Weblate
|
||||
without replacing the site's translation format. This keeps one authored layout
|
||||
and a small offline build instead of maintaining nineteen HTML trees.
|
||||
|
||||
See [GNU gettext's PO format](https://www.gnu.org/software/gettext/manual/html_node/PO-File-Entries.html),
|
||||
[Weblate's translation workflows](https://docs.weblate.org/en/latest/workflows.html)
|
||||
and [Google's localized-page guidance](https://developers.google.com/search/docs/specialty/international/localized-versions).
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,51 @@
|
|||
[
|
||||
{ "code": "en", "name": "English", "readme": "README.md", "dir": "ltr" },
|
||||
{
|
||||
"code": "zh-CN",
|
||||
"name": "简体中文",
|
||||
"readme": "README_zh.md",
|
||||
"dir": "ltr"
|
||||
},
|
||||
{
|
||||
"code": "zh-TW",
|
||||
"name": "繁體中文",
|
||||
"readme": "README_zh-TW.md",
|
||||
"dir": "ltr"
|
||||
},
|
||||
{ "code": "ja", "name": "日本語", "readme": "README_ja.md", "dir": "ltr" },
|
||||
{ "code": "ko", "name": "한국어", "readme": "README_ko.md", "dir": "ltr" },
|
||||
{ "code": "tr", "name": "Türkçe", "readme": "README_tr.md", "dir": "ltr" },
|
||||
{ "code": "ru", "name": "Русский", "readme": "README_ru.md", "dir": "ltr" },
|
||||
{
|
||||
"code": "vi",
|
||||
"name": "Tiếng Việt",
|
||||
"readme": "README_vi.md",
|
||||
"dir": "ltr"
|
||||
},
|
||||
{ "code": "th", "name": "ไทย", "readme": "README_th.md", "dir": "ltr" },
|
||||
{ "code": "de", "name": "Deutsch", "readme": "README_de.md", "dir": "ltr" },
|
||||
{ "code": "es", "name": "Español", "readme": "README_es.md", "dir": "ltr" },
|
||||
{ "code": "fr", "name": "Français", "readme": "README_fr.md", "dir": "ltr" },
|
||||
{
|
||||
"code": "uk",
|
||||
"name": "Українська",
|
||||
"readme": "README_uk.md",
|
||||
"dir": "ltr"
|
||||
},
|
||||
{ "code": "pl", "name": "Polski", "readme": "README_pl.md", "dir": "ltr" },
|
||||
{
|
||||
"code": "pt-BR",
|
||||
"name": "Português (Brasil)",
|
||||
"readme": "README_pt-BR.md",
|
||||
"dir": "ltr"
|
||||
},
|
||||
{ "code": "ar", "name": "العربية", "readme": "README_ar.md", "dir": "rtl" },
|
||||
{ "code": "fa", "name": "فارسی", "readme": "README_fa.md", "dir": "rtl" },
|
||||
{
|
||||
"code": "id",
|
||||
"name": "Bahasa Indonesia",
|
||||
"readme": "README_id.md",
|
||||
"dir": "ltr"
|
||||
},
|
||||
{ "code": "it", "name": "Italiano", "readme": "README_it.md", "dir": "ltr" }
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,4 +1,5 @@
|
|||
import { generateExampleCode } from "./aegis-otp.js";
|
||||
import { t } from "./i18n.js";
|
||||
|
||||
async function initializeAegisDemo() {
|
||||
const demo = document.querySelector("[data-aegis-demo]");
|
||||
|
|
@ -18,19 +19,22 @@ async function initializeAegisDemo() {
|
|||
demo.querySelector("[data-aegis-block]").textContent = String(block);
|
||||
demo.querySelector("[data-aegis-division]").textContent =
|
||||
`floor(${seconds} / 30)`;
|
||||
demo.querySelector("[data-aegis-window]").textContent =
|
||||
`${block * 30}–${block * 30 + 29} seconds`;
|
||||
demo.querySelector("[data-aegis-window]").textContent = t(
|
||||
"{start}–{end} seconds",
|
||||
{ start: block * 30, end: block * 30 + 29 },
|
||||
);
|
||||
demo.querySelector("[data-aegis-code]").textContent = code;
|
||||
clock.setAttribute(
|
||||
"aria-valuetext",
|
||||
`${seconds} seconds, time block ${block}`,
|
||||
t("{seconds} seconds, time block {block}", { seconds, block }),
|
||||
);
|
||||
status.textContent = "";
|
||||
return true;
|
||||
} catch {
|
||||
if (currentRevision === revision) {
|
||||
status.textContent =
|
||||
"Interactive calculation is unavailable in this browser. The example shows the code at 59 seconds.";
|
||||
status.textContent = t(
|
||||
"Interactive calculation is unavailable in this browser. The example shows the code at 59 seconds.",
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -55,7 +59,7 @@ async function initializeAegisDemo() {
|
|||
checkButton.disabled = false;
|
||||
checkButton.addEventListener("click", async () => {
|
||||
checkButton.disabled = true;
|
||||
checkResult.textContent = "Checking…";
|
||||
checkResult.textContent = t("Checking…");
|
||||
try {
|
||||
const response = await fetch(
|
||||
new URL("../showcase/aegis/test-vectors.json", import.meta.url),
|
||||
|
|
@ -69,12 +73,14 @@ async function initializeAegisDemo() {
|
|||
if (code === vector.sha1.slice(-digits)) passed += 1;
|
||||
}
|
||||
}
|
||||
checkResult.textContent =
|
||||
`${passed} / ${vectors.length * 2} checks passed ` +
|
||||
"(six reference cases, at six and eight digits).";
|
||||
checkResult.textContent = t(
|
||||
"{passed} / {total} checks passed (six reference cases, at six and eight digits).",
|
||||
{ passed, total: vectors.length * 2 },
|
||||
);
|
||||
} catch {
|
||||
checkResult.textContent =
|
||||
"Could not run the reference checks. Try again.";
|
||||
checkResult.textContent = t(
|
||||
"Could not run the reference checks. Try again.",
|
||||
);
|
||||
} finally {
|
||||
checkButton.disabled = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { advanceSpeed, simulateSpeed, SPEED_RULE } from "./dino-speed.js";
|
||||
import { t } from "./i18n.js";
|
||||
|
||||
// A new teaching game around the recovered speed rule. Drawing, jump physics
|
||||
// and rectangle collision checks are authored for this demo.
|
||||
|
|
@ -67,7 +68,9 @@ function initializeDinoDemo(demo) {
|
|||
context.font = "13px monospace";
|
||||
context.textAlign = "right";
|
||||
context.fillText(
|
||||
`DISTANCE ${String(Math.floor(distance / 100)).padStart(4, "0")}`,
|
||||
t("Distance {distance}", {
|
||||
distance: String(Math.floor(distance / 100)).padStart(4, "0"),
|
||||
}),
|
||||
580,
|
||||
28,
|
||||
);
|
||||
|
|
@ -75,7 +78,7 @@ function initializeDinoDemo(demo) {
|
|||
context.textAlign = "center";
|
||||
context.font = "15px system-ui";
|
||||
context.fillText(
|
||||
crashed ? "Hit a cactus. Try another speed." : "Space or Jump ↑",
|
||||
crashed ? t("Hit a cactus. Try another speed.") : t("Space or Jump ↑"),
|
||||
330,
|
||||
85,
|
||||
);
|
||||
|
|
@ -85,7 +88,7 @@ function initializeDinoDemo(demo) {
|
|||
const stop = (message) => {
|
||||
running = false;
|
||||
cancelAnimationFrame(frame);
|
||||
start.textContent = crashed ? "Play again" : "Play";
|
||||
start.textContent = crashed ? t("Play again") : t("Play");
|
||||
if (message) status.textContent = message;
|
||||
draw();
|
||||
};
|
||||
|
|
@ -99,8 +102,8 @@ function initializeDinoDemo(demo) {
|
|||
obstacles = [{ x: 550, height: 38 }];
|
||||
if (auto.checked) speed = SPEED_RULE.start;
|
||||
elapsed = 0;
|
||||
start.textContent = "Play";
|
||||
status.textContent = "Press Play, then jump over the cactus.";
|
||||
start.textContent = t("Play");
|
||||
status.textContent = t("Press Play, then jump over the cactus.");
|
||||
updateSpeedDisplay();
|
||||
draw();
|
||||
};
|
||||
|
|
@ -134,7 +137,9 @@ function initializeDinoDemo(demo) {
|
|||
)
|
||||
) {
|
||||
crashed = true;
|
||||
stop("Hit a cactus. Press Play again, or change the speed and restart.");
|
||||
stop(
|
||||
t("Hit a cactus. Press Play again, or change the speed and restart."),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -157,8 +162,8 @@ function initializeDinoDemo(demo) {
|
|||
running = true;
|
||||
lastTime = performance.now();
|
||||
elapsed = 0;
|
||||
start.textContent = "Pause";
|
||||
status.textContent = "Running. Space or Jump clears a cactus.";
|
||||
start.textContent = t("Pause");
|
||||
status.textContent = t("Running. Space or Jump clears a cactus.");
|
||||
frame = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
|
|
@ -169,7 +174,7 @@ function initializeDinoDemo(demo) {
|
|||
};
|
||||
|
||||
start.addEventListener("click", () => {
|
||||
if (running) stop("Paused. Press Play to continue.");
|
||||
if (running) stop(t("Paused. Press Play to continue."));
|
||||
else play();
|
||||
});
|
||||
demo.querySelector("[data-dino-jump]").addEventListener("click", jump);
|
||||
|
|
@ -189,24 +194,28 @@ function initializeDinoDemo(demo) {
|
|||
speed = Number(slider.value);
|
||||
updateSpeedDisplay();
|
||||
status.textContent = running
|
||||
? `Fixed speed: ${speed.toFixed(1)}. Space or Jump clears a cactus.`
|
||||
: `Fixed speed: ${speed.toFixed(1)}. Press Play to try it.`;
|
||||
? t("Fixed speed: {speed}. Space or Jump clears a cactus.", {
|
||||
speed: speed.toFixed(1),
|
||||
})
|
||||
: t("Fixed speed: {speed}. Press Play to try it.", {
|
||||
speed: speed.toFixed(1),
|
||||
});
|
||||
draw();
|
||||
});
|
||||
auto.addEventListener("change", () => {
|
||||
if (auto.checked) speed = SPEED_RULE.start;
|
||||
updateSpeedDisplay();
|
||||
status.textContent = auto.checked
|
||||
? "Recovered rule: start at 6, then increase toward 13."
|
||||
: `Fixed speed: ${speed.toFixed(1)}.`;
|
||||
? t("Recovered rule: start at 6, then increase toward 13.")
|
||||
: t("Fixed speed: {speed}.", { speed: speed.toFixed(1) });
|
||||
});
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (document.hidden && running) stop("Paused. Press Play to continue.");
|
||||
if (document.hidden && running) stop(t("Paused. Press Play to continue."));
|
||||
});
|
||||
if ("IntersectionObserver" in window) {
|
||||
new IntersectionObserver((entries) => {
|
||||
if (!entries[0].isIntersecting && running)
|
||||
stop("Paused. Press Play to continue.");
|
||||
stop(t("Paused. Press Play to continue."));
|
||||
}).observe(demo);
|
||||
}
|
||||
demo.querySelector(".dino-fallback").setAttribute("hidden", "");
|
||||
|
|
@ -230,6 +239,10 @@ speedCheck?.addEventListener("click", () => {
|
|||
matches && speed === cell.parentElement.children[1].textContent.trim();
|
||||
});
|
||||
document.querySelector("[data-speed-check-status]").textContent = matches
|
||||
? "Replayed the recovered rule. All four values match the controlled original-game check when rounded to three decimals."
|
||||
: "The replay differs from the recorded original-game values. Compare the speed rule and settings above.";
|
||||
? t(
|
||||
"Replayed the recovered rule. All four values match the controlled original-game check when rounded to three decimals.",
|
||||
)
|
||||
: t(
|
||||
"The replay differs from the recorded original-game values. Compare the speed rule and settings above.",
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { t } from "./i18n.js";
|
||||
|
||||
function initializePercentDemo() {
|
||||
const demo = document.querySelector("[data-percent-demo]");
|
||||
if (demo === null) return;
|
||||
|
|
@ -24,11 +26,11 @@ function initializePercentDemo() {
|
|||
equals.disabled = stage !== "percent";
|
||||
status.textContent =
|
||||
stage === "input"
|
||||
? "Press % to see what happens to 10."
|
||||
? t("Press % to see what happens to 10.")
|
||||
: stage === "percent"
|
||||
? adding
|
||||
? "10% of 200 is 20. Press = to add it."
|
||||
: "For multiplication, 10 becomes 0.1. Press = to multiply."
|
||||
? t("10% of 200 is 20. Press = to add it.")
|
||||
: t("For multiplication, 10 becomes 0.1. Press = to multiply.")
|
||||
: `200 ${operator} ${percent} = ${result}.`;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
const messages = JSON.parse(
|
||||
document.getElementById("website-messages")?.textContent ?? "{}",
|
||||
);
|
||||
|
||||
export function t(message, values = {}) {
|
||||
const translated = messages[message] ?? message;
|
||||
return translated.replace(/\{([a-zA-Z][a-zA-Z0-9_]*)\}/g, (match, key) =>
|
||||
Object.hasOwn(values, key) ? String(values[key]) : match,
|
||||
);
|
||||
}
|
||||
|
||||
document.querySelectorAll("[data-language]").forEach((link) => {
|
||||
link.addEventListener("click", () => {
|
||||
const target = new URL(link.href);
|
||||
target.hash = window.location.hash;
|
||||
link.href = target.href;
|
||||
});
|
||||
});
|
||||
|
||||
const picker = document.querySelector(".language-picker");
|
||||
if (picker !== null) {
|
||||
document.addEventListener("click", (event) => {
|
||||
if (!picker.contains(event.target)) picker.open = false;
|
||||
});
|
||||
picker.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
picker.open = false;
|
||||
picker.querySelector("summary").focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,142 +1,160 @@
|
|||
function initializeCopyButtons() {
|
||||
document.querySelectorAll("[data-copy]").forEach((button) => {
|
||||
button.addEventListener("click", async () => {
|
||||
const target = document.getElementById(button.getAttribute("data-copy"));
|
||||
if (target === null) return;
|
||||
async function initializeWebsite() {
|
||||
const { t } = await import("./i18n.js");
|
||||
|
||||
const status = document.getElementById("copy-status");
|
||||
const content = target.textContent.trim();
|
||||
const text =
|
||||
target.closest(".terminal-prompt") === null
|
||||
? content
|
||||
: content.replace(/\s+/g, " ");
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
button.textContent = "Copied";
|
||||
if (status !== null) status.textContent = "Code copied to clipboard.";
|
||||
} catch {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(target);
|
||||
const selection = window.getSelection();
|
||||
if (selection !== null) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
button.textContent = "Selected";
|
||||
if (status !== null)
|
||||
status.textContent = "Code selected. Use your keyboard to copy it.";
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
button.textContent = "Copy";
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
initializeCopyButtons();
|
||||
|
||||
function initializeStepComparisons() {
|
||||
document.querySelectorAll("[data-step-comparison]").forEach((comparison) => {
|
||||
const buttons = comparison.querySelectorAll("[data-select-step]");
|
||||
const selectStep = (button) => {
|
||||
const selected = button.getAttribute("data-select-step");
|
||||
buttons.forEach((candidate) => {
|
||||
candidate.setAttribute("aria-pressed", String(candidate === button));
|
||||
});
|
||||
comparison.querySelectorAll("[data-step]").forEach((fragment) => {
|
||||
fragment.classList.toggle(
|
||||
"is-active",
|
||||
fragment.getAttribute("data-step") === selected,
|
||||
function initializeCopyButtons() {
|
||||
document.querySelectorAll("[data-copy]").forEach((button) => {
|
||||
button.addEventListener("click", async () => {
|
||||
const target = document.getElementById(
|
||||
button.getAttribute("data-copy"),
|
||||
);
|
||||
if (target === null) return;
|
||||
|
||||
const status = document.getElementById("copy-status");
|
||||
const content = target.textContent.trim();
|
||||
const text =
|
||||
target.closest(".terminal-prompt") === null
|
||||
? content
|
||||
: content.replace(/\s+/g, " ");
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
button.textContent = t("Copied");
|
||||
if (status !== null)
|
||||
status.textContent = t("Code copied to clipboard.");
|
||||
} catch {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(target);
|
||||
const selection = window.getSelection();
|
||||
if (selection !== null) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
button.textContent = t("Selected");
|
||||
if (status !== null)
|
||||
status.textContent = t(
|
||||
"Code selected. Use your keyboard to copy it.",
|
||||
);
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
button.textContent = t("Copy");
|
||||
}, 2000);
|
||||
});
|
||||
comparison.querySelectorAll("[data-step-note]").forEach((note) => {
|
||||
note.hidden = note.getAttribute("data-step-note") !== selected;
|
||||
});
|
||||
}
|
||||
|
||||
initializeCopyButtons();
|
||||
|
||||
function initializeStepComparisons() {
|
||||
document
|
||||
.querySelectorAll("[data-step-comparison]")
|
||||
.forEach((comparison) => {
|
||||
const buttons = comparison.querySelectorAll("[data-select-step]");
|
||||
const selectStep = (button) => {
|
||||
const selected = button.getAttribute("data-select-step");
|
||||
buttons.forEach((candidate) => {
|
||||
candidate.setAttribute(
|
||||
"aria-pressed",
|
||||
String(candidate === button),
|
||||
);
|
||||
});
|
||||
comparison.querySelectorAll("[data-step]").forEach((fragment) => {
|
||||
fragment.classList.toggle(
|
||||
"is-active",
|
||||
fragment.getAttribute("data-step") === selected,
|
||||
);
|
||||
});
|
||||
comparison.querySelectorAll("[data-step-note]").forEach((note) => {
|
||||
note.hidden = note.getAttribute("data-step-note") !== selected;
|
||||
});
|
||||
};
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener("click", () => selectStep(button));
|
||||
});
|
||||
const initial = Array.from(buttons).find(
|
||||
(button) => button.getAttribute("aria-pressed") === "true",
|
||||
);
|
||||
if (initial) selectStep(initial);
|
||||
});
|
||||
}
|
||||
|
||||
initializeStepComparisons();
|
||||
|
||||
function initializeFaqAnswers() {
|
||||
const answers = document.querySelectorAll("[data-faq] details[id]");
|
||||
if (answers.length === 0) return;
|
||||
|
||||
const revealAnswer = (fragment) => {
|
||||
answers.forEach((answer) => {
|
||||
if (`#${answer.id}` === fragment) answer.open = true;
|
||||
});
|
||||
};
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener("click", () => selectStep(button));
|
||||
});
|
||||
const initial = Array.from(buttons).find(
|
||||
(button) => button.getAttribute("aria-pressed") === "true",
|
||||
window.addEventListener("hashchange", () =>
|
||||
revealAnswer(window.location.hash),
|
||||
);
|
||||
if (initial) selectStep(initial);
|
||||
});
|
||||
}
|
||||
|
||||
initializeStepComparisons();
|
||||
|
||||
function initializeFaqAnswers() {
|
||||
const answers = document.querySelectorAll("[data-faq] details[id]");
|
||||
if (answers.length === 0) return;
|
||||
|
||||
const revealAnswer = (fragment) => {
|
||||
answers.forEach((answer) => {
|
||||
if (`#${answer.id}` === fragment) answer.open = true;
|
||||
document.querySelectorAll('[data-faq] a[href^="#"]').forEach((link) => {
|
||||
link.addEventListener("click", () =>
|
||||
revealAnswer(link.getAttribute("href")),
|
||||
);
|
||||
});
|
||||
};
|
||||
window.addEventListener("hashchange", () =>
|
||||
revealAnswer(window.location.hash),
|
||||
);
|
||||
document.querySelectorAll('[data-faq] a[href^="#"]').forEach((link) => {
|
||||
link.addEventListener("click", () =>
|
||||
revealAnswer(link.getAttribute("href")),
|
||||
);
|
||||
});
|
||||
revealAnswer(window.location.hash);
|
||||
}
|
||||
|
||||
initializeFaqAnswers();
|
||||
|
||||
function initializeBackToTop() {
|
||||
const link = document.querySelector(".back-to-top");
|
||||
if (link === null) return;
|
||||
|
||||
const updateVisibility = () => {
|
||||
link.hidden = window.scrollY < 400;
|
||||
};
|
||||
window.addEventListener("scroll", updateVisibility, { passive: true });
|
||||
updateVisibility();
|
||||
|
||||
link.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
const reduceMotion = window.matchMedia(
|
||||
"(prefers-reduced-motion: reduce)",
|
||||
).matches;
|
||||
window.scrollTo({ top: 0, behavior: reduceMotion ? "auto" : "smooth" });
|
||||
document
|
||||
.querySelector(".brand, .breadcrumb a")
|
||||
?.focus({ preventScroll: true });
|
||||
});
|
||||
}
|
||||
|
||||
initializeBackToTop();
|
||||
|
||||
async function initializeGitHubStars() {
|
||||
const link = document.querySelector(".nav-github");
|
||||
const count = link?.querySelector(".nav-github-count");
|
||||
if (count === null || count === undefined) return;
|
||||
|
||||
try {
|
||||
const response = await fetch("https://api.github.com/repos/morluto/rea", {
|
||||
headers: { Accept: "application/vnd.github+json" },
|
||||
credentials: "omit",
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (!response.ok) return;
|
||||
const repository = await response.json();
|
||||
const stars = repository.stargazers_count;
|
||||
if (!Number.isSafeInteger(stars) || stars < 0) return;
|
||||
|
||||
const formatted = new Intl.NumberFormat("en-US").format(stars);
|
||||
const label = `REA on GitHub (${formatted} ${stars === 1 ? "star" : "stars"})`;
|
||||
count.textContent = formatted;
|
||||
count.hidden = false;
|
||||
link.setAttribute("aria-label", label);
|
||||
link.setAttribute("title", label);
|
||||
} catch {
|
||||
// Keep the repository link usable when GitHub is unavailable.
|
||||
revealAnswer(window.location.hash);
|
||||
}
|
||||
|
||||
initializeFaqAnswers();
|
||||
|
||||
function initializeBackToTop() {
|
||||
const link = document.querySelector(".back-to-top");
|
||||
if (link === null) return;
|
||||
|
||||
const updateVisibility = () => {
|
||||
link.hidden = window.scrollY < 400;
|
||||
};
|
||||
window.addEventListener("scroll", updateVisibility, { passive: true });
|
||||
updateVisibility();
|
||||
|
||||
link.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
const reduceMotion = window.matchMedia(
|
||||
"(prefers-reduced-motion: reduce)",
|
||||
).matches;
|
||||
window.scrollTo({ top: 0, behavior: reduceMotion ? "auto" : "smooth" });
|
||||
document
|
||||
.querySelector(".brand, .breadcrumb a")
|
||||
?.focus({ preventScroll: true });
|
||||
});
|
||||
}
|
||||
|
||||
initializeBackToTop();
|
||||
|
||||
async function initializeGitHubStars() {
|
||||
const link = document.querySelector(".nav-github");
|
||||
const count = link?.querySelector(".nav-github-count");
|
||||
if (count === null || count === undefined) return;
|
||||
|
||||
try {
|
||||
const response = await fetch("https://api.github.com/repos/morluto/rea", {
|
||||
headers: { Accept: "application/vnd.github+json" },
|
||||
credentials: "omit",
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (!response.ok) return;
|
||||
const repository = await response.json();
|
||||
const stars = repository.stargazers_count;
|
||||
if (!Number.isSafeInteger(stars) || stars < 0) return;
|
||||
|
||||
const formatted = new Intl.NumberFormat(
|
||||
document.documentElement.lang,
|
||||
).format(stars);
|
||||
const label = t("REA on GitHub ({count})", { count: formatted });
|
||||
count.textContent = formatted;
|
||||
count.hidden = false;
|
||||
link.setAttribute("aria-label", label);
|
||||
link.setAttribute("title", label);
|
||||
} catch {
|
||||
// Keep the repository link usable when GitHub is unavailable.
|
||||
}
|
||||
}
|
||||
|
||||
initializeGitHubStars();
|
||||
}
|
||||
|
||||
initializeGitHubStars();
|
||||
initializeWebsite();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ body {
|
|||
background: var(--page);
|
||||
color: var(--ink);
|
||||
line-height: 1.65;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
a {
|
||||
color: var(--accent);
|
||||
|
|
@ -50,6 +51,15 @@ code {
|
|||
font-size: 0.9em;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
span[translate="no"] {
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
}
|
||||
html[dir="rtl"] span[translate="no"] {
|
||||
display: inline-block;
|
||||
max-inline-size: 100%;
|
||||
text-align: start;
|
||||
}
|
||||
kbd {
|
||||
padding: 0.05rem 0.35rem;
|
||||
border: 1px solid var(--line);
|
||||
|
|
@ -136,8 +146,72 @@ section[id] {
|
|||
color: var(--ink);
|
||||
}
|
||||
.site-header {
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.language-picker {
|
||||
position: relative;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.language-picker summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
min-height: 44px;
|
||||
padding: 0.35rem 0.65rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 5px;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
list-style: none;
|
||||
}
|
||||
.language-picker summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.language-picker summary::after {
|
||||
content: "⌄";
|
||||
}
|
||||
.language-picker nav {
|
||||
position: absolute;
|
||||
inset-inline-end: 0;
|
||||
top: calc(100% + 0.5rem);
|
||||
z-index: 12;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.15rem;
|
||||
width: min(340px, calc(100vw - 2.5rem));
|
||||
max-height: 70vh;
|
||||
overflow: auto;
|
||||
padding: 0.6rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--page);
|
||||
box-shadow: 0 5px 20px rgb(32 37 43 / 8%);
|
||||
}
|
||||
.language-picker nav a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 44px;
|
||||
padding: 0.45rem 0.6rem;
|
||||
color: var(--muted);
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.language-picker nav a:hover,
|
||||
.language-picker nav a[aria-current="true"] {
|
||||
color: var(--accent);
|
||||
background: var(--soft);
|
||||
}
|
||||
.translation-notice {
|
||||
padding: 0.9rem 1.2rem;
|
||||
margin-block: 1.5rem;
|
||||
border-inline-start: 2px solid var(--accent);
|
||||
background: var(--soft);
|
||||
color: var(--muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.header-inner {
|
||||
min-height: 88px;
|
||||
display: grid;
|
||||
|
|
@ -165,8 +239,9 @@ section[id] {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 1.8rem;
|
||||
font-size: 0.9rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.65rem 1.4rem;
|
||||
}
|
||||
.navigation a {
|
||||
color: var(--muted);
|
||||
|
|
@ -534,7 +609,7 @@ pre code {
|
|||
}
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
.stats dt {
|
||||
|
|
@ -564,7 +639,7 @@ pre code {
|
|||
}
|
||||
.workflows {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 2.8rem;
|
||||
}
|
||||
.workflows p {
|
||||
|
|
@ -1586,7 +1661,7 @@ pre code {
|
|||
font-size: 0.85rem;
|
||||
}
|
||||
.home-expert-shortcut a {
|
||||
white-space: nowrap;
|
||||
white-space: normal;
|
||||
}
|
||||
.home-expert-shortcut + .home-expert-shortcut {
|
||||
margin-top: 0.5rem;
|
||||
|
|
@ -1798,12 +1873,12 @@ pre code {
|
|||
outline-offset: 3px;
|
||||
}
|
||||
.assembly-disclosure::after {
|
||||
content: "Show +";
|
||||
content: "+";
|
||||
color: var(--accent);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.expert-assembly[open] .assembly-disclosure::after {
|
||||
content: "Hide −";
|
||||
content: "−";
|
||||
}
|
||||
.expert-assembly pre {
|
||||
margin: 0;
|
||||
|
|
@ -2188,6 +2263,10 @@ pre code {
|
|||
.speed-check-table th:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
.speed-check-table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
|
@ -2382,7 +2461,7 @@ pre code {
|
|||
grid-template-columns: 1fr;
|
||||
}
|
||||
.case-stats {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
border-left: 0;
|
||||
padding: 1.5rem 0 0;
|
||||
border-top: 1px solid var(--line);
|
||||
|
|
@ -2485,3 +2564,96 @@ pre code {
|
|||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep prose natural in each language while code and evidence stay left-to-right. */
|
||||
html:lang(zh),
|
||||
html:lang(ja),
|
||||
html:lang(ko),
|
||||
html:lang(th),
|
||||
html[dir="rtl"] {
|
||||
letter-spacing: normal;
|
||||
}
|
||||
html:lang(zh) h1,
|
||||
html:lang(zh) h2,
|
||||
html:lang(zh) h3,
|
||||
html:lang(ja) h1,
|
||||
html:lang(ja) h2,
|
||||
html:lang(ja) h3,
|
||||
html:lang(ko) h1,
|
||||
html:lang(ko) h2,
|
||||
html:lang(ko) h3,
|
||||
html:lang(th) h1,
|
||||
html:lang(th) h2,
|
||||
html:lang(th) h3,
|
||||
html[dir="rtl"] h1,
|
||||
html[dir="rtl"] h2,
|
||||
html[dir="rtl"] h3 {
|
||||
letter-spacing: normal;
|
||||
line-height: 1.35;
|
||||
}
|
||||
html[dir="rtl"] code,
|
||||
html[dir="rtl"] pre,
|
||||
html[dir="rtl"] kbd,
|
||||
html[dir="rtl"] .dino-stage,
|
||||
html[dir="rtl"] .percent-demo,
|
||||
html[dir="rtl"] .aegis-calculation {
|
||||
direction: ltr;
|
||||
unicode-bidi: isolate;
|
||||
text-align: left;
|
||||
}
|
||||
html[dir="rtl"] ul,
|
||||
html[dir="rtl"] ol {
|
||||
padding-left: 0;
|
||||
padding-right: 1.3rem;
|
||||
}
|
||||
html[dir="rtl"] .terminal-prompt {
|
||||
font-family: inherit;
|
||||
text-align: start;
|
||||
}
|
||||
html[dir="rtl"] .breadcrumb,
|
||||
html[dir="rtl"] .brand-name {
|
||||
unicode-bidi: isolate;
|
||||
}
|
||||
@media (min-width: 851px) and (max-width: 1250px) {
|
||||
.brand-caption {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 850px) {
|
||||
.header-inner {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
}
|
||||
.brand-caption {
|
||||
display: none;
|
||||
}
|
||||
.navigation {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: 2;
|
||||
justify-content: flex-start;
|
||||
padding-bottom: 0.8rem;
|
||||
}
|
||||
.header-social {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
.nav-github-count {
|
||||
display: none;
|
||||
}
|
||||
.language-picker {
|
||||
position: static;
|
||||
}
|
||||
.language-picker nav {
|
||||
inset-inline: 1.25rem;
|
||||
top: 4.3rem;
|
||||
width: auto;
|
||||
}
|
||||
.explanatory-figure figcaption a {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
@media (max-width: 400px) {
|
||||
.header-social .nav-x {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/blog/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/blog/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/blog/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../blog/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../zh-CN/blog/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../zh-TW/blog/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../ja/blog/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../ko/blog/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../tr/blog/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../ru/blog/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../vi/blog/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../th/blog/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../de/blog/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../es/blog/" lang="es" dir="ltr" data-language="es">Español</a><a href="../fr/blog/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../uk/blog/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../pl/blog/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../pt-BR/blog/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../ar/blog/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../fa/blog/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../id/blog/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../it/blog/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/blog/touhou-reconstruction/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/blog/touhou-reconstruction/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/blog/touhou-reconstruction/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../blog/touhou-reconstruction/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/blog/touhou-reconstruction/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/blog/touhou-reconstruction/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/blog/touhou-reconstruction/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/blog/touhou-reconstruction/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/blog/touhou-reconstruction/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/blog/touhou-reconstruction/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/blog/touhou-reconstruction/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/blog/touhou-reconstruction/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/blog/touhou-reconstruction/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/blog/touhou-reconstruction/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/blog/touhou-reconstruction/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/blog/touhou-reconstruction/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/blog/touhou-reconstruction/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/blog/touhou-reconstruction/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/blog/touhou-reconstruction/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/blog/touhou-reconstruction/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/blog/touhou-reconstruction/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/blog/touhou-reconstruction/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/examples/dino-lab/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/examples/dino-lab/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/examples/dino-lab/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -62,7 +104,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/">Showcases</a>
|
||||
|
|
@ -72,6 +114,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../examples/dino-lab/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/examples/dino-lab/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/examples/dino-lab/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/examples/dino-lab/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/examples/dino-lab/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/examples/dino-lab/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/examples/dino-lab/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/examples/dino-lab/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/examples/dino-lab/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/examples/dino-lab/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/examples/dino-lab/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/examples/dino-lab/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/examples/dino-lab/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/examples/dino-lab/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/examples/dino-lab/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/examples/dino-lab/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/examples/dino-lab/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/examples/dino-lab/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/examples/dino-lab/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -261,7 +304,9 @@
|
|||
<h3>Use the same rule in the new game</h3>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Reconstruction · dino-speed.js</span
|
||||
<span
|
||||
>Reconstruction ·
|
||||
<span translate="no">dino-speed.js</span></span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/faq/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/faq/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/faq/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../faq/" aria-current="page">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../faq/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../zh-CN/faq/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../zh-TW/faq/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../ja/faq/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../ko/faq/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../tr/faq/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../ru/faq/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../vi/faq/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../th/faq/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../de/faq/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../es/faq/" lang="es" dir="ltr" data-language="es">Español</a><a href="../fr/faq/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../uk/faq/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../pl/faq/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../pt-BR/faq/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../ar/faq/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../fa/faq/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../id/faq/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../it/faq/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -160,8 +203,9 @@
|
|||
<details class="faq-item" id="install">
|
||||
<summary>How do I install REA?</summary>
|
||||
<p>
|
||||
With Node.js and npm available, run setup, choose your coding
|
||||
agent and review the proposed changes.
|
||||
With <span translate="no">Node.js</span> and npm available,
|
||||
run setup, choose your coding agent and review the proposed
|
||||
changes.
|
||||
</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
|
|
@ -368,9 +412,10 @@
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="faq-analysis-prompt"
|
||||
>Use REA to analyze /absolute/path/to/app and explain how
|
||||
it exports data. Show the relevant code and source
|
||||
locations.</span
|
||||
>Use REA to analyze
|
||||
<span translate="no">/absolute/path/to/app</span> and
|
||||
explain how it exports data. Show the relevant code and
|
||||
source locations.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/first-investigation/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/first-investigation/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/first-investigation/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../first-investigation/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../zh-CN/first-investigation/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../zh-TW/first-investigation/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../ja/first-investigation/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../ko/first-investigation/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../tr/first-investigation/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../ru/first-investigation/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../vi/first-investigation/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../th/first-investigation/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../de/first-investigation/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../es/first-investigation/" lang="es" dir="ltr" data-language="es">Español</a><a href="../fr/first-investigation/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../uk/first-investigation/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../pl/first-investigation/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../pt-BR/first-investigation/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../ar/first-investigation/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../fa/first-investigation/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../id/first-investigation/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../it/first-investigation/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -144,7 +187,8 @@
|
|||
check one detail yourself.
|
||||
</p>
|
||||
<p class="page-meta">
|
||||
A supplied example · Node.js and npm · Your coding agent
|
||||
A supplied example · <span translate="no">Node.js</span> and npm ·
|
||||
Your coding agent
|
||||
</p>
|
||||
</div>
|
||||
<div class="article-layout">
|
||||
|
|
@ -163,7 +207,7 @@
|
|||
<h2>1. Connect your agent to REA</h2>
|
||||
<p>
|
||||
Use a coding agent such as Claude Code, Codex or Cursor. You’ll
|
||||
need Node.js and npm; the
|
||||
need <span translate="no">Node.js</span> and npm; the
|
||||
<a href="../get-started/">setup guide lists supported versions</a
|
||||
>.
|
||||
</p>
|
||||
|
|
@ -186,9 +230,10 @@
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="first-install-prompt"
|
||||
>Install REA and connect it to this coding agent using npx
|
||||
rea-agents@latest setup. Show me the setup plan for approval,
|
||||
then verify the installation.</span
|
||||
>Install REA and connect it to this coding agent using
|
||||
<span translate="no">npx rea-agents@latest setup</span>. Show
|
||||
me the setup plan for approval, then verify the
|
||||
installation.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -235,11 +280,14 @@
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="first-analysis-prompt"
|
||||
>Download https://rea.tools/examples/notes-example.zip into a
|
||||
new example folder and unpack it. Use REA to find what happens
|
||||
when I click Export notes. Show where notes.csv is written,
|
||||
which fields it contains, and the relevant files and
|
||||
lines.</span
|
||||
>Download
|
||||
<span translate="no"
|
||||
>https://rea.tools/examples/notes-example.zip</span
|
||||
>
|
||||
into a new example folder and unpack it. Use REA to find what
|
||||
happens when I click Export notes. Show where
|
||||
<span translate="no">notes.csv</span> is written, which fields
|
||||
it contains, and the relevant files and lines.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -276,22 +324,26 @@
|
|||
<p class="figure-title">From the button to the file writer</p>
|
||||
<ol class="flow-steps">
|
||||
<li>
|
||||
<span class="flow-label">Page · renderer.js</span
|
||||
<span class="flow-label"
|
||||
>Page · <span translate="no">renderer.js</span></span
|
||||
><span class="flow-node">Export notes</span
|
||||
><span class="flow-note"
|
||||
>Calls <code>notes.exportCsv()</code>.</span
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="flow-label">Bridge · preload.js</span
|
||||
<span class="flow-label"
|
||||
>Bridge · <span translate="no">preload.js</span></span
|
||||
><span class="flow-node"><code>notes:export</code></span
|
||||
><span class="flow-note"
|
||||
>Sends a named message to the main process.</span
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="flow-label">Handler · main.js</span
|
||||
><span class="flow-node">Write notes.csv</span
|
||||
<span class="flow-label"
|
||||
>Handler · <span translate="no">main.js</span></span
|
||||
><span class="flow-node"
|
||||
>Write <span translate="no">notes.csv</span></span
|
||||
><span class="flow-note"
|
||||
>Calls the formatter in <code>csv.js</code> and writes the
|
||||
file.</span
|
||||
|
|
@ -305,7 +357,7 @@
|
|||
</figure>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>main.js · lines 8–12</span
|
||||
<span><span translate="no">main.js</span> · lines 8–12</span
|
||||
><a href="../examples/notes-electron/main.js">Source</a>
|
||||
</div>
|
||||
<pre><code>ipcMain.handle("notes:export", () => {
|
||||
|
|
@ -350,9 +402,11 @@
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="first-check-prompt"
|
||||
>Predict the CSV for a note with id 1 and title Hello, "REA".
|
||||
Then run the example’s toCsv formatter with Node.js to check
|
||||
it. Show the prediction and actual output.</span
|
||||
>Predict the CSV for a note with id 1 and title
|
||||
<span translate="no">Hello, "REA"</span>. Then run the
|
||||
example’s <span translate="no">toCsv</span> formatter with
|
||||
<span translate="no">Node.js</span> to check it. Show the
|
||||
prediction and actual output.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -365,7 +419,8 @@
|
|||
</div>
|
||||
<p>
|
||||
The title stays in one quoted field; each quotation mark is
|
||||
doubled. This checks the formatter directly with Node.js.
|
||||
doubled. This checks the formatter directly with
|
||||
<span translate="no">Node.js</span>.
|
||||
</p>
|
||||
<details class="evidence-details">
|
||||
<summary>Run the check yourself</summary>
|
||||
|
|
@ -375,7 +430,8 @@
|
|||
</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Node.js · CSV formatter</span
|
||||
<span
|
||||
><span translate="no">Node.js</span> · CSV formatter</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/get-started/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/get-started/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/get-started/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../get-started/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../zh-CN/get-started/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../zh-TW/get-started/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../ja/get-started/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../ko/get-started/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../tr/get-started/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../ru/get-started/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../vi/get-started/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../th/get-started/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../de/get-started/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../es/get-started/" lang="es" dir="ltr" data-language="es">Español</a><a href="../fr/get-started/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../uk/get-started/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../pl/get-started/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../pt-BR/get-started/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../ar/get-started/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../fa/get-started/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../id/get-started/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../it/get-started/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -142,11 +185,13 @@
|
|||
terminal.
|
||||
</p>
|
||||
<p class="requirements">
|
||||
You'll need Node.js 22 (22.19+), 24 (24.11+) or 26+. npm comes with
|
||||
Node.js.
|
||||
You'll need <span translate="no">Node.js</span> 22 (22.19+), 24
|
||||
(24.11+) or 26+. npm comes with <span translate="no">Node.js</span>.
|
||||
</p>
|
||||
<details class="evidence-details" id="install-node">
|
||||
<summary>Don't have Node.js, or not sure?</summary>
|
||||
<summary>
|
||||
Don't have <span translate="no">Node.js</span>, or not sure?
|
||||
</summary>
|
||||
<p>Open a terminal and check:</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
|
|
@ -166,7 +211,7 @@ npm -v</code></pre>
|
|||
<p>
|
||||
If <code>node -v</code> prints v22.19+, v24.11+ or v26+, you're
|
||||
ready. If it prints an older version or "not recognized" / "command
|
||||
not found", install Node.js 24 LTS:
|
||||
not found", install <span translate="no">Node.js</span> 24 LTS:
|
||||
</p>
|
||||
<p><strong>Windows (PowerShell)</strong></p>
|
||||
<div class="code-block">
|
||||
|
|
@ -374,9 +419,10 @@ fnm default 24</code></pre>
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="agent-install-prompt"
|
||||
>Install REA and connect it to this coding agent using npx
|
||||
rea-agents@latest setup. Show me the setup plan for approval,
|
||||
then verify the installation.</span
|
||||
>Install REA and connect it to this coding agent using
|
||||
<span translate="no">npx rea-agents@latest setup</span>. Show
|
||||
me the setup plan for approval, then verify the
|
||||
installation.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/guides/browser/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/guides/browser/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/guides/browser/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../guides/browser/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/guides/browser/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/guides/browser/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/guides/browser/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/guides/browser/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/guides/browser/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/guides/browser/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/guides/browser/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/guides/browser/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/guides/browser/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/guides/browser/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/guides/browser/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/guides/browser/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/guides/browser/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/guides/browser/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/guides/browser/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/guides/browser/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/guides/browser/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/guides/browser/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -382,7 +425,10 @@
|
|||
</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>export.js · example source excerpt</span>
|
||||
<span
|
||||
><span translate="no">export.js</span> · example source
|
||||
excerpt</span
|
||||
>
|
||||
</div>
|
||||
<pre><code>const response = await fetch("./notes.json");
|
||||
const { notes } = await response.json();
|
||||
|
|
@ -400,11 +446,11 @@ link.click();</code></pre>
|
|||
<p>
|
||||
<a href="../../examples/notes-web/">Open the example</a> ·
|
||||
<a href="../../examples/notes-web/export.js" download
|
||||
>Download export.js</a
|
||||
>Download <span translate="no">export.js</span></a
|
||||
>
|
||||
·
|
||||
<a href="../../examples/notes-web/notes.json" download
|
||||
>Download notes.json</a
|
||||
>Download <span translate="no">notes.json</span></a
|
||||
>
|
||||
</p>
|
||||
<blockquote class="prompt">
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/guides/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/guides/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/guides/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../guides/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../zh-CN/guides/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../zh-TW/guides/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../ja/guides/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../ko/guides/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../tr/guides/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../ru/guides/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../vi/guides/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../th/guides/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../de/guides/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../es/guides/" lang="es" dir="ltr" data-language="es">Español</a><a href="../fr/guides/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../uk/guides/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../pl/guides/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../pt-BR/guides/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../ar/guides/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../fa/guides/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../id/guides/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../it/guides/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/guides/javascript/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/guides/javascript/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/guides/javascript/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../guides/javascript/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/guides/javascript/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/guides/javascript/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/guides/javascript/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/guides/javascript/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/guides/javascript/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/guides/javascript/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/guides/javascript/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/guides/javascript/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/guides/javascript/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/guides/javascript/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/guides/javascript/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/guides/javascript/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/guides/javascript/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/guides/javascript/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/guides/javascript/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/guides/javascript/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/guides/javascript/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/guides/javascript/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -250,7 +293,10 @@
|
|||
<h3>The page calls a small API</h3>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>renderer.js · example source</span>
|
||||
<span
|
||||
><span translate="no">renderer.js</span> · example
|
||||
source</span
|
||||
>
|
||||
</div>
|
||||
<pre><code>document.querySelector("#export").addEventListener("click", async () => {
|
||||
const destination = await window.notes.exportCsv();
|
||||
|
|
@ -263,7 +309,9 @@
|
|||
</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>preload.js · example source</span>
|
||||
<span
|
||||
><span translate="no">preload.js</span> · example source</span
|
||||
>
|
||||
</div>
|
||||
<pre><code>contextBridge.exposeInMainWorld("notes", {
|
||||
exportCsv: () => ipcRenderer.invoke("notes:export"),
|
||||
|
|
@ -276,7 +324,9 @@
|
|||
</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>main.js · example source</span>
|
||||
<span
|
||||
><span translate="no">main.js</span> · example source</span
|
||||
>
|
||||
</div>
|
||||
<pre><code>ipcMain.handle("notes:export", () => {
|
||||
const destination = path.join(app.getPath("downloads"), "notes.csv");
|
||||
|
|
@ -311,7 +361,8 @@
|
|||
<p>
|
||||
Download the example and unzip it. The archive contains the
|
||||
complete <code>notes-example</code> folder. Analyze it with
|
||||
Node.js and npm; Electron is not needed for this example.
|
||||
<span translate="no">Node.js</span> and npm; Electron is not
|
||||
needed for this example.
|
||||
</p>
|
||||
<p>
|
||||
<a
|
||||
|
|
@ -326,32 +377,32 @@
|
|||
<ul class="example-files">
|
||||
<li>
|
||||
<a href="../../examples/notes-electron/package.json" download
|
||||
>package.json</a
|
||||
><span translate="no">package.json</span></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="../../examples/notes-electron/main.js" download
|
||||
>main.js</a
|
||||
><span translate="no">main.js</span></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="../../examples/notes-electron/preload.js" download
|
||||
>preload.js</a
|
||||
><span translate="no">preload.js</span></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="../../examples/notes-electron/renderer.js" download
|
||||
>renderer.js</a
|
||||
><span translate="no">renderer.js</span></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="../../examples/notes-electron/csv.js" download
|
||||
>csv.js</a
|
||||
><span translate="no">csv.js</span></a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="../../examples/notes-electron/index.html" download
|
||||
>index.html</a
|
||||
><span translate="no">index.html</span></a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/guides/native/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/guides/native/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/guides/native/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../guides/native/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/guides/native/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/guides/native/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/guides/native/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/guides/native/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/guides/native/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/guides/native/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/guides/native/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/guides/native/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/guides/native/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/guides/native/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/guides/native/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/guides/native/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/guides/native/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/guides/native/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/guides/native/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/guides/native/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/guides/native/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/guides/native/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -52,7 +94,7 @@
|
|||
<link rel="icon" href="assets/favicon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="assets/styles.css" />
|
||||
<script src="assets/main.js" defer></script>
|
||||
<script src="assets/home.js" defer></script>
|
||||
<script type="module" src="assets/home.js"></script>
|
||||
<script type="module" src="assets/dino-demo.js"></script>
|
||||
</head>
|
||||
<body class="home-page" id="top">
|
||||
|
|
@ -63,7 +105,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="./" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="./showcase/">Showcases</a>
|
||||
|
|
@ -73,6 +115,7 @@
|
|||
<a href="./faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="./" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="./zh-CN/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="./zh-TW/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="./ja/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="./ko/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="./tr/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="./ru/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="./vi/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="./th/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="./de/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="./es/" lang="es" dir="ltr" data-language="es">Español</a><a href="./fr/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="./uk/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="./pl/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="./pt-BR/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="./ar/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="./fa/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="./id/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="./it/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -208,9 +251,10 @@
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="home-install-prompt"
|
||||
>Install REA and connect it to this coding agent using npx
|
||||
rea-agents@latest setup. Show me the setup plan for approval,
|
||||
then verify the installation.</span
|
||||
>Install REA and connect it to this coding agent using
|
||||
<span translate="no">npx rea-agents@latest setup</span>. Show
|
||||
me the setup plan for approval, then verify the
|
||||
installation.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -230,7 +274,8 @@
|
|||
Approve the setup plan, then restart your agent.
|
||||
</p>
|
||||
<p class="home-expert-shortcut">
|
||||
First time, or missing Node.js or a coding agent?
|
||||
First time, or missing <span translate="no">Node.js</span> or a
|
||||
coding agent?
|
||||
<a href="get-started/">Follow the step-by-step setup guide →</a>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -254,7 +299,10 @@
|
|||
</p>
|
||||
<p class="comparison-question">
|
||||
One question:
|
||||
<strong>why does Calculator give 220 for 200 + 10%?</strong>
|
||||
<strong
|
||||
>why does Calculator give 220 for
|
||||
<span translate="no">200 + 10%</span>?</strong
|
||||
>
|
||||
</p>
|
||||
<figure class="home-role-comparison" id="how-rea-helps">
|
||||
<div
|
||||
|
|
@ -440,8 +488,8 @@
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="home-analysis-prompt"
|
||||
>Use REA to inspect Windows Calculator. Why does 200 + 10%
|
||||
give 220?</span
|
||||
>Use REA to inspect Windows Calculator. Why does
|
||||
<span translate="no">200 + 10%</span> give 220?</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
<div class="agent-reply">
|
||||
|
|
@ -622,7 +670,10 @@
|
|||
</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>REA · loaded index.js · selected lines</span>
|
||||
<span
|
||||
>REA · loaded <span translate="no">index.js</span> ·
|
||||
selected lines</span
|
||||
>
|
||||
</div>
|
||||
<pre><code>if (this.currentSpeed < this.config.MAX_SPEED) {
|
||||
<span class="code-key">this.currentSpeed += this.config.ACCELERATION;</span>
|
||||
|
|
@ -724,8 +775,9 @@ SPEED: 6</code></pre>
|
|||
<p class="eyebrow">Example 02 · Windows Calculator</p>
|
||||
<h2>Rebuild Calculator’s % button.</h2>
|
||||
<p class="lede">
|
||||
We saw why <strong>200 + 10% gives 220.</strong> Now let’s recover
|
||||
the rules for both + and ×, and try them.
|
||||
We saw why
|
||||
<strong><span translate="no">200 + 10%</span> gives 220.</strong>
|
||||
Now let’s recover the rules for both + and ×, and try them.
|
||||
</p>
|
||||
</div>
|
||||
<dl class="case-brief">
|
||||
|
|
@ -759,14 +811,14 @@ SPEED: 6</code></pre>
|
|||
data-percent-operation="add"
|
||||
aria-pressed="true"
|
||||
>
|
||||
200 + 10%
|
||||
<span translate="no">200 + 10%</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-percent-operation="multiply"
|
||||
aria-pressed="false"
|
||||
>
|
||||
200 × 10%
|
||||
<span translate="no">200 × 10%</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="percent-display">
|
||||
|
|
@ -880,7 +932,8 @@ SPEED: 6</code></pre>
|
|||
</p>
|
||||
<ol class="flow-steps">
|
||||
<li>
|
||||
<span class="flow-label">01 · REA reads calc.exe</span
|
||||
<span class="flow-label"
|
||||
>01 · REA reads <span translate="no">calc.exe</span></span
|
||||
><span class="flow-node">It launches the Calculator app</span
|
||||
><span class="flow-note"
|
||||
>The code opens <code>ms-calculator:</code>. The agent then
|
||||
|
|
@ -1001,8 +1054,9 @@ SPEED: 6</code></pre>
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="website-project-prompt"
|
||||
>Use REA to inspect https://rea.tools/. Clone this website
|
||||
for me.</span
|
||||
>Use REA to inspect
|
||||
<span translate="no">https://rea.tools/</span>. Clone this
|
||||
website for me.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/showcase/aegis/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/showcase/aegis/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/showcase/aegis/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -62,7 +104,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/" aria-current="page">Showcases</a>
|
||||
|
|
@ -72,6 +114,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../showcase/aegis/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/showcase/aegis/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/showcase/aegis/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/showcase/aegis/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/showcase/aegis/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/showcase/aegis/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/showcase/aegis/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/showcase/aegis/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/showcase/aegis/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/showcase/aegis/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/showcase/aegis/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/showcase/aegis/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/showcase/aegis/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/showcase/aegis/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/showcase/aegis/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/showcase/aegis/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/showcase/aegis/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/showcase/aegis/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/showcase/aegis/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -222,10 +265,11 @@
|
|||
<p class="terminal-prompt">
|
||||
<span class="prompt-symbol" aria-hidden="true">›</span
|
||||
><span id="aegis-prompt"
|
||||
>Use REA to inspect aegis-v3.4.3.apk. Find how it generates
|
||||
the six-digit login code, explain why it changes every 30
|
||||
seconds, and rebuild a small demo where I can change the
|
||||
time.</span
|
||||
>Use REA to inspect aegis-v3.4.<span translate="no"
|
||||
>3.apk</span
|
||||
>. Find how it generates the six-digit login code, explain why
|
||||
it changes every 30 seconds, and rebuild a small demo where I
|
||||
can change the time.</span
|
||||
><span class="terminal-cursor" aria-hidden="true"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/showcase/ctf/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/showcase/ctf/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/showcase/ctf/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/" aria-current="page">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../showcase/ctf/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/showcase/ctf/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/showcase/ctf/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/showcase/ctf/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/showcase/ctf/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/showcase/ctf/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/showcase/ctf/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/showcase/ctf/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/showcase/ctf/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/showcase/ctf/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/showcase/ctf/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/showcase/ctf/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/showcase/ctf/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/showcase/ctf/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/showcase/ctf/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/showcase/ctf/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/showcase/ctf/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/showcase/ctf/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/showcase/ctf/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/showcase/dx-ball/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/showcase/dx-ball/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/showcase/dx-ball/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/" aria-current="page">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../showcase/dx-ball/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/showcase/dx-ball/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/showcase/dx-ball/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/showcase/dx-ball/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/showcase/dx-ball/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/showcase/dx-ball/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/showcase/dx-ball/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/showcase/dx-ball/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/showcase/dx-ball/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/showcase/dx-ball/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/showcase/dx-ball/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/showcase/dx-ball/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/showcase/dx-ball/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/showcase/dx-ball/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/showcase/dx-ball/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/showcase/dx-ball/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/showcase/dx-ball/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/showcase/dx-ball/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/showcase/dx-ball/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/showcase/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/showcase/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/showcase/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../showcase/" aria-current="page">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../showcase/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../zh-CN/showcase/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../zh-TW/showcase/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../ja/showcase/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../ko/showcase/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../tr/showcase/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../ru/showcase/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../vi/showcase/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../th/showcase/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../de/showcase/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../es/showcase/" lang="es" dir="ltr" data-language="es">Español</a><a href="../fr/showcase/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../uk/showcase/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../pl/showcase/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../pt-BR/showcase/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../ar/showcase/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../fa/showcase/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../id/showcase/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../it/showcase/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/showcase/notion/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/showcase/notion/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/showcase/notion/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/" aria-current="page">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../showcase/notion/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/showcase/notion/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/showcase/notion/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/showcase/notion/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/showcase/notion/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/showcase/notion/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/showcase/notion/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/showcase/notion/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/showcase/notion/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/showcase/notion/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/showcase/notion/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/showcase/notion/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/showcase/notion/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/showcase/notion/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/showcase/notion/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/showcase/notion/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/showcase/notion/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/showcase/notion/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/showcase/notion/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
@ -283,7 +326,9 @@ source: preload.js:1:6486–6522</code></pre>
|
|||
<h4>Start at the API exposed to the page</h4>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>tab_browser_view/preload.js · API member</span
|
||||
<span
|
||||
>tab_browser_view/<span translate="no">preload.js</span> ·
|
||||
API member</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
|
|
@ -310,7 +355,9 @@ source: preload.js:1:6486–6522</code></pre>
|
|||
<h4>Resolve the preload's wrapper</h4>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>tab_browser_view/preload.js · IPC helper</span
|
||||
<span
|
||||
>tab_browser_view/<span translate="no">preload.js</span> ·
|
||||
IPC helper</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
|
|
@ -339,7 +386,9 @@ function invokeInMainAndReturnResult(channel, ...args) {
|
|||
<h4>Check how the receiver is registered</h4>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>main/index.js · handler helper</span
|
||||
<span
|
||||
>main/<span translate="no">index.js</span> · handler
|
||||
helper</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
|
|
@ -365,7 +414,9 @@ function invokeInMainAndReturnResult(channel, ...args) {
|
|||
<h4>Find the write and its sender check</h4>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>main/index.js · clipboard receiver</span
|
||||
<span
|
||||
>main/<span translate="no">index.js</span> · clipboard
|
||||
receiver</span
|
||||
><button
|
||||
class="copy-button"
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,48 @@
|
|||
<!-- website:sharing:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="https://rea.tools/showcase/th04/" />
|
||||
<!-- website:languages:start -->
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="en" href="https://rea.tools/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-CN" href="https://rea.tools/zh-CN/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="zh-TW" href="https://rea.tools/zh-TW/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ja" href="https://rea.tools/ja/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ko" href="https://rea.tools/ko/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="tr" href="https://rea.tools/tr/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ru" href="https://rea.tools/ru/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="vi" href="https://rea.tools/vi/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="th" href="https://rea.tools/th/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="de" href="https://rea.tools/de/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="es" href="https://rea.tools/es/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fr" href="https://rea.tools/fr/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="uk" href="https://rea.tools/uk/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pl" href="https://rea.tools/pl/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="pt-BR" href="https://rea.tools/pt-BR/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="ar" href="https://rea.tools/ar/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="fa" href="https://rea.tools/fa/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="id" href="https://rea.tools/id/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="it" href="https://rea.tools/it/showcase/th04/" />
|
||||
<!-- prettier-ignore -->
|
||||
<link rel="alternate" hreflang="x-default" href="https://rea.tools/showcase/th04/" />
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
@ -61,7 +103,7 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="../../" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">
|
||||
<a href="../../showcase/" aria-current="page">Showcases</a>
|
||||
|
|
@ -71,6 +113,7 @@
|
|||
<a href="../../faq/">FAQ</a>
|
||||
</nav>
|
||||
<div class="header-social">
|
||||
<details class="language-picker" data-i18n-skip><summary><span aria-hidden="true">文 / A</span> <span>English</span></summary><nav aria-label="English"><a href="../../showcase/th04/" lang="en" dir="ltr" data-language="en" aria-current="true">English</a><a href="../../zh-CN/showcase/th04/" lang="zh-CN" dir="ltr" data-language="zh-CN">简体中文</a><a href="../../zh-TW/showcase/th04/" lang="zh-TW" dir="ltr" data-language="zh-TW">繁體中文</a><a href="../../ja/showcase/th04/" lang="ja" dir="ltr" data-language="ja">日本語</a><a href="../../ko/showcase/th04/" lang="ko" dir="ltr" data-language="ko">한국어</a><a href="../../tr/showcase/th04/" lang="tr" dir="ltr" data-language="tr">Türkçe</a><a href="../../ru/showcase/th04/" lang="ru" dir="ltr" data-language="ru">Русский</a><a href="../../vi/showcase/th04/" lang="vi" dir="ltr" data-language="vi">Tiếng Việt</a><a href="../../th/showcase/th04/" lang="th" dir="ltr" data-language="th">ไทย</a><a href="../../de/showcase/th04/" lang="de" dir="ltr" data-language="de">Deutsch</a><a href="../../es/showcase/th04/" lang="es" dir="ltr" data-language="es">Español</a><a href="../../fr/showcase/th04/" lang="fr" dir="ltr" data-language="fr">Français</a><a href="../../uk/showcase/th04/" lang="uk" dir="ltr" data-language="uk">Українська</a><a href="../../pl/showcase/th04/" lang="pl" dir="ltr" data-language="pl">Polski</a><a href="../../pt-BR/showcase/th04/" lang="pt-BR" dir="ltr" data-language="pt-BR">Português (Brasil)</a><a href="../../ar/showcase/th04/" lang="ar" dir="rtl" data-language="ar">العربية</a><a href="../../fa/showcase/th04/" lang="fa" dir="rtl" data-language="fa">فارسی</a><a href="../../id/showcase/th04/" lang="id" dir="ltr" data-language="id">Bahasa Indonesia</a><a href="../../it/showcase/th04/" lang="it" dir="ltr" data-language="it">Italiano</a></nav></details>
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -1,2 +1,4 @@
|
|||
# SVG-to-PNG conversion for the generated social preview.
|
||||
CairoSVG==2.9.1
|
||||
# Standard gettext PO/POT catalogs; no translation service is used by builds.
|
||||
polib==1.2.0
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ fold. Keep the main path short and let readers open the supporting details.
|
|||
|
||||
## Write the task directly
|
||||
|
||||
Write the English source first. Keep translated wording just as concrete: a
|
||||
reader should understand the question, the evidence and the next action without
|
||||
decoding a literal translation. Preserve commands, code and recorded values.
|
||||
Read a whole example together when reviewing its translation. Check headings,
|
||||
figures and interactive labels at phone widths, including right-to-left editions.
|
||||
The [translation guide](locales/README.md) explains the catalogs and update process.
|
||||
|
||||
Name the software, behavior or action in headings. Give the opening paragraph
|
||||
one job: explain what the page covers. Use concrete verbs such as install, trace,
|
||||
read, compare and calculate.
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
<div class="container header-inner">
|
||||
<a class="brand" href="$base" aria-label="REA home"
|
||||
><span class="brand-name">REA</span
|
||||
><span class="brand-caption">Reverse Engineer Anything</span></a
|
||||
><span class="brand-caption" data-i18n-skip>Reverse Engineer Anything</span></a
|
||||
>
|
||||
<nav class="navigation" aria-label="Main navigation">$navigation</nav>
|
||||
<div class="header-social">
|
||||
$language_picker
|
||||
<a
|
||||
class="nav-github"
|
||||
href="https://github.com/morluto/rea"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
<!-- prettier-ignore -->
|
||||
<link rel="canonical" href="$canonical" />
|
||||
<!-- website:languages:start -->
|
||||
$alternates
|
||||
<!-- website:languages:end -->
|
||||
<!-- prettier-ignore -->
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- prettier-ignore -->
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ workers_dev = true
|
|||
preview_urls = false
|
||||
|
||||
[assets]
|
||||
directory = "./public"
|
||||
directory = "./_site"
|
||||
html_handling = "auto-trailing-slash"
|
||||
not_found_handling = "none"
|
||||
|
||||
[build]
|
||||
cwd = ".."
|
||||
command = "python3 scripts/website.py check"
|
||||
watch_dir = "./public/examples/notes-electron"
|
||||
watch_dir = ["./public", "./locales", "./templates"]
|
||||
|
||||
# Public HTTPS depends on zone activation and certificate readiness.
|
||||
[env.production]
|
||||
|
|
|
|||
Loading…
Reference in New Issue