# TAKEOVER - AI Takeover Simulator for DOS
# Build with OpenWatcom 2.0: wmake
#
# Prerequisites:
#   - OpenWatcom 2.0 installed (WATCOM env var set)
#   - NASM (optional, for future assembly modules)

CC = wcc
LD = wlink
ASM = nasm

# OpenWatcom flags:
#   -0    8088 instructions only (maximum compatibility)
#   -fpi  inline 8087 emulation (no coprocessor required)
#   -ms   small memory model
#   -s    remove stack overflow checks
#   -ox   maximum optimization
#   -w4   maximum warnings
#   -zq   quiet mode
#   -bt=dos  target DOS
CFLAGS = -0 -fpi -ms -s -ox -w4 -zq -bt=dos

# Include paths
# src/engine and src/shell are Phase 1+ destinations; no compiled TUs yet,
# but the include paths land here so future engine/shell headers are reachable.
CFLAGS += -i=src -i=src/engine -i=src/shell -i=lib

# Phase 3 build target split: TAKEOVER.EXE (production) links
# src\shell\news_req.obj; RUNTESTS.EXE links src\tests\news_stub.obj
# IN PLACE OF news_req.obj. Exactly one is linked per binary. The
# divergence is deliberate; see docs/plans/2026-05-16-takeover-v2-phase3-plan.md
# Task 12 and design.md section D3 lines 664-678.
#
# Shared object list (no news TU). The production and test
# Makefiles each add their own news TU to this set.
SHELL_OBJS = src\engine\events.obj src\engine\far_util.obj &
             src\engine\meta.obj src\engine\engine_themes.obj &
             src\engine\engine_request.obj src\shell\consumer.obj &
             src\shell\cursor.obj src\shell\tag_table.obj &
             src\shell\word_wrap.obj src\shell\theme_apply.obj &
             src\shell\theme_state.obj src\shell\delay.obj &
             src\shell\text_emit.obj src\shell\scrollback.obj &
             src\shell\audio.obj src\shell\effects.obj &
             src\shell\transitions.obj src\shell\attr.obj &
             src\shell\input.obj src\shell\overlay.obj &
             src\shell\menu_card.obj src\shell\menu_cards.obj &
             src\shell\menu_save.obj src\shell\status_bar.obj &
             src\shell\dat_io.obj src\shell\achievements_copy.obj

# Phase 7: src\audio.c and src\effects.c deleted (migrated to src\shell\).
# Phase 10 subcommit 3: src\menu.c + src\menu.h DELETED from disk.
# Save helpers migrated to src\shell\menu_save.c.
OBJS = src\main.obj src\engine.obj &
       src\news.obj src\display.obj src\hwdetect.obj &
       src\vga13h.obj src\title.obj src\adlib.obj src\climax.obj &
       src\cracktro.obj lib\screen.obj $(SHELL_OBJS) &
       src\shell\news_req.obj

# Target
TARGET = TAKEOVER.EXE

all: $(TARGET) .SYMBOLIC

# Explicit compilation rules (wmake inference rules are fragile across dirs)
src\main.obj: src\main.c src\engine.h src\shell\effects.h src\shell\audio.h src\shell\menu_save.h src\shell\menu_card.h src\shell\dat_io.h src\hwdetect.h src\title.h src\cracktro.h src\shell\consumer.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\main.c

# engine.obj: events.h + consumer.h listed defensively. engine.c is the
# most likely TU to pull in these Phase 2+ headers; wmake doesn't auto-track
# header deps, so a struct change there without rebuilding engine.obj would
# silently desync. Other TUs add these only when they actually #include them.
src\engine.obj: src\engine.c src\engine.h src\shell\effects.h src\shell\audio.h src\shell\attr.h src\adlib.h src\hwdetect.h lib\screen.h src\engine\events.h src\engine\far_util.h src\engine\engine_meta.h src\engine\engine_themes.h src\engine\engine_request.h src\engine\pool_access.h src\shell\consumer.h
	$(CC) $(CFLAGS) -fo=$^@ src\engine.c

