520 lines
16 KiB
Bash
Executable file
520 lines
16 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
require() {
|
|
for cmd in "$@"; do
|
|
command -v "$cmd" >/dev/null 2>&1 || {
|
|
echo "ctl: missing dependency: $cmd" >&2
|
|
exit 1
|
|
}
|
|
done
|
|
}
|
|
|
|
case "$1" in
|
|
screenshot)
|
|
dir="${XDG_PICTURES_DIR:-$HOME/Pictures}/Screenshots"
|
|
mkdir -p "$dir"
|
|
file="$dir/$(openssl rand -hex 10)-$(date +'%Y-%m-%d_%H-%M-%S').png"
|
|
if [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then
|
|
require grim slurp wl-copy
|
|
grim -g "$(slurp)" "$file" && wl-copy <"$file"
|
|
else
|
|
require maim xclip
|
|
maim -s "$file" && xclip -selection clipboard -t image/png -i "$file" &
|
|
fi
|
|
;;
|
|
keyboard)
|
|
case "$2" in
|
|
next)
|
|
if [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then
|
|
if [ "$XDG_CURRENT_DESKTOP" = "Hyprland" ]; then
|
|
hyprctl switchxkblayout current next
|
|
elif [ "$XDG_CURRENT_DESKTOP" = "sway" ]; then
|
|
swaymsg input type:keyboard xkb_switch_layout next
|
|
fi
|
|
else
|
|
current="$(setxkbmap -query | awk '/variant/{print $2}')"
|
|
case "$current" in
|
|
"") setxkbmap -layout us -variant dvorak ;;
|
|
dvorak) setxkbmap -layout us -variant colemak ;;
|
|
*) setxkbmap -layout us ;;
|
|
esac
|
|
fi
|
|
;;
|
|
pick)
|
|
require fuzzel
|
|
variant=$(hyprctl getoption input:kb_variant 2>/dev/null | awk '/^str:/{print $2}' | cut -d, -f2)
|
|
case "$variant" in
|
|
dvorak) current="Dvorak" ;;
|
|
colemak) current="Colemak" ;;
|
|
*) current="QWERTY" ;;
|
|
esac
|
|
choice=$(printf 'QWERTY\nDvorak\nColemak' |
|
|
awk -v cur="$current" '{
|
|
prefix = ($0 == cur) ? " > " : " "
|
|
printf "%s%s\t%s\n", prefix, $0, $0
|
|
}' |
|
|
fuzzel --dmenu --prompt="kbd: " --no-icons --lines=3 \
|
|
--with-nth=1 --accept-nth=2 --font="monospace:size=12" --width=23)
|
|
[ -z "$choice" ] && exit 0
|
|
case "$choice" in
|
|
QWERTY) variant="" ;;
|
|
Dvorak) variant="dvorak" ;;
|
|
Colemak) variant="colemak" ;;
|
|
esac
|
|
if [ "$XDG_CURRENT_DESKTOP" = "Hyprland" ]; then
|
|
hyprctl keyword input:kb_layout "us,us,us"
|
|
hyprctl keyword input:kb_variant ",$variant"
|
|
hyprctl switchxkblayout current 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Usage: ctl keyboard {next|pick}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
audio)
|
|
require wpctl pw-dump jq fuzzel
|
|
case "$2" in
|
|
sink | source)
|
|
if [ "$2" = sink ]; then
|
|
class="Audio/Sink"
|
|
prompt="sink: "
|
|
default_meta="default.audio.sink"
|
|
node="@DEFAULT_AUDIO_SINK@"
|
|
pad=7
|
|
else
|
|
class="Audio/Source"
|
|
prompt="source: "
|
|
default_meta="default.audio.source"
|
|
node="@DEFAULT_AUDIO_SOURCE@"
|
|
pad=8
|
|
fi
|
|
while :; do
|
|
dump=$(pw-dump)
|
|
devices=$(printf '%s' "$dump" | jq -r --arg class "$class" \
|
|
'.[] | select(.info.props."media.class" == $class) | "\(.id)\t\(.info.props."node.description" // .info.props."node.name" // "unknown")\t\(.info.props."node.name" // "")"')
|
|
[ -z "$devices" ] && exit 0
|
|
default_name=$(printf '%s' "$dump" | jq -r --arg key "$default_meta" \
|
|
'.[] | select(.type == "PipeWire:Interface:Metadata" and .info.props."metadata.name" == "default") | .info.metadata[] | select(.key == $key) | .value | fromjson | .name')
|
|
vol=$(wpctl get-volume "$node" | awk '{printf "%d", $2 * 100}')
|
|
rows=$(printf '%s\n' "$devices" | while IFS="$(printf '\t')" read -r id name node_name; do
|
|
active=$([ "$node_name" = "$default_name" ] && echo ">" || echo "")
|
|
printf '%s\t%s\t%s\n' "$id" "$name" "$active"
|
|
done)
|
|
[ -z "$rows" ] && exit 0
|
|
w1=$(printf '%s\n' "$rows" | awk -F'\t' 'BEGIN{m=11}{l=length($2);if(l>m)m=l}END{print m}')
|
|
fw=$((w1 + pad + 10))
|
|
sep=$(awk -v n="$w1" 'BEGIN{for(i=0;i<n;i++)printf "─";print ""}')
|
|
indent=$(printf "%${pad}s" "")
|
|
active_prefix=$(printf " >%$((pad - 3))s" "")
|
|
header=$(printf "%s%s vol: %d%%\n%s%s" "$indent" "Device name" "$vol" "$indent" "$sep")
|
|
count=$(printf '%s\n' "$rows" | wc -l)
|
|
choice=$(printf '%s\n' "$rows" |
|
|
awk -F'\t' -v w1="$w1" -v indent="$indent" -v active_prefix="$active_prefix" '{
|
|
prefix = ($3 == ">") ? active_prefix : indent
|
|
printf "%s%-*s\t%s\n", prefix, w1, $2, $1
|
|
}' |
|
|
fuzzel --dmenu --prompt="$prompt" --no-icons --lines="$count" \
|
|
--with-nth=1 --accept-nth=2 \
|
|
--mesg="$header" --mesg-mode=expand \
|
|
--font="monospace:size=12" --width="$fw")
|
|
rc=$?
|
|
[ "$rc" = 11 ] && { wpctl set-volume "$node" 5%+ --limit 1.0; continue; }
|
|
[ "$rc" = 12 ] && { wpctl set-volume "$node" 5%-; continue; }
|
|
[ -z "$choice" ] && exit 0
|
|
wpctl set-default "$choice"
|
|
break
|
|
done
|
|
;;
|
|
*)
|
|
echo "Usage: ctl audio {sink|source}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
brightness)
|
|
require brightnessctl notify-send
|
|
BRIGHT_STEP=5
|
|
case "$2" in
|
|
up) brightnessctl set "$BRIGHT_STEP"%+ ;;
|
|
down) brightnessctl set "$BRIGHT_STEP"%- ;;
|
|
*)
|
|
echo "Usage: ctl brightness {up|down}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
pct=$(awk -v cur="$(brightnessctl get)" -v max="$(brightnessctl max)" 'BEGIN { printf "%d", cur * 100 / max }')
|
|
filled=$((pct / 5))
|
|
empty=$((20 - filled))
|
|
bar=""
|
|
i=0
|
|
while [ "$i" -lt "$filled" ]; do
|
|
bar="${bar}━"
|
|
i=$((i + 1))
|
|
done
|
|
i=0
|
|
while [ "$i" -lt "$empty" ]; do
|
|
bar="${bar}─"
|
|
i=$((i + 1))
|
|
done
|
|
notify-send -a ctl -t 2500 -r 5555 " $bar"
|
|
;;
|
|
volume)
|
|
require wpctl notify-send
|
|
SINK="@DEFAULT_AUDIO_SINK@"
|
|
VOL_STEP=5
|
|
get_vol() { wpctl get-volume "$SINK" | awk '{printf "%d", $2 * 100}'; }
|
|
case "$2" in
|
|
up) wpctl set-volume "$SINK" "${VOL_STEP}%+" --limit 1.0 ;;
|
|
down) wpctl set-volume "$SINK" "${VOL_STEP}%-" ;;
|
|
toggle) wpctl set-mute "$SINK" toggle ;;
|
|
*)
|
|
echo "Usage: ctl volume {up|down|toggle}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
vol=$(get_vol)
|
|
filled=$((vol / 5))
|
|
empty=$((20 - filled))
|
|
bar=""
|
|
i=0
|
|
while [ "$i" -lt "$filled" ]; do
|
|
bar="${bar}━"
|
|
i=$((i + 1))
|
|
done
|
|
i=0
|
|
while [ "$i" -lt "$empty" ]; do
|
|
bar="${bar}─"
|
|
i=$((i + 1))
|
|
done
|
|
if wpctl get-volume "$SINK" | grep -q MUTED; then
|
|
icon=""
|
|
elif [ "$vol" -le 33 ]; then
|
|
icon=""
|
|
elif [ "$vol" -le 66 ]; then
|
|
icon=""
|
|
else
|
|
icon=""
|
|
fi
|
|
notify-send -a ctl -t 2500 -r 5556 "$icon $bar"
|
|
;;
|
|
wifi)
|
|
case "$2" in
|
|
pick)
|
|
require fuzzel
|
|
station=$(iwctl device list 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | awk '/station/{print $1}')
|
|
[ -z "$station" ] && {
|
|
echo "ctl: no wifi device found" >&2
|
|
exit 1
|
|
}
|
|
while :; do
|
|
networks=$(iwctl station "$station" get-networks 2>/dev/null |
|
|
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' |
|
|
awk 'NR>4 && /\S/ && !/^[[:space:]]*-/' |
|
|
awk '{
|
|
active = ($0 ~ /^[[:space:]]*>/) ? ">" : ""
|
|
sub(/^[[:space:]>]*/, "")
|
|
sub(/[[:space:]]*$/, "")
|
|
i = index($0, " ")
|
|
if (i > 0) {
|
|
ssid = substr($0, 1, i - 1)
|
|
rest = substr($0, i)
|
|
sub(/^[[:space:]]*/, "", rest)
|
|
j = index(rest, " ")
|
|
if (j > 0) {
|
|
security = substr(rest, 1, j - 1)
|
|
signal = substr(rest, j)
|
|
sub(/^[[:space:]]*/, "", signal)
|
|
sub(/[[:space:]]*$/, "", signal)
|
|
} else {
|
|
security = rest
|
|
signal = ""
|
|
}
|
|
sub(/[[:space:]]*$/, "", ssid)
|
|
sub(/[[:space:]]*$/, "", security)
|
|
printf "%s\t%s\t%s\t%s\n", ssid, security, signal, active
|
|
}
|
|
}')
|
|
[ -z "$networks" ] && exit 0
|
|
w1=$(printf '%s\n' "$networks" | awk -F'\t' 'BEGIN{m=12}{l=length($1);if(l>m)m=l}END{print m}')
|
|
w2=$(printf '%s\n' "$networks" | awk -F'\t' 'BEGIN{m=8}{l=length($2);if(l>m)m=l}END{print m}')
|
|
w3=$(printf '%s\n' "$networks" | awk -F'\t' 'BEGIN{m=6}{l=length($3);if(l>m)m=l}END{print m}')
|
|
fw=$((w1 + 4 + w2 + 4 + w3 + 17))
|
|
sep=$(awk -v n="$((w1 + w2 + w3 + 8))" 'BEGIN{for(i=0;i<n;i++)printf "─";print ""}')
|
|
header=$(printf " %-*s %-*s %s\n %s" "$w1" "Network name" "$w2" "Security" "Signal" "$sep")
|
|
count=$(printf '%s\n' "$networks" | wc -l)
|
|
ssid=$(printf '%s\n' "$networks" |
|
|
awk -F'\t' -v w1="$w1" -v w2="$w2" '{
|
|
prefix = ($4 == ">") ? " > " : " "
|
|
printf "%s%-*s %-*s %s\t%s\n", prefix, w1, $1, w2, $2, $3, $1
|
|
}' |
|
|
fuzzel --dmenu --prompt="wifi: " --no-icons --lines="$count" \
|
|
--with-nth=1 --accept-nth=2 \
|
|
--mesg="$header" --mesg-mode=expand \
|
|
--font="monospace:size=12" --width="$fw")
|
|
rc=$?
|
|
[ "$rc" = 10 ] && continue
|
|
[ -z "$ssid" ] && exit 0
|
|
break
|
|
done
|
|
known=$(iwctl known-networks list 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g')
|
|
if printf '%s' "$known" | grep -qF "$ssid"; then
|
|
iwctl station "$station" connect "$ssid"
|
|
elif iwctl station "$station" get-networks 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' | grep -F "$ssid" | grep -qi "open"; then
|
|
iwctl station "$station" connect "$ssid"
|
|
else
|
|
pass=$(printf '' | fuzzel --dmenu --prompt="passphrase: " --no-icons --password --lines=0)
|
|
[ -z "$pass" ] && exit 0
|
|
iwctl station "$station" connect "$ssid" --passphrase "$pass"
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Usage: ctl wifi {pick}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
media)
|
|
if pgrep -x wf-recorder >/dev/null 2>&1; then
|
|
pkill -INT wf-recorder
|
|
file=$(cat "${XDG_RUNTIME_DIR:-/tmp}/ctl-recording" 2>/dev/null)
|
|
rm -f "${XDG_RUNTIME_DIR:-/tmp}/ctl-recording"
|
|
printf '%s' "$file" | wl-copy
|
|
notify-send -a ctl -t 2500 "Recording saved to ~${file#"$HOME"}"
|
|
exit 0
|
|
fi
|
|
pkill -x fuzzel 2>/dev/null && exit 0
|
|
require fuzzel grim slurp wl-copy wf-recorder hyprctl jq tesseract
|
|
ss_dir="${XDG_PICTURES_DIR:-$HOME/Pictures}/Screenshots"
|
|
rec_dir="${XDG_VIDEOS_DIR:-$HOME/Videos}"
|
|
mkdir -p "$ss_dir" "$rec_dir"
|
|
cap_desktop=" Capture Screen"
|
|
cap_area=" Capture Area"
|
|
cap_window=" Capture Window"
|
|
rec_desktop=" Record Screen"
|
|
rec_area=" Record Area"
|
|
rec_window=" Record Window"
|
|
ocr_area=" OCR Area"
|
|
chosen="$(printf '%s\n' "$cap_desktop" "$cap_area" "$cap_window" "$rec_desktop" "$rec_area" "$rec_window" "$ocr_area" | fuzzel --dmenu --hide-prompt --lines=7 --width=25 --no-icons 2>/dev/null)"
|
|
case "$chosen" in
|
|
"$cap_desktop")
|
|
file="$ss_dir/$(date +'%Y-%m-%d_%H-%M-%S').png"
|
|
grim "$file" && wl-copy <"$file" && echo "$file" && notify-send -a ctl -t 2500 "Screenshot saved to ~${file#"$HOME"}"
|
|
;;
|
|
"$cap_area")
|
|
file="$ss_dir/$(date +'%Y-%m-%d_%H-%M-%S').png"
|
|
grim -g "$(slurp)" "$file" && wl-copy <"$file" && echo "$file" && notify-send -a ctl -t 2500 "Screenshot saved to ~${file#"$HOME"}"
|
|
;;
|
|
"$cap_window")
|
|
geom=$(hyprctl activewindow -j | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')
|
|
file="$ss_dir/$(date +'%Y-%m-%d_%H-%M-%S').png"
|
|
grim -g "$geom" "$file" && wl-copy <"$file" && echo "$file" && notify-send -a ctl -t 2500 "Screenshot saved to ~${file#"$HOME"}"
|
|
;;
|
|
"$rec_desktop")
|
|
file="$rec_dir/$(date +'%Y-%m-%d_%H-%M-%S').mp4"
|
|
echo "$file" >"${XDG_RUNTIME_DIR:-/tmp}/ctl-recording"
|
|
notify-send -a ctl -t 2500 "Recording started"
|
|
wf-recorder -f "$file" &
|
|
;;
|
|
"$rec_area")
|
|
file="$rec_dir/$(date +'%Y-%m-%d_%H-%M-%S').mp4"
|
|
echo "$file" >"${XDG_RUNTIME_DIR:-/tmp}/ctl-recording"
|
|
notify-send -a ctl -t 2500 "Recording started"
|
|
wf-recorder -g "$(slurp)" -f "$file" &
|
|
;;
|
|
"$rec_window")
|
|
geom=$(hyprctl activewindow -j | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')
|
|
file="$rec_dir/$(date +'%Y-%m-%d_%H-%M-%S').mp4"
|
|
echo "$file" >"${XDG_RUNTIME_DIR:-/tmp}/ctl-recording"
|
|
notify-send -a ctl -t 2500 "Recording started"
|
|
wf-recorder -g "$geom" -f "$file" &
|
|
;;
|
|
"$ocr_area")
|
|
file="$ss_dir/$(date +'%Y-%m-%d_%H-%M-%S').png"
|
|
region="$(slurp)" || exit 0
|
|
[ -n "$region" ] || exit 0
|
|
grim -g "$region" "$file" && tesseract -l eng "$file" - 2>/dev/null | wl-copy
|
|
;;
|
|
esac
|
|
;;
|
|
wallpaper)
|
|
require python
|
|
python - "$2" <<'PYTHON'
|
|
import os
|
|
import random
|
|
import subprocess
|
|
import sys
|
|
|
|
try:
|
|
from PIL import Image, ImageDraw
|
|
except ImportError:
|
|
print("ctl: missing dependency: pillow", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
HOME = os.environ["HOME"]
|
|
DIR = os.path.join(os.environ.get("XDG_PICTURES_DIR", os.path.join(HOME, "Pictures")), "Screensavers")
|
|
os.makedirs(DIR, exist_ok=True)
|
|
|
|
|
|
def get_resolution():
|
|
output = "1920x1080"
|
|
if "WAYLAND_DISPLAY" in os.environ:
|
|
desktop = os.environ.get("XDG_CURRENT_DESKTOP", "")
|
|
if desktop == "Hyprland":
|
|
output = (
|
|
subprocess.check_output(
|
|
"hyprctl monitors -j | jq -r '.[] | select(.focused==true) | .width, .height' | paste -sd x -",
|
|
shell=True,
|
|
)
|
|
.decode()
|
|
.strip()
|
|
)
|
|
elif desktop == "sway":
|
|
output = (
|
|
subprocess.check_output(
|
|
"swaymsg -t get_outputs -r | jq -r '.[] | select(.active==true) | .current_mode.width,.current_mode.height' | paste -sd x -",
|
|
shell=True,
|
|
)
|
|
.decode()
|
|
.strip()
|
|
)
|
|
else:
|
|
output = (
|
|
subprocess.check_output(
|
|
"xrandr | grep '*' | awk '{print $1}'", shell=True
|
|
)
|
|
.decode()
|
|
.strip()
|
|
)
|
|
return map(int, output.split("x"))
|
|
|
|
|
|
def lock():
|
|
W, H = get_resolution()
|
|
UNIT = 16
|
|
grid_w = W // UNIT
|
|
grid_h = H // UNIT
|
|
|
|
bg_color = tuple(random.randint(0, 255) for _ in range(3))
|
|
img = Image.new("RGB", (W, H), bg_color)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
MU = 0.8
|
|
SIGMA = 0.7
|
|
SCALE_FACTOR = 1.8
|
|
|
|
S = {(x, y) for x in range(grid_w) for y in range(grid_h)}
|
|
N = len(S)
|
|
|
|
while S:
|
|
if random.random() < 1 / N:
|
|
break
|
|
gx, gy = S.pop()
|
|
w_units = max(
|
|
1,
|
|
min(
|
|
grid_w - gx,
|
|
int(round(random.lognormvariate(MU, SIGMA) * SCALE_FACTOR)),
|
|
),
|
|
)
|
|
h_units = max(
|
|
1,
|
|
min(
|
|
grid_h - gy,
|
|
int(round(random.lognormvariate(MU, SIGMA) * SCALE_FACTOR)),
|
|
),
|
|
)
|
|
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
|
|
|
dx = random.choice([1, -1])
|
|
dy = random.choice([1, -1])
|
|
|
|
gx_end = gx + dx * (w_units - 1)
|
|
gy_end = gy + dy * (h_units - 1)
|
|
|
|
x0, x1 = sorted([gx, gx_end])
|
|
y0, y1 = sorted([gy, gy_end])
|
|
|
|
draw.rectangle(
|
|
[x0 * UNIT, y0 * UNIT, (x1 + 1) * UNIT - 1, (y1 + 1) * UNIT - 1],
|
|
fill=color,
|
|
)
|
|
|
|
img.save(f"{DIR}/lock.jpg", quality=95)
|
|
|
|
|
|
def wall():
|
|
W, H = get_resolution()
|
|
|
|
colors = [
|
|
"#aa0000",
|
|
"#ff3333",
|
|
"#ff7777",
|
|
"#ffbb55",
|
|
"#ffcc88",
|
|
"#ff88ff",
|
|
"#aaaaff",
|
|
"#77ddbb",
|
|
"#77ff77",
|
|
"#cccccc",
|
|
]
|
|
|
|
colors.reverse()
|
|
|
|
img = Image.new("RGB", (W, H), "white")
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
num_bars = len(colors)
|
|
|
|
for i, color in enumerate(reversed(colors)):
|
|
top = round(i * H / num_bars)
|
|
bottom = round((i + 1) * H / num_bars)
|
|
draw.rectangle([0, top, W, bottom], fill=color)
|
|
|
|
img.save(f"{DIR}/wallpaper.jpg", quality=95)
|
|
|
|
|
|
cmd = sys.argv[1] if len(sys.argv) > 1 else None
|
|
if cmd == "lock":
|
|
lock()
|
|
elif cmd == "wall":
|
|
wall()
|
|
else:
|
|
print("Usage: ctl wallpaper {wall|lock}", file=sys.stderr)
|
|
sys.exit(1)
|
|
PYTHON
|
|
;;
|
|
power)
|
|
require fuzzel
|
|
lock=" Lock"
|
|
suspend=" Suspend"
|
|
logout=" Logout"
|
|
reboot=" Reboot"
|
|
shutdown=" Shutdown"
|
|
chosen="$(printf '%s\n' "$lock" "$suspend" "$logout" "$reboot" "$shutdown" | fuzzel --dmenu --hide-prompt --lines=5 --width=20 --no-icons)"
|
|
case "$chosen" in
|
|
"$lock") hyprlock ;;
|
|
"$suspend") systemctl suspend ;;
|
|
"$logout") hyprctl dispatch exit ;;
|
|
"$reboot") systemctl reboot ;;
|
|
"$shutdown") systemctl poweroff ;;
|
|
esac
|
|
;;
|
|
idle)
|
|
require notify-send
|
|
if systemctl --user is-active --quiet hypridle.service; then
|
|
systemctl --user stop hypridle.service
|
|
tmux set -g lock-after-time 0 2>/dev/null
|
|
notify-send -a ctl -t 2500 'idle off'
|
|
else
|
|
systemctl --user start hypridle.service
|
|
tmux set -g lock-after-time 300 2>/dev/null
|
|
notify-send -a ctl -t 2500 'idle on'
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Usage: ctl {screenshot|keyboard|audio|wifi|brightness|volume|media|wallpaper|power|idle}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|