<?php
declare(strict_types=1);

// Included by a C or B adapter after its read-only environment/schema gate.
const CDX_WEIGHT_CONTRACT_TOKEN = 'CDX_WEIGHT_CONTRACT_WRITE_APPROVED_20261002_V1';
$scenario = (string)getenv('CDX_WEIGHT_SCENARIO');
if (!in_array($scenario, ['single', 'duplicate'], true)) {
    throw new RuntimeException('Explicit single/duplicate scenario required');
}
$sourceSha = 'bec86974a8447c3f714320b77719caebf7a4ce55dcb8aceed6c0489683debca8';
$sourcePaths = $weightTarget === 'C'
    ? ['/tmp/zhct-ai-http-20260929.3XDj3w/app/api/model/meal/Meal.php',
       '/tmp/zhct-dm-poc-20260928.fcpiiN/ai_api/app/api/model/meal/Meal.php']
    : ['/tmp/zhct-http-ai-macos.x2CCZX/app/api/model/meal/Meal.php',
       '/Users/wiscourper/Documents/workspace/local/dm8-full-acceptance.fF5yTy/ai_api/app/api/model/meal/Meal.php'];
$stage = 'actual_model_source_hash';
foreach ($sourcePaths as $path) {
    if (!is_file($path) || hash_file('sha256', $path) !== $sourceSha) {
        throw new RuntimeException('Approved Meal model source not loaded');
    }
}
$tables = [
    'user' => $weightPrefix . 'user',
    'staff' => $weightPrefix . 'staff',
    'meal' => $weightPrefix . 'meal',
    'infos' => $weightPrefix . 'meal_infos',
    'dishes' => $weightPrefix . 'dishes',
    'dishes_foods' => $weightPrefix . 'dishes_foods',
    'foods' => $weightPrefix . 'foods',
];
$stage = 'weight_contract_insert_columns_readonly';
foreach (['user' => 'USER_ID,STORE_ID,NICK_NAME,CREATE_TIME',
    'staff' => 'ID,USER_ID,STORE_ID,NAME,CREATE_TIME',
    'meal' => 'ID,STAFF_ID,STORE_ID,MEAL_DATE,MEAL_TIMES,MEAL_TIME,CREATE_BY,'
        . 'ENERGY,CARBOHYDRATE,PROTEIN,FAT,IS_DELETE',
    'infos' => 'ID,MEAL_ID,STAFF_ID,STORE_ID,MEAL_DATE,MEAL_TIMES,MEAL_TIME,'
        . 'DISHES_ID,DISHES_WEIGHT,DISHES_NUMBER,CREATE_BY,IS_DELETE',
    'dishes' => 'ID,WEIGHT,ENERGY,CARBOHYDRATE,PROTEIN,FAT,IS_DELETE',
] as $name => $columns) {
    $ai->query('SELECT ' . $columns . ' FROM ' . $tables[$name] . ' WHERE 1=0');
}
$stage = 'weight_contract_positive_dish_readonly';
$dishSql = 'SELECT d.ID,d.WEIGHT,d.ENERGY,d.CARBOHYDRATE,d.PROTEIN,d.FAT'
    . ' FROM ' . $tables['dishes'] . ' d INNER JOIN ' . $tables['dishes_foods']
    . ' df ON d.ID=df.DISHES_ID INNER JOIN ' . $tables['foods']
    . ' f ON f.ID=df.FOODS_ID WHERE d.IS_DELETE=0 AND d.WEIGHT>0'
    . ' AND d.ENERGY>0 ORDER BY d.ID';
$positiveDishCount = (int)$ai->query('SELECT COUNT(*) FROM '
    . $tables['dishes'] . ' d INNER JOIN ' . $tables['dishes_foods']
    . ' df ON d.ID=df.DISHES_ID INNER JOIN ' . $tables['foods']
    . ' f ON f.ID=df.FOODS_ID WHERE d.IS_DELETE=0 AND d.WEIGHT>0'
    . ' AND d.ENERGY>0')->fetchColumn();
$day = '2027-12-13';
$end = '2027-12-19';
if (!hash_equals(CDX_WEIGHT_CONTRACT_TOKEN,
    (string)getenv('CDX_WEIGHT_CONTRACT_APPROVAL'))) {
    echo json_encode(['status' => 'weight-contract-default-readonly',
        'target' => $weightTarget, 'scenario' => $scenario,
        'approved_model_source' => true,
        'insert_column_groups_queryable' => 5,
        'positive_mapped_dish_exists' => $positiveDishCount > 0,
        'candidate_week_exclusive' => $counts['ai_meal_week'] === 0
            && $counts['ai_meal_infos_week'] === 0,
        'business_http_count' => 0, 'writes' => 0],
        JSON_UNESCAPED_SLASHES), PHP_EOL;
    exit(0);
}
$stage = 'approved_write_boundary';
if ($counts['ai_meal_week'] !== 0 || $counts['ai_meal_infos_week'] !== 0) {
    throw new RuntimeException('Target week no longer exclusive');
}
if ($positiveDishCount < 1) throw new RuntimeException('Mapped positive dish unavailable');
$positiveDish = $ai->query($dishSql)->fetch(PDO::FETCH_ASSOC);
if (!is_array($positiveDish)) throw new RuntimeException('Mapped dish row unavailable');
foreach ($config as $key => $value) {
    if (strpos($key, 'POC_') === 0) putenv($key . '=' . $value);
}
if ($weightTarget === 'B') {
    putenv('POC_DIALECT=mysql');
    putenv('POC_EXTERNAL_STUBS=1');
}
define('TP_ENV', 'poc');
define('BUSINESS', 'aizhct');
define('ENTERPRISE_NO', '10001');
require $root . '/vendor/autoload.php';
(new \think\App($root))->setEnvName('poc')->initialize();
$ai->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
$dish = array_change_key_case($positiveDish, CASE_LOWER);
$marker = 'CDXPARWEIGHT' . strtoupper(bin2hex(random_bytes(5)));
$token = $marker . 'T' . strtoupper(bin2hex(random_bytes(10)));
$ids = [];
$hashes = [];
$cases = [];
$cleanup = [];
$error = null;
$globalWeekIsolated = true;
$referenceStable = true;
$requestState = ['started' => false, 'complete' => true];
$dishId = (int)$dish['id'];
$dishWeight = (string)$dish['weight'];
$now = time();
echo json_encode(['stage' => 'before_synthetic_write', 'target' => $weightTarget,
    'marker' => $marker], JSON_UNESCAPED_SLASHES), PHP_EOL;
flush();
$all = static function (string $sql, array $bind = []) use ($ai): array {
    $stmt = $ai->prepare($sql);
    $stmt->execute($bind);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
};
$num = static function (string $sql, array $bind = []) use ($ai): int {
    $stmt = $ai->prepare($sql);
    $stmt->execute($bind);
    return (int)$stmt->fetchColumn();
};
$takeId = static function (string $sql, array $bind) use ($all): int {
    $rows = $all($sql, $bind);
    if (count($rows) !== 1) throw new RuntimeException('Synthetic ID not unique');
    $id = (int)array_values($rows[0])[0];
    if ($id <= 0) throw new RuntimeException('Synthetic ID invalid');
    return $id;
};
$rowHash = static function (string $table, string $key, int $id) use ($all): string {
    $rows = $all('SELECT * FROM ' . $table . ' WHERE ' . $key . '=?', [$id]);
    if (count($rows) !== 1) throw new RuntimeException('Synthetic row not unique');
    return hash('sha256', json_encode($rows[0],
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
};
$weekCounts = static function () use ($num, $tables, $day, $end): array {
    return [
        'meal' => $num('SELECT COUNT(*) FROM ' . $tables['meal']
            . ' WHERE MEAL_DATE>=? AND MEAL_DATE<=? AND IS_DELETE=0', [$day, $end]),
        'infos' => $num('SELECT COUNT(*) FROM ' . $tables['infos']
            . ' WHERE MEAL_DATE>=? AND MEAL_DATE<=? AND IS_DELETE=0', [$day, $end]),
    ];
};
$request = static function (string $token) use ($weightPort, $day,
    &$requestState): array {
    $requestState = ['started' => true, 'complete' => false];
    $url = 'http://127.0.0.1:' . $weightPort
        . '/api/analysis.Analysis/daily?storeId=10001';
    $context = stream_context_create(['http' => [
        'method' => 'POST', 'timeout' => 25, 'ignore_errors' => true,
        'header' => 'Access-Token: ' . $token
            . "\r\nplatform: POC\r\nContent-Type: application/json;charset=utf-8\r\n",
        'content' => json_encode(['date' => $day]),
    ]]);
    $text = file_get_contents($url, false, $context);
    $line = $http_response_header[0] ?? '';
    $body = is_string($text) ? json_decode($text, true) : null;
    $http = preg_match('/HTTP\/\S+\s+(\d+)/', $line, $match)
        ? (int)$match[1] : 0;
    $requestState['complete'] = $http > 0 && is_array($body);
    return [
        'http' => $http,
        'body' => $body,
    ];
};
$workerIdentity = static function () use ($weightTarget, $weightPort, $root): bool {
    if ($weightTarget === 'C') {
        $pid = 53772;
        $cmd = file_get_contents('/proc/' . $pid . '/cmdline');
        $children = file_get_contents('/proc/' . $pid . '/task/' . $pid . '/children');
        return is_string($cmd) && is_string($children)
            && trim($children) === ''
            && strpos($cmd, $root . '/public') !== false
            && strpos($cmd, '127.0.0.1:' . $weightPort) !== false;
    }
    $pid = (int)getenv('CDX_HEALTH_HTTP_PID');
    if ($pid <= 1) return false;
    $cmd = shell_exec('/bin/ps -p ' . $pid . ' -o command=');
    $children = shell_exec('/usr/bin/pgrep -P ' . $pid);
    $listener = shell_exec('/usr/sbin/lsof -nP -iTCP:' . $weightPort
        . ' -sTCP:LISTEN -t');
    $displayRoot = str_replace('/private/tmp/', '/tmp/', $root);
    return is_string($cmd) && strpos($cmd, '-S 127.0.0.1:' . $weightPort) !== false
        && (strpos($cmd, $root . '/public') !== false
            || strpos($cmd, $displayRoot . '/public') !== false)
        && trim((string)$children) === ''
        && trim((string)$listener) === (string)$pid;
};
$boundaryBarrier = static function () use ($weightPort, $workerIdentity): bool {
    if (!$workerIdentity()) return false;
    $context = stream_context_create(['http' => [
        'method' => 'GET', 'timeout' => 35, 'ignore_errors' => true,
    ]]);
    $text = file_get_contents('http://127.0.0.1:' . $weightPort
        . '/__poc_boundary', false, $context);
    $statusLine = $http_response_header[0] ?? '';
    $body = is_string($text) ? json_decode($text, true) : null;
    return preg_match('/HTTP\/\S+\s+200\b/', $statusLine) === 1
        && is_array($body) && !empty($body['external_stubs'])
        && $workerIdentity();
};
$hasSensitiveKey = null;
$hasSensitiveKey = static function ($value) use (&$hasSensitiveKey): bool {
    if (!is_array($value)) return false;
    foreach ($value as $key => $item) {
        if (is_string($key) && in_array(strtolower($key), [
            'api_key', 'password', 'secret', 'access_token', 'refresh_token',
            'authorization', 'mobile', 'phone', 'nick_name',
        ], true)) return true;
        if ($hasSensitiveKey($item)) return true;
    }
    return false;
};
try {
    $stage = 'week_zero_recheck';
    if ($weekCounts() !== ['meal' => 0, 'infos' => 0]) {
        $globalWeekIsolated = false;
        throw new RuntimeException('Week no longer exclusive');
    }
    $hashes['dish'] = $rowHash($tables['dishes'], 'ID', $dishId);
    $stage = 'insert_user';
    if ($num('SELECT COUNT(*) FROM ' . $tables['user']
        . ' WHERE NICK_NAME=? AND STORE_ID=10001', [$marker]) !== 0) {
        throw new RuntimeException('Marker collision');
    }
    $ai->prepare('INSERT INTO ' . $tables['user']
        . ' (STORE_ID,MOBILE,NICK_NAME,BALANCE,GIFT_BALANCE,IS_DELETE,CREATE_TIME)'
        . ' VALUES (10001,?,?,?,?,0,?)')
        ->execute(['', $marker, '0.00', '0.00', $now]);
    $ids['user'] = $takeId('SELECT USER_ID FROM ' . $tables['user']
        . ' WHERE NICK_NAME=? AND STORE_ID=10001', [$marker]);
    $hashes['user'] = $rowHash($tables['user'], 'USER_ID', $ids['user']);
    $stage = 'insert_staff';
    $ai->prepare('INSERT INTO ' . $tables['staff']
        . ' (NAME,USER_ID,STORE_ID,HEIGHT,WEIGHT,GENDER,BIRTHDAY,PHONE,'
        . ' CREATE_TIME,IS_DELETE)'
        . " VALUES (?,?,10001,170,60,1,'1990-01-01','',?,0)")
        ->execute([$marker, $ids['user'], $day . ' 00:00:00']);
    $ids['staff'] = $takeId('SELECT ID FROM ' . $tables['staff']
        . ' WHERE NAME=? AND USER_ID=? AND STORE_ID=10001',
        [$marker, $ids['user']]);
    $hashes['staff'] = $rowHash($tables['staff'], 'ID', $ids['staff']);
    $stage = 'insert_meal';
    $ai->prepare('INSERT INTO ' . $tables['meal']
        . ' (STAFF_ID,STORE_ID,MEAL_DATE,MEAL_TIMES,MEAL_TIME,CREATE_BY,'
        . ' ENERGY,CARBOHYDRATE,PROTEIN,FAT,IS_DELETE)'
        . ' VALUES (?,10001,?,1,?,?,?,?,?,?,0)')
        ->execute([$ids['staff'], $day, $day . ' 12:00:00', $marker,
            (float)$dish['energy'] * ($scenario === 'duplicate' ? 2 : 1),
            (float)$dish['carbohydrate'] * ($scenario === 'duplicate' ? 2 : 1),
            (float)$dish['protein'] * ($scenario === 'duplicate' ? 2 : 1),
            (float)$dish['fat'] * ($scenario === 'duplicate' ? 2 : 1)]);
    $ids['meal'] = $takeId('SELECT ID FROM ' . $tables['meal']
        . ' WHERE STAFF_ID=? AND MEAL_DATE=? AND MEAL_TIMES=1 AND CREATE_BY=?',
        [$ids['staff'], $day, $marker]);
    $hashes['meal'] = $rowHash($tables['meal'], 'ID', $ids['meal']);
    $insertInfo = static function (string $number) use ($ai, $tables, $ids,
        $day, $dishId, $dishWeight, $marker): void {
        $ai->prepare('INSERT INTO ' . $tables['infos']
            . ' (MEAL_ID,STAFF_ID,STORE_ID,MEAL_DATE,MEAL_TIMES,MEAL_TIME,'
            . ' DISHES_ID,DISHES_WEIGHT,DISHES_NUMBER,CREATE_BY,IS_DELETE)'
            . ' VALUES (?,?,10001,?,1,?,?,?,?,?,0)')
            ->execute([$ids['meal'], $ids['staff'], $day,
                $day . ' 12:00:00', $dishId, $dishWeight, $number, $marker]);
    };
    $stage = 'insert_first_infos';
    $insertInfo('1');
    $ids['first_infos'] = $takeId('SELECT ID FROM ' . $tables['infos']
        . ' WHERE MEAL_ID=? AND STAFF_ID=? AND CREATE_BY=?',
        [$ids['meal'], $ids['staff'], $marker]);
    $hashes['first_infos'] = $rowHash($tables['infos'], 'ID', $ids['first_infos']);
    if ($scenario === 'duplicate') {
        $stage = 'insert_second_infos';
        // Two independent one-serving rows of the same dish; total meal is 2x.
        $insertInfo('1');
        $ids['second_infos'] = $takeId('SELECT ID FROM ' . $tables['infos']
            . ' WHERE MEAL_ID=? AND STAFF_ID=? AND CREATE_BY=? AND ID<>?',
            [$ids['meal'], $ids['staff'], $marker, $ids['first_infos']]);
        $hashes['second_infos'] = $rowHash($tables['infos'], 'ID',
            $ids['second_infos']);
    }
    $expectedInfos = $scenario === 'duplicate' ? 2 : 1;
    if ($weekCounts() !== ['meal' => 1, 'infos' => $expectedInfos]) {
        $globalWeekIsolated = false;
        throw new RuntimeException('Scenario fixture overlapped other row');
    }
    if (!\think\facade\Cache::set($token, [
        'user' => ['user_id' => $ids['user']],
        'password_version' => 0, 'login_type' => 'thirdparty',
    ], 300)) throw new RuntimeException('Token cache unavailable');

    $stage = $scenario . '_daily_http';
    $response = $request($token);
    $body = $response['body'];
    $data = is_array($body) ? ($body['data'] ?? null) : null;
    $weight = $data['meal_data'][0]['dishes_weight'] ?? null;
    $sensitiveKey = $hasSensitiveKey($data);
    $ok = $response['http'] === 200 && is_array($body)
        && (int)($body['status'] ?? -1) === 200 && is_array($data)
        && !$sensitiveKey
        && count($data['meal_data'] ?? []) === 1
        && (int)($data['meal_data'][0]['dishes_id'] ?? 0) === $dishId;
    if ($scenario === 'single') {
        $ok = $ok && is_string($weight)
            && preg_match('/^-?[0-9]+\.[0-9]{2}$/', $weight) === 1
            && abs((float)$weight - (float)$dishWeight) < 0.000001;
    } else {
        $ok = $ok && (is_int($weight) || is_float($weight))
            && abs((float)$weight - 2 * (float)$dishWeight) < 0.000001;
    }
    if ($weekCounts() !== ['meal' => 1, 'infos' => $expectedInfos]) {
        $globalWeekIsolated = false;
        $ok = false;
    }
    $cases[$scenario] = ['http' => $response['http'],
        'business_status' => is_array($body) ? ($body['status'] ?? null) : null,
        'dishes_weight_json_type' => gettype($weight),
        'sensitive_key_present' => $sensitiveKey,
        'fixed_two_decimal_string' => is_string($weight)
            && preg_match('/^-?[0-9]+\.[0-9]{2}$/', $weight) === 1,
        'weight_equals_original_rows' => is_numeric($weight)
            && abs((float)$weight - $expectedInfos * (float)$dishWeight) < 0.000001,
        'pass' => $ok];
    if (!$ok) throw new RuntimeException('Weight response not closed');
    foreach (['user' => ['USER_ID', 'user'], 'staff' => ['ID', 'staff'],
        'meal' => ['ID', 'meal'], 'first_infos' => ['ID', 'infos'],
        'second_infos' => ['ID', 'infos']] as $name => [$key, $tableName]) {
        if (isset($ids[$name]) && $rowHash($tables[$tableName], $key, $ids[$name])
            !== $hashes[$name]) {
            throw new RuntimeException('Daily read changed synthetic row');
        }
    }
} catch (Throwable $failure) {
    $error = ['class' => get_class($failure), 'code' => (string)$failure->getCode(),
        'stage' => $stage];
} finally {
    try {
        \think\facade\Cache::delete($token);
        $cleanup['cache_absent'] = \think\facade\Cache::get($token) === null;
    } catch (Throwable $ignored) {
        $cleanup['cache_absent'] = false;
    }
    $barrierRequired = $requestState['started'] && !$requestState['complete'];
    $barrierPassed = !$barrierRequired;
    if ($barrierRequired) {
        try {
            $barrierPassed = $boundaryBarrier();
        } catch (Throwable $ignored) {
            $barrierPassed = false;
        }
    }
    $cleanup['incomplete_http_barrier_required'] = $barrierRequired;
    $cleanup['incomplete_http_barrier_passed'] = $barrierPassed;
    try {
        $expectedWeek = ['meal' => isset($ids['meal']) ? 1 : 0,
            'infos' => (int)isset($ids['first_infos'])
                + (int)isset($ids['second_infos'])];
        $cleanup['global_week_overlap'] = $weekCounts() !== $expectedWeek;
        if ($cleanup['global_week_overlap']) $globalWeekIsolated = false;
    } catch (Throwable $ignored) {
        $cleanup['global_week_overlap'] = true;
        $globalWeekIsolated = false;
    }
    $safe = isset($ids['user'], $hashes['user'])
        && (!$barrierRequired || ($barrierPassed
            && $cleanup['global_week_overlap'] === false));
    try {
        if ($safe) {
            $expected = ['user' => 1, 'staff' => isset($ids['staff']) ? 1 : 0,
                'meal' => isset($ids['meal']) ? 1 : 0,
                'infos' => (int)isset($ids['first_infos'])
                    + (int)isset($ids['second_infos'])];
            $countsNow = [
                'user' => $num('SELECT COUNT(*) FROM ' . $tables['user']
                    . ' WHERE USER_ID=? AND NICK_NAME=? AND STORE_ID=10001',
                    [$ids['user'], $marker]),
                'staff' => $num('SELECT COUNT(*) FROM ' . $tables['staff']
                    . ' WHERE USER_ID=? AND STORE_ID=10001', [$ids['user']]),
                'meal' => $num('SELECT COUNT(*) FROM ' . $tables['meal']
                    . ' WHERE STAFF_ID=? AND CREATE_BY=?',
                    [$ids['staff'] ?? -1, $marker]),
                'infos' => $num('SELECT COUNT(*) FROM ' . $tables['infos']
                    . ' WHERE STAFF_ID=? AND CREATE_BY=?',
                    [$ids['staff'] ?? -1, $marker]),
            ];
            if ($countsNow !== $expected) $safe = false;
            foreach (['user' => ['USER_ID', 'user'], 'staff' => ['ID', 'staff'],
                'meal' => ['ID', 'meal'], 'first_infos' => ['ID', 'infos'],
                'second_infos' => ['ID', 'infos']] as $name => [$key, $tableName]) {
                if (isset($ids[$name]) && (!isset($hashes[$name])
                    || $rowHash($tables[$tableName], $key, $ids[$name])
                        !== $hashes[$name])) $safe = false;
            }
            if ($rowHash($tables['dishes'], 'ID', $dishId)
                !== $hashes['dish']) $referenceStable = false;
        }
    } catch (Throwable $ignored) {
        $safe = false;
    }
    $cleanup['ownership_gate'] = $safe;
    $cleanup['deferred_due_to_incomplete_http'] = $barrierRequired && !$safe;
    foreach (['second_infos' => 'infos', 'first_infos' => 'infos',
        'meal' => 'meal', 'staff' => 'staff', 'user' => 'user'] as $name => $tableName) {
        if (!isset($ids[$name])) {
            $cleanup[$name] = 0;
            continue;
        }
        if (!$safe) {
            $cleanup[$name] = -1;
            continue;
        }
        try {
            $key = $name === 'user' ? 'USER_ID' : 'ID';
            if ($name === 'user') {
                $where = ' AND NICK_NAME=? AND STORE_ID=10001';
                $bind = [$ids[$name], $marker];
            } elseif ($name === 'staff') {
                $where = ' AND USER_ID=? AND STORE_ID=10001';
                $bind = [$ids[$name], $ids['user']];
            } else {
                $where = ' AND STAFF_ID=? AND CREATE_BY=?';
                $bind = [$ids[$name], $ids['staff'], $marker];
            }
            $ai->prepare('DELETE FROM ' . $tables[$tableName]
                . ' WHERE ' . $key . '=?' . $where)->execute($bind);
            $cleanup[$name] = $num('SELECT COUNT(*) FROM '
                . $tables[$tableName] . ' WHERE ' . $key . '=?', [$ids[$name]]);
        } catch (Throwable $ignored) {
            $cleanup[$name] = -1;
            $safe = false;
        }
    }
}
$clean = ($cleanup['cache_absent'] ?? false) === true
    && ($cleanup['ownership_gate'] ?? false) === true;
foreach (['second_infos', 'first_infos', 'meal', 'staff', 'user'] as $name) {
    $clean = $clean && isset($cleanup[$name]) && $cleanup[$name] === 0;
}
$pass = $error === null && $referenceStable && $globalWeekIsolated
    && count($cases) === 1 && !in_array(false, array_column($cases, 'pass'), true)
    && $clean;
echo json_encode(['status' => $pass ? 'weight-contract-pass' : 'weight-contract-not-closed',
    'target' => $weightTarget, 'scenario' => $scenario, 'marker' => $marker,
    'synthetic_ids' => $ids, 'cases' => $cases,
    'error' => $error, 'cleanup' => $cleanup,
    'global_week_isolated' => $globalWeekIsolated,
    'reference_dish_stable' => $referenceStable],
    JSON_UNESCAPED_SLASHES), PHP_EOL;
exit($pass ? 0 : 3);