src\news.obj: src\news.c src\news.h
	$(CC) $(CFLAGS) -fo=$^@ src\news.c

src\display.obj: src\display.c src\display.h src\hwdetect.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\display.c

src\hwdetect.obj: src\hwdetect.c src\hwdetect.h
	$(CC) $(CFLAGS) -fo=$^@ src\hwdetect.c

src\vga13h.obj: src\vga13h.c src\vga13h.h src\shell\audio.h
	$(CC) $(CFLAGS) -fo=$^@ src\vga13h.c

src\title.obj: src\title.c src\title.h src\vga13h.h src\hwdetect.h src\engine.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\title.c

src\adlib.obj: src\adlib.c src\adlib.h
	$(CC) $(CFLAGS) -fo=$^@ src\adlib.c

src\climax.obj: src\climax.c src\climax.h src\vga13h.h src\engine.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\climax.c

src\cracktro.obj: src\cracktro.c src\cracktro.h src\vga13h.h src\adlib.h src\engine.h src\hwdetect.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\cracktro.c

lib\screen.obj: lib\screen.c lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ lib\screen.c

src\engine\events.obj: src\engine\events.c src\engine\events.h
	$(CC) $(CFLAGS) -fo=$^@ src\engine\events.c

src\engine\far_util.obj: src\engine\far_util.c src\engine\far_util.h
	$(CC) $(CFLAGS) -fo=$^@ src\engine\far_util.c

src\engine\meta.obj: src\engine\meta.c src\engine\meta.h src\engine\engine_meta.h src\engine\engine_themes.h
	$(CC) $(CFLAGS) -fo=$^@ src\engine\meta.c

src\engine\engine_themes.obj: src\engine\engine_themes.c src\engine\engine_themes.h
	$(CC) $(CFLAGS) -fo=$^@ src\engine\engine_themes.c



src\engine\engine_request.obj: src\engine\engine_request.c src\engine\engine_request.h
	$(CC) $(CFLAGS) -fo=$^@ src\engine\engine_request.c

src\shell\consumer.obj: src\shell\consumer.c src\shell\consumer.h src\engine\events.h src\shell\news_req.h src\shell\cursor.h src\shell\tag_table.h src\shell\word_wrap.h src\shell\theme_state.h src\shell\theme_apply.h src\shell\text_emit.h src\shell\delay.h src\shell\scrollback.h src\shell\effects.h src\shell\transitions.h src\shell\input.h src\shell\status_bar.h src\shell\dat_io.h src\engine\engine_themes.h src\engine\pool_access.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\consumer.c

src\shell\news_req.obj: src\shell\news_req.c src\shell\news_req.h src\engine\engine_request.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\news_req.c

# Phase 4 D5 foundation: dormant shell modules. Each is anchored
# from shell_init() in consumer.c so the linker keeps the .obj.
src\shell\cursor.obj: src\shell\cursor.c src\shell\cursor.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\cursor.c

src\shell\tag_table.obj: src\shell\tag_table.c src\shell\tag_table.h src\engine\pool_access.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\tag_table.c

src\shell\word_wrap.obj: src\shell\word_wrap.c src\shell\word_wrap.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\word_wrap.c

# Phase 5 D4 theming layer.
src\shell\theme_apply.obj: src\shell\theme_apply.c src\shell\theme_apply.h src\engine\engine_themes.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\theme_apply.c

src\shell\theme_state.obj: src\shell\theme_state.c src\shell\theme_state.h src\engine\engine_themes.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\theme_state.c

# Phase 6 subcommit 3 (D5): shell-side wait primitives + text emit dispatch.
# Phase 8: delay.c now includes input.h (shell_input_dispatch_fkey).
src\shell\delay.obj: src\shell\delay.c src\shell\delay.h src\shell\input.h src\shell\overlay.h src\shell\audio.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\delay.c

