#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

AGENT_VERSION="1.1.1"
ACTION="${1:-help}"
[[ $# -gt 0 ]] && shift || true
SERVER=""; NODE_ID=""; TOKEN=""; NODE_NAME=""; HEARTBEAT_INTERVAL="300"
BASE_DIR="/usr/local/lib/offseek-vps-node"
CONFIG_FILE="/etc/offseek-vps-node.conf"
STATE_DIR="/var/lib/offseek-vps-node"
AGENT_PATH="$BASE_DIR/agent.sh"
BIN_LINK="/usr/local/bin/offseek-node"
LOG_FILE="/var/log/offseek-vps-node.log"
PID_FILE="$STATE_DIR/agent.pid"
LOCK_DIR="$STATE_DIR/daemon.lock"
GEO_CACHE="$STATE_DIR/geo.cache"
MANAGER_FILE="$STATE_DIR/manager"
DISABLED_FILE="$STATE_DIR/disabled"

log(){ printf '[Offseek Node] %s\n' "$*"; }
die(){ printf '[Offseek Node] 错误：%s\n' "$*" >&2; exit 1; }
need_arg(){ [[ $# -ge 2 && -n "${2:-}" ]] || die "参数 $1 缺少值"; }

while [[ $# -gt 0 ]]; do
  case "$1" in
    --server|-s) need_arg "$@"; SERVER="${2%/}"; shift 2 ;;
    --node|-n) need_arg "$@"; NODE_ID="$2"; shift 2 ;;
    --token|-t) need_arg "$@"; TOKEN="$2"; shift 2 ;;
    --name|-N) need_arg "$@"; NODE_NAME="$2"; shift 2 ;;
    --interval|-i) need_arg "$@"; HEARTBEAT_INTERVAL="$2"; shift 2 ;;
    *) die "未知参数：$1" ;;
  esac
done

require_root(){ [[ "$(id -u)" -eq 0 ]] || die "该操作需要 root 权限，请使用 sudo。"; }
valid_interval(){ [[ "${1:-}" =~ ^[0-9]+$ ]] && (( $1 >= 180 && $1 <= 3600 )); }

load_config(){
  [[ -r "$CONFIG_FILE" ]] || die "节点尚未安装：$CONFIG_FILE 不存在。"
  # shellcheck disable=SC1090
  source "$CONFIG_FILE"
  SERVER="${OFFSEEK_SERVER:-}"
  NODE_ID="${OFFSEEK_NODE_ID:-}"
  TOKEN="${OFFSEEK_NODE_TOKEN:-}"
  NODE_NAME="${OFFSEEK_NODE_NAME:-}"
  HEARTBEAT_INTERVAL="${OFFSEEK_HEARTBEAT_INTERVAL:-300}"
  [[ "$SERVER" =~ ^https:// ]] || die "节点平台地址无效。"
  [[ "$NODE_ID" =~ ^N[A-Za-z0-9_-]{6,31}$ ]] || die "节点 ID 无效。"
  [[ ${#TOKEN} -ge 32 ]] || die "节点令牌无效。"
  valid_interval "$HEARTBEAT_INTERVAL" || HEARTBEAT_INTERVAL=300
}

install_deps(){
  command -v curl >/dev/null 2>&1 && return 0
  log "正在安装 curl 与 CA 证书……"
  if command -v apt-get >/dev/null 2>&1; then
    apt-get update -qq || true
    env DEBIAN_FRONTEND=noninteractive apt-get install -y curl ca-certificates
  elif command -v dnf >/dev/null 2>&1; then dnf install -y curl ca-certificates
  elif command -v microdnf >/dev/null 2>&1; then microdnf install -y curl ca-certificates
  elif command -v yum >/dev/null 2>&1; then yum install -y curl ca-certificates
  elif command -v apk >/dev/null 2>&1; then apk add --no-cache curl ca-certificates
  elif command -v pacman >/dev/null 2>&1; then pacman -Sy --noconfirm --needed curl ca-certificates
  elif command -v zypper >/dev/null 2>&1; then zypper --non-interactive install curl ca-certificates
  elif command -v xbps-install >/dev/null 2>&1; then xbps-install -Sy curl ca-certificates
  else die "无法识别包管理器，请先手动安装 curl。"
  fi
}

json_escape(){
  local s="${1:-}"
  s=${s//\\/\\\\}; s=${s//\"/\\\"}; s=${s//$'\n'/\\n}; s=${s//$'\r'/\\r}; s=${s//$'\t'/\\t}
  printf '%s' "$s"
}
json_num(){ [[ "${1:-}" =~ ^-?[0-9]+([.][0-9]+)?$ ]] && printf '%s' "$1" || printf '0'; }
json_bool_cmd(){ command -v "$1" >/dev/null 2>&1 && printf true || printf false; }

json_get_string(){
  local key="$1" data="$2"
  if command -v jq >/dev/null 2>&1; then jq -r --arg k "$key" '.[$k] // empty' <<<"$data" 2>/dev/null || true
  else printf '%s' "$data" | tr -d '\n' | sed -n 's/.*"'"$key"'"[[:space:]]*:[[:space:]]*"\([^"\\]*\)".*/\1/p' | head -1; fi
}
json_get_connection_string(){
  local key="$1" data="$2"
  if command -v jq >/dev/null 2>&1; then jq -r --arg k "$key" '.connection[$k] // empty' <<<"$data" 2>/dev/null || true
  else printf '%s' "$data" | tr -d '\n' | sed -n 's/.*"connection"[[:space:]]*:[[:space:]]*{[^}]*"'"$key"'"[[:space:]]*:[[:space:]]*"\([^"\\]*\)".*/\1/p' | head -1; fi
}
json_get_asn(){
  local data="$1" value=""
  if command -v jq >/dev/null 2>&1; then value="$(jq -r '.connection.asn // empty' <<<"$data" 2>/dev/null || true)"
  else value="$(printf '%s' "$data" | tr -d '\n' | sed -n 's/.*"asn"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' | head -1)"; fi
  [[ -n "$value" ]] && printf 'AS%s' "$value"
}

load_geo(){
  local now cached_at=0 data=""
  now="$(date +%s)"
  if [[ -r "$GEO_CACHE" ]]; then
    # shellcheck disable=SC1090
    source "$GEO_CACHE" || true
    cached_at="${GEO_CACHED_AT:-0}"
    if [[ "$cached_at" =~ ^[0-9]+$ ]] && (( now - cached_at < 86400 )); then return 0; fi
  fi
  data="$(curl -fsS --connect-timeout 5 --max-time 10 'https://ipwho.is/' 2>/dev/null || true)"
  [[ -n "$data" ]] || return 0
  GEO_COUNTRY_CODE="$(json_get_string country_code "$data")"
  GEO_COUNTRY="$(json_get_string country "$data")"
  GEO_REGION="$(json_get_string region "$data")"
  GEO_CITY="$(json_get_string city "$data")"
  GEO_ASN="$(json_get_asn "$data")"
  GEO_ORG="$(json_get_connection_string org "$data")"
  [[ -n "$GEO_ORG" ]] || GEO_ORG="$(json_get_connection_string isp "$data")"
  {
    printf 'GEO_CACHED_AT=%q\n' "$now"
    printf 'GEO_COUNTRY_CODE=%q\n' "${GEO_COUNTRY_CODE:-}"
    printf 'GEO_COUNTRY=%q\n' "${GEO_COUNTRY:-}"
    printf 'GEO_REGION=%q\n' "${GEO_REGION:-}"
    printf 'GEO_CITY=%q\n' "${GEO_CITY:-}"
    printf 'GEO_ASN=%q\n' "${GEO_ASN:-}"
    printf 'GEO_ORG=%q\n' "${GEO_ORG:-}"
  } > "$GEO_CACHE.tmp"
  mv -f "$GEO_CACHE.tmp" "$GEO_CACHE"
}

collect_payload(){
  local host os_name kernel arch virt cpu_model cpu_cores memory_mb disk_gb uptime_s
  local GEO_COUNTRY_CODE="" GEO_COUNTRY="" GEO_REGION="" GEO_CITY="" GEO_ASN="" GEO_ORG="" GEO_CACHED_AT="0"
  host="$(hostname -f 2>/dev/null || hostname 2>/dev/null || echo unknown)"
  if [[ -r /etc/os-release ]]; then
    # shellcheck disable=SC1091
    . /etc/os-release
    os_name="${PRETTY_NAME:-${NAME:-Linux}}"
  else os_name="Linux"; fi
  kernel="$(uname -sr 2>/dev/null || echo Linux)"
  arch="$(uname -m 2>/dev/null || echo unknown)"
  virt="$(systemd-detect-virt 2>/dev/null || true)"
  [[ -n "$virt" && "$virt" != none ]] || virt="$(virt-what 2>/dev/null | head -1 || true)"
  [[ -n "$virt" ]] || virt="unknown"
  cpu_model="$(awk -F: '/model name|Hardware|Processor/{sub(/^[ \t]+/,"",$2); print $2; exit}' /proc/cpuinfo 2>/dev/null || true)"
  cpu_cores="$(getconf _NPROCESSORS_ONLN 2>/dev/null || nproc 2>/dev/null || echo 1)"
  memory_mb="$(awk '/MemTotal:/{printf "%d",$2*1024/1000000}' /proc/meminfo 2>/dev/null || echo 0)"
  disk_gb="$(df -Pk / 2>/dev/null | awk 'NR==2{printf "%.2f",$2/1048576}' || echo 0)"
  uptime_s="$(awk '{printf "%d",$1}' /proc/uptime 2>/dev/null || echo 0)"
  load_geo

  printf '{'
  printf '"agent_version":"%s",' "$(json_escape "$AGENT_VERSION")"
  printf '"node_name":"%s",' "$(json_escape "$NODE_NAME")"
  printf '"hostname":"%s",' "$(json_escape "$host")"
  printf '"os_name":"%s",' "$(json_escape "$os_name")"
  printf '"kernel":"%s",' "$(json_escape "$kernel")"
  printf '"architecture":"%s",' "$(json_escape "$arch")"
  printf '"virtualization":"%s",' "$(json_escape "$virt")"
  printf '"cpu_model":"%s",' "$(json_escape "$cpu_model")"
  printf '"cpu_cores":%s,' "$(json_num "$cpu_cores")"
  printf '"memory_mb":%s,' "$(json_num "$memory_mb")"
  printf '"disk_gb":%s,' "$(json_num "$disk_gb")"
  printf '"uptime_seconds":%s,' "$(json_num "$uptime_s")"
  printf '"country_code":"%s",' "$(json_escape "${GEO_COUNTRY_CODE:-}")"
  printf '"country":"%s",' "$(json_escape "${GEO_COUNTRY:-}")"
  printf '"region":"%s",' "$(json_escape "${GEO_REGION:-}")"
  printf '"city":"%s",' "$(json_escape "${GEO_CITY:-}")"
  printf '"asn":"%s",' "$(json_escape "${GEO_ASN:-}")"
  printf '"organization":"%s",' "$(json_escape "${GEO_ORG:-}")"
  printf '"capabilities":{"icmp_target":true,"ping":%s,"mtr":%s,"remote_commands":false,"proxy":false}' "$(json_bool_cmd ping)" "$(json_bool_cmd mtr)"
  printf '}'
}

rotate_log(){
  [[ -f "$LOG_FILE" ]] || return 0
  local size="$(wc -c < "$LOG_FILE" 2>/dev/null || echo 0)"
  [[ "$size" =~ ^[0-9]+$ ]] || size=0
  (( size < 1048576 )) || { tail -n 300 "$LOG_FILE" > "$LOG_FILE.tmp" 2>/dev/null || true; mv -f "$LOG_FILE.tmp" "$LOG_FILE" 2>/dev/null || true; }
}

run_heartbeat(){
  local quiet="${1:-0}" payload response_file http_code curl_status fail_count
  load_config
  [[ ! -e "$DISABLED_FILE" ]] || return 10
  command -v curl >/dev/null 2>&1 || return 1
  mkdir -p "$STATE_DIR"
  payload="$(collect_payload)"
  response_file="$STATE_DIR/response.tmp"
  set +e
  http_code="$(curl -sS -o "$response_file" -w '%{http_code}' --retry 1 --retry-delay 2 --connect-timeout 10 --max-time 28 \
    -H "Authorization: Bearer $TOKEN" -H "X-Offseek-Node-Token: $TOKEN" -H 'Content-Type: application/json' \
    --data-binary "$payload" "$SERVER/api/v1/nodes/$NODE_ID/heartbeat")"
  curl_status=$?
  set -e
  if [[ "$curl_status" -eq 0 && "$http_code" == "200" ]]; then
    printf '0' > "$STATE_DIR/auth-failures"
    date +%s > "$STATE_DIR/last-success"
    [[ "$quiet" -eq 1 ]] || log "心跳成功：$NODE_ID"
    rm -f "$response_file"
    return 0
  fi
  if [[ "$http_code" == "410" ]]; then
    : > "$DISABLED_FILE"
    log "平台已移除该节点，本地常驻进程已停止。"
    rm -f "$response_file"
    return 10
  fi
  fail_count="$(cat "$STATE_DIR/auth-failures" 2>/dev/null || echo 0)"
  [[ "$fail_count" =~ ^[0-9]+$ ]] || fail_count=0
  if [[ "$http_code" == "401" ]]; then
    fail_count=$((fail_count + 1)); printf '%s' "$fail_count" > "$STATE_DIR/auth-failures"
    if (( fail_count >= 3 )); then
      : > "$DISABLED_FILE"
      log "连续 3 次认证失败，节点已停止；请在平台重新创建。"
      rm -f "$response_file"
      return 10
    fi
  fi
  [[ "$quiet" -eq 1 ]] || log "心跳失败（HTTP ${http_code:-000}）：$(head -c 240 "$response_file" 2>/dev/null || true)"
  rm -f "$response_file"
  return 1
}

daemon_loop(){
  require_root; load_config; mkdir -p "$STATE_DIR"
  [[ ! -e "$DISABLED_FILE" ]] || exit 0
  if ! mkdir "$LOCK_DIR" 2>/dev/null; then
    local oldpid="$(cat "$PID_FILE" 2>/dev/null || echo '')"
    [[ "$oldpid" =~ ^[0-9]+$ ]] && kill -0 "$oldpid" 2>/dev/null && exit 0
    rm -rf "$LOCK_DIR"; mkdir "$LOCK_DIR" 2>/dev/null || exit 0
  fi
  printf '%s' "$$" > "$PID_FILE"
  trap 'rm -f "$PID_FILE"; rmdir "$LOCK_DIR" 2>/dev/null || true; exit 0' TERM INT EXIT
  while :; do
    rotate_log
    if run_heartbeat 1; then :; else
      local rc=$?
      (( rc == 10 )) && exit 0
    fi
    sleep "$HEARTBEAT_INTERVAL" & wait $!
  done
}

start_background(){
  load_config; mkdir -p "$STATE_DIR"; [[ ! -e "$DISABLED_FILE" ]] || return 0
  local pid="$(cat "$PID_FILE" 2>/dev/null || echo '')"
  [[ "$pid" =~ ^[0-9]+$ ]] && kill -0 "$pid" 2>/dev/null && return 0
  rm -f "$PID_FILE"; rm -rf "$LOCK_DIR"
  rotate_log
  if command -v setsid >/dev/null 2>&1; then
    setsid nohup "$BIN_LINK" daemon >>"$LOG_FILE" 2>&1 </dev/null &
  else
    nohup "$BIN_LINK" daemon >>"$LOG_FILE" 2>&1 </dev/null &
  fi
  sleep 1
  pid="$(cat "$PID_FILE" 2>/dev/null || echo '')"
  [[ "$pid" =~ ^[0-9]+$ ]] && kill -0 "$pid" 2>/dev/null
}

write_systemd(){
  rm -f /etc/systemd/system/offseek-vps-node.timer
  cat > /etc/systemd/system/offseek-vps-node.service <<EOF2
[Unit]
Description=Offseek VPS Community Node
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=$BIN_LINK daemon
Restart=on-failure
RestartSec=20
User=root
Nice=15
IOSchedulingClass=idle
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF2
  systemctl daemon-reload
  systemctl enable --now offseek-vps-node.service
  printf systemd > "$MANAGER_FILE"
}

write_openrc(){
  cat > /etc/init.d/offseek-vps-node <<EOF2
#!/sbin/openrc-run
name="Offseek VPS Community Node"
command="$BIN_LINK"
command_args="daemon"
command_background="yes"
pidfile="$PID_FILE"
output_log="$LOG_FILE"
error_log="$LOG_FILE"
depend() { need net; after firewall; }
EOF2
  chmod 755 /etc/init.d/offseek-vps-node
  rc-update add offseek-vps-node default >/dev/null 2>&1 || true
  rc-service offseek-vps-node restart
  printf openrc > "$MANAGER_FILE"
}

write_runit(){
  local service_dir="/etc/sv/offseek-vps-node" active_dir=""
  mkdir -p "$service_dir"
  cat > "$service_dir/run" <<EOF2
#!/bin/sh
exec 2>&1
exec $BIN_LINK daemon
EOF2
  chmod 755 "$service_dir/run"
  [[ -d /var/service ]] && active_dir=/var/service
  [[ -z "$active_dir" && -d /etc/service ]] && active_dir=/etc/service
  if [[ -n "$active_dir" ]]; then ln -sfn "$service_dir" "$active_dir/offseek-vps-node"; sv up "$active_dir/offseek-vps-node" >/dev/null 2>&1 || true
  else start_background; fi
  printf runit > "$MANAGER_FILE"
}

write_fallback(){
  mkdir -p /etc/cron.d
  cat > /etc/cron.d/offseek-vps-node <<EOF2
*/5 * * * * root $BIN_LINK ensure >/dev/null 2>&1
EOF2
  chmod 644 /etc/cron.d/offseek-vps-node
  start_background
  printf background > "$MANAGER_FILE"
}

install_manager(){
  rm -f /etc/cron.d/offseek-vps-node
  if command -v systemctl >/dev/null 2>&1 && [[ -d /run/systemd/system ]]; then write_systemd
  elif command -v rc-service >/dev/null 2>&1 && command -v rc-update >/dev/null 2>&1; then write_openrc
  elif command -v sv >/dev/null 2>&1 && [[ -d /etc/sv ]]; then write_runit
  else write_fallback
  fi
}

stop_manager(){
  if command -v systemctl >/dev/null 2>&1; then
    systemctl disable --now offseek-vps-node.service offseek-vps-node.timer >/dev/null 2>&1 || true
  fi
  if command -v rc-service >/dev/null 2>&1; then rc-service offseek-vps-node stop >/dev/null 2>&1 || true; fi
  if command -v rc-update >/dev/null 2>&1; then rc-update del offseek-vps-node default >/dev/null 2>&1 || true; fi
  if command -v sv >/dev/null 2>&1; then sv down /var/service/offseek-vps-node >/dev/null 2>&1 || true; sv down /etc/service/offseek-vps-node >/dev/null 2>&1 || true; fi
  local pid="$(cat "$PID_FILE" 2>/dev/null || echo '')"
  [[ "$pid" =~ ^[0-9]+$ ]] && kill "$pid" >/dev/null 2>&1 || true
  rm -f /etc/cron.d/offseek-vps-node /etc/init.d/offseek-vps-node
  rm -f /etc/systemd/system/offseek-vps-node.service /etc/systemd/system/offseek-vps-node.timer
  rm -f /var/service/offseek-vps-node /etc/service/offseek-vps-node
  rm -rf /etc/sv/offseek-vps-node "$LOCK_DIR"
  command -v systemctl >/dev/null 2>&1 && systemctl daemon-reload >/dev/null 2>&1 || true
}

format_time(){
  local epoch="${1:-}"
  [[ "$epoch" =~ ^[0-9]+$ ]] || { printf '尚无'; return; }
  date -d "@$epoch" '+%F %T' 2>/dev/null || date -r "$epoch" '+%F %T' 2>/dev/null || printf '%s' "$epoch"
}

case "$ACTION" in
  install)
    require_root
    [[ "$SERVER" =~ ^https:// ]] || die "生产环境平台地址必须使用 HTTPS。"
    [[ "$NODE_ID" =~ ^N[A-Za-z0-9_-]{6,31}$ ]] || die "节点 ID 格式错误。"
    [[ ${#TOKEN} -ge 32 ]] || die "节点令牌格式错误。"
    valid_interval "$HEARTBEAT_INTERVAL" || HEARTBEAT_INTERVAL=300
    install_deps
    mkdir -p "$BASE_DIR" "$STATE_DIR"
    curl -fsSL --retry 3 --connect-timeout 15 --max-time 60 "$SERVER/node-agent.sh?v=298" -o "$AGENT_PATH"
    chmod 700 "$AGENT_PATH"; ln -sf "$AGENT_PATH" "$BIN_LINK"
    {
      printf 'OFFSEEK_SERVER=%q\n' "$SERVER"
      printf 'OFFSEEK_NODE_ID=%q\n' "$NODE_ID"
      printf 'OFFSEEK_NODE_TOKEN=%q\n' "$TOKEN"
      printf 'OFFSEEK_NODE_NAME=%q\n' "$NODE_NAME"
      printf 'OFFSEEK_HEARTBEAT_INTERVAL=%q\n' "$HEARTBEAT_INTERVAL"
    } > "$CONFIG_FILE"
    chmod 600 "$CONFIG_FILE"; rm -f "$DISABLED_FILE"
    "$BIN_LINK" run || true
    install_manager
    log "节点已作为系统后台服务安装，SSH 退出不会中断。"
    log "节点 ID：$NODE_ID"
    log "查看状态：sudo offseek-node status"
    log "退出节点：sudo offseek-node uninstall"
    ;;
  run) require_root; run_heartbeat 0 ;;
  daemon) daemon_loop ;;
  ensure) require_root; [[ -e "$DISABLED_FILE" ]] || start_background ;;
  restart) require_root; stop_manager; rm -f "$DISABLED_FILE"; install_manager; log "节点服务已重启。" ;;
  upgrade)
    require_root; load_config; install_deps
    tmp_agent="$(mktemp "${TMPDIR:-/tmp}/offseek-node-upgrade.XXXXXX")"
    trap 'rm -f "$tmp_agent"' EXIT INT TERM
    curl -fsSL --retry 3 --connect-timeout 15 --max-time 60 "$SERVER/node-agent.sh?v=298" -o "$tmp_agent"
    bash -n "$tmp_agent" || die "新节点脚本语法检查失败。"
    chmod 700 "$tmp_agent"; mv -f "$tmp_agent" "$AGENT_PATH"; chmod 700 "$AGENT_PATH"
    trap - EXIT INT TERM
    "$BIN_LINK" restart
    log "节点程序已升级到最新版本。"
    ;;
  status)
    require_root; load_config
    pid="$(cat "$PID_FILE" 2>/dev/null || echo '')"
    echo "节点 ID：$NODE_ID"
    echo "平台：$SERVER"
    echo "运行方式：$(cat "$MANAGER_FILE" 2>/dev/null || echo 未知)"
    if [[ -e "$DISABLED_FILE" ]]; then echo "本地状态：已停用"
    elif [[ "$pid" =~ ^[0-9]+$ ]] && kill -0 "$pid" 2>/dev/null; then echo "后台进程：运行中（PID $pid）"
    else echo "后台进程：未运行"; fi
    echo "心跳间隔：${HEARTBEAT_INTERVAL} 秒"
    echo "最近成功心跳：$(format_time "$(cat "$STATE_DIR/last-success" 2>/dev/null || echo '')")"
    ;;
  uninstall)
    require_root
    if [[ -r "$CONFIG_FILE" ]]; then
      load_config
      curl -fsS --connect-timeout 8 --max-time 15 -X POST -H "Authorization: Bearer $TOKEN" -H "X-Offseek-Node-Token: $TOKEN" \
        "$SERVER/api/v1/nodes/$NODE_ID/unregister" >/dev/null 2>&1 || true
    fi
    stop_manager
    rm -f "$BIN_LINK" "$CONFIG_FILE"
    rm -rf "$BASE_DIR" "$STATE_DIR"
    log "节点程序已卸载。"
    ;;
  help|-h|--help)
    cat <<EOF2
Offseek VPS Community Node v$AGENT_VERSION
用法：
  sudo offseek-node status
  sudo offseek-node run
  sudo offseek-node restart
  sudo offseek-node upgrade
  sudo offseek-node uninstall

节点以系统服务或独立后台进程运行，退出 SSH 不会中断；默认每 5 分钟发送一次轻量心跳。
节点不接受远程命令，也不提供代理、转发或文件服务。
EOF2
    ;;
  *) die "未知操作：$ACTION" ;;
esac