src\shell\text_emit.obj: src\shell\text_emit.c src\shell\text_emit.h src\shell\cursor.h src\shell\delay.h src\shell\scrollback.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\text_emit.c

# Phase 6 subcommit 5 (D5): scrollback ring with _fmalloc-backed cells +
# index arrays per Phase 6 plan Task 13. Depends on far_util.h for
# normalize_far and lib/screen.h for scr_read_cell.
src\shell\scrollback.obj: src\shell\scrollback.c src\shell\scrollback.h src\shell\overlay.h src\shell\input.h src\engine\far_util.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\scrollback.c

# Phase 7: shell-side audio, effects, transitions, attr (D1, D4, D5).
src\shell\audio.obj: src\shell\audio.c src\shell\audio.h src\shell\delay.h src\shell\status_bar.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\audio.c

src\shell\effects.obj: src\shell\effects.c src\shell\effects.h src\shell\audio.h src\engine.h src\hwdetect.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\effects.c

src\shell\transitions.obj: src\shell\transitions.c src\shell\transitions.h src\shell\effects.h src\shell\audio.h src\engine.h src\hwdetect.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\transitions.c

src\shell\attr.obj: src\shell\attr.c src\shell\attr.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\attr.c

# Phase 8 (D5 lines 286-336): shell-side choice + input + F-key dispatch.
# Phase 10: menu.h dep replaced by shell/menu_save.h; menu_card.h added
# for the F2 dispatch arm.
src\shell\input.obj: src\shell\input.c src\shell\input.h src\shell\audio.h src\shell\delay.h src\shell\cursor.h src\shell\attr.h src\shell\overlay.h src\shell\menu_save.h src\shell\menu_card.h src\shell\status_bar.h src\engine\engine_request.h src\adlib.h src\hwdetect.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\input.c

# Phase 9: shell-side scrollback overlay UI + F1 help.
src\shell\overlay.obj: src\shell\overlay.c src\shell\overlay.h src\shell\input.h src\shell\scrollback.h src\shell\audio.h src\shell\transitions.h src\engine\engine_request.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\overlay.c

# Phase 10: card-gallery main menu (render + nav), per-AI card data,
# and the migrated save helpers (TAKEOVER.DAT load/save + audio
# persist).
src\shell\menu_card.obj: src\shell\menu_card.c src\shell\menu_card.h src\shell\menu_cards.h src\shell\menu_save.h src\shell\attr.h src\shell\audio.h src\shell\input.h src\adlib.h src\hwdetect.h src\cracktro.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\menu_card.c

src\shell\menu_cards.obj: src\shell\menu_cards.c src\shell\menu_cards.h src\shell\menu_card.h src\shell\menu_save.h src\engine\engine_themes.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\menu_cards.c

src\shell\menu_save.obj: src\shell\menu_save.c src\shell\menu_save.h src\shell\dat_io.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\menu_save.c

# Phase 11: live row-24 status bar (D6 lines 1056-1098, roadmap lines
# 373-397). Pure shell consumer of TKE_THEME_CHANGED + adlib/audio
# mute getters; no DGROUP near-data per Cerberus discipline.
src\shell\status_bar.obj: src\shell\status_bar.c src\shell\status_bar.h src\shell\theme_apply.h src\shell\theme_state.h src\shell\audio.h src\adlib.h lib\screen.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\status_bar.c

# Phase 12 (D8 lines 1097-1279, roadmap lines 401-428): TAKEOVER.DAT
# v3 schema, migration, persistence. New shell TU that replaces the
# v1/v2 read/write bodies in src\shell\menu_save.c (subcommit 2).
src\shell\dat_io.obj: src\shell\dat_io.c src\shell\dat_io.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\dat_io.c

# Phase 12 subcommit 3: 24-entry achievement copy table consumed by
# Phase 10's About sub-menu (deferred wire-up). Pure data TU with
# zero DGROUP contribution; the array lives in __far storage.
src\shell\achievements_copy.obj: src\shell\achievements_copy.c src\shell\achievements_copy.h
	$(CC) $(CFLAGS) -fo=$^@ src\shell\achievements_copy.c

$(TARGET): $(OBJS)
	$(LD) system dos name $(TARGET) option statics option map=takeover.map option stack=3072 file { $(OBJS) }

clean: .SYMBOLIC
	-del src\*.obj
	-del src\engine\*.obj
	-del src\shell\*.obj
	-del src\tests\*.obj
	-del lib\*.obj
	-del $(TARGET)
	-del takeover.map
	-del RUNTESTS.EXE
	-del runtests.map
# v2.0.3 C-S6: wmake glob does not catch the sidecar -rt.obj files
# that Makefile.tests writes alongside production .obj files. Spell
# each one out so `wmake clean` deletes all 34 -rt.obj sidecars
# (v2.0.4 C5: the v2.0.3 comment said "30" but the actual count was
# already 34 at v2.0.3 time; counted comment corrected).
# Keep alphabetized by parent directory; if a new sidecar lands in
# Makefile.tests OBJS_RUNTESTS, add it here too.
	-del src\adlib-rt.obj
	-del src\climax-rt.obj
	-del src\cracktro-rt.obj
	-del src\display-rt.obj
	-del src\engine-rt.obj
	-del src\hwdetect-rt.obj
	-del src\news-rt.obj
	-del src\screen-rt.obj
	-del src\title-rt.obj
	-del src\vga13h-rt.obj
	-del src\engine\engine_request-rt.obj
	-del src\engine\engine_themes-rt.obj
	-del src\engine\events-rt.obj
	-del src\engine\far_util-rt.obj
	-del src\engine\meta-rt.obj
	-del src\shell\attr-rt.obj
	-del src\shell\audio-rt.obj
	-del src\shell\consumer-rt.obj
	-del src\shell\cursor-rt.obj
	-del src\shell\delay-rt.obj
	-del src\shell\effects-rt.obj
	-del src\shell\input-rt.obj
	-del src\shell\menu_card-rt.obj
	-del src\shell\menu_cards-rt.obj
	-del src\shell\menu_save-rt.obj
	-del src\shell\overlay-rt.obj
	-del src\shell\scrollback-rt.obj
	-del src\shell\tag_table-rt.obj
	-del src\shell\text_emit-rt.obj
	-del src\shell\theme_apply-rt.obj
	-del src\shell\theme_state-rt.obj
	-del src\shell\transitions-rt.obj
	-del src\shell\word_wrap-rt.obj
	-del src\shell\achievements_copy-rt.obj

# Per-TU DGROUP audit. dgroup-report is informational; dgroup-check
# enforces invariant I2 (zero DGROUP near-data from src/shell TUs) and
# exits non-zero on violation. See tools/dgroup-report/README.md.
dgroup-report: $(TARGET) .SYMBOLIC
	py -3 tools\dgroup-report\dgroup-report.py takeover.map

dgroup-check: $(TARGET) .SYMBOLIC
	py -3 tools\dgroup-report\dgroup-report.py takeover.map --enforce-shell-zero

# Keyword-parity gate: design doc Appendix A versus engine.c parser
# strcmp ladder. Fails build on drift. See tools/keyword-parity/README.md.
keyword-parity: .SYMBOLIC
	py -3 tools\keyword-parity\keyword-parity.py

# Normalize-far gate (Phase 2 D2): enforces the _fmalloc/normalize_far
# pairing invariant before the first _fmalloc call site lands in
# Phase 3. Returns OK vacuously today; from Phase 3 onward it fails the
# build on any drift. See tools/normalize-far-check/README.md.
normalize-far-check: .SYMBOLIC
	py -3 tools\normalize-far-check\check_normalize_far.py

# Phase 1 meta-gate: runs all Phase 1 enforcement checks in sequence.
# Builds TAKEOVER.EXE first so the .map is fresh.
phase1-gate: $(TARGET) .SYMBOLIC
	@echo === Phase 1 gates ===
	py -3 tools\dgroup-report\dgroup-report.py takeover.map --enforce-shell-zero
	py -3 tools\keyword-parity\keyword-parity.py
	@echo === Phase 1 gates: PASS ===

# Phase 2 meta-gate: Phase 1 gates plus normalize-far-check, and runs
# the check's self-test once so the gate stays exercised even when no
# _fmalloc call sites exist yet.
phase2-gate: $(TARGET) .SYMBOLIC
	@echo === Phase 2 gates ===
	py -3 tools\dgroup-report\dgroup-report.py takeover.map --enforce-shell-zero
	py -3 tools\keyword-parity\keyword-parity.py
	py -3 tools\normalize-far-check\check_normalize_far.py --self-test
	py -3 tools\normalize-far-check\check_normalize_far.py
	@echo === Phase 2 gates: PASS ===

# Phase 3 meta-gate: Phase 2 gates plus the now-binding
# normalize-far-check (Phase 3 lands the first production _fmalloc
# call site, so the check is no longer vacuous). The check runs
# against the live source tree without --self-test here; the self-
# test still runs under phase2-gate.
phase3-gate: $(TARGET) .SYMBOLIC
	@echo === Phase 3 gates ===
	py -3 tools\dgroup-report\dgroup-report.py takeover.map --enforce-shell-zero
	py -3 tools\keyword-parity\keyword-parity.py
	py -3 tools\normalize-far-check\check_normalize_far.py --self-test
	py -3 tools\normalize-far-check\check_normalize_far.py
	@echo === Phase 3 gates: PASS ===

# Phase 4 shell-tag-write-check: enforces Phase 4-5 dormancy of
# shell_tag_table. No TU under src/shell/ may write to the table.
# Phase 6 inverts this gate atomically with the g_tags deletion.
shell-tag-write-check: .SYMBOLIC
	py -3 tools\check_shell_tag_writes.py

# Phase 4 meta-gate: Phase 3 gates plus the new dormancy check and
# its self-test. The self-test is run unconditionally so the gate
# stays exercised even on a clean source tree.
phase4-gate: $(TARGET) .SYMBOLIC
	@echo === Phase 4 gates ===
	py -3 tools\dgroup-report\dgroup-report.py takeover.map --enforce-shell-zero
	py -3 tools\keyword-parity\keyword-parity.py
	py -3 tools\normalize-far-check\check_normalize_far.py --self-test
	py -3 tools\normalize-far-check\check_normalize_far.py
	py -3 tools\check_shell_tag_writes.py --self-test
	py -3 tools\check_shell_tag_writes.py
	@echo === Phase 4 gates: PASS ===

# Phase 5 meta-gate: Phase 4 gates plus the new themes-segment audit
# (verifies the themes[] table lands outside DGROUP via the linker
# map). The shell theme-state cells follow the same FAR_DATA
# placement; the dgroup-report --enforce-shell-zero check already
# enforces zero DGROUP near-data from src/shell, which covers the
# theme_state.c discipline.
phase5-gate: $(TARGET) .SYMBOLIC
	@echo === Phase 5 gates ===
	py -3 tools\dgroup-report\dgroup-report.py takeover.map --enforce-shell-zero
	py -3 tools\keyword-parity\keyword-parity.py
	py -3 tools\normalize-far-check\check_normalize_far.py --self-test
	py -3 tools\normalize-far-check\check_normalize_far.py
	py -3 tools\check_shell_tag_writes.py --self-test
	py -3 tools\check_shell_tag_writes.py
	py -3 tools\check_themes_segment.py takeover.map
	py -3 tools\check_theme_state_segment.py takeover.map
	@echo === Phase 5 gates: PASS ===

# Phase 6 meta-gate (subcommit 5 close-out): Phase 5 gates plus the
# inverted shell_tag_table allowlist self-test (already covered by
# phase5-gate; runs again here so the gate is exercised explicitly at
# the Phase 6 acceptance moment), and an acceptance-grep verifying
# g_tags / alloc_tag / find_tag are wholly deleted from src/engine/.
#
# Phase 6.1 S-C5: phase6-gate now also builds RUNTESTS.EXE so unit
# tests cannot silently drift out of sync with the production binary.
# The actual unit-test execution requires DOSBox-Staging and is not
# invoked from wmake (DOSBox orchestration is PowerShell-driven); the
# developer runs `phase6-gate-full` for the full chain or invokes
# tools/run-phase6-tests.ps1 directly. phase6-gate still FAILS LOUDLY
# if RUNTESTS.EXE is missing after the runtests-build dependency
# (catches Makefile.tests breakage).
#
# v2.0.4 C7: dat_io_check.py runs BEFORE runtests-build dependency
# (a structural drift catcher should fail the build fast). Achieved by
# routing through a separate phase6-gate-prebuild prerequisite target
# that depends on $(TARGET) but NOT on runtests-build; dat_io_check
# runs in its recipe. phase6-gate then has runtests-build as its
# remaining dependency, and resumes the rest of the static analyses.
phase6-gate-prebuild: $(TARGET) .SYMBOLIC
	@echo === Phase 6 pre-build static analyses ===
	py -3 tools\dat_io_check.py

phase6-gate: phase6-gate-prebuild runtests-build .SYMBOLIC
	@echo === Phase 6 gates ===
	py -3 tools\dgroup-report\dgroup-report.py takeover.map --enforce-shell-zero
	py -3 tools\keyword-parity\keyword-parity.py
	py -3 tools\normalize-far-check\check_normalize_far.py --self-test
	py -3 tools\normalize-far-check\check_normalize_far.py
	py -3 tools\check_shell_tag_writes.py --self-test
	py -3 tools\check_shell_tag_writes.py
	py -3 tools\check_themes_segment.py --self-test
	py -3 tools\check_themes_segment.py takeover.map
	py -3 tools\check_theme_state_segment.py --self-test
	py -3 tools\check_theme_state_segment.py takeover.map
	py -3 tools\check_no_shell_emit.py --self-test
	py -3 tools\check_no_shell_emit.py
	py -3 tools\phase6-acceptance-grep.py
	py -3 -c "import os,sys;p='RUNTESTS.EXE';sys.exit(0) if os.path.exists(p) else (sys.stderr.write('FAIL: '+p+' missing or not built\n'),sys.exit(1))"
	@echo === Phase 6 gates: PASS ===
	@echo NOTE: phase6-gate is static-analysis + build only.
	@echo       Run tools\run-phase6-tests.ps1 (DOSBox-Staging) for unit-test execution,
	@echo       or invoke `wmake phase6-gate-full` to chain it after the static gates.

# Phase 6.1 S-C5: build RUNTESTS.EXE via Makefile.tests so phase6-gate
# can depend on it. The recursive wmake invocation reuses the already-
# built shared .obj set from `wmake all`; Makefile.tests adds only the
# test-side TUs (runtests.obj, news_stub.obj, screen-rt.obj).
runtests-build: $(TARGET) .SYMBOLIC
	@echo === Building RUNTESTS.EXE ===
	wmake -f Makefile.tests all

# Phase 6.1 S-C5: optional "full" gate that ALSO runs the DOSBox-
# Staging unit-test suite via tools/run-phase6-tests.ps1. Requires
# DOSBox-Staging installed at the default %LOCALAPPDATA% path; if
# DOSBox is elsewhere the developer passes -DosboxExe directly to the
# script. Exit code is propagated via the PowerShell exit code.
phase6-gate-full: phase6-gate .SYMBOLIC
	@echo === Phase 6 DOSBox-Staging unit-test run ===
	powershell -ExecutionPolicy Bypass -File tools\run-phase6-tests.ps1
	@echo === Phase 6 gates (full): PASS ===
