mirror of
https://github.com/addyosmani/agent-skills.git
synced 2026-10-26 15:05:04 +00:00
436 lines
18 KiB
Bash
Executable File
436 lines
18 KiB
Bash
Executable File
#!/bin/bash
|
|
# simplify-ignore.sh — Hook for Read (PreToolUse), Edit|Write (PostToolUse), Stop
|
|
#
|
|
# PreToolUse Read → backs up file, replaces blocks with BLOCK_<hash> in-place
|
|
# PostToolUse Edit → expands placeholders, re-filters so file stays hidden
|
|
# PostToolUse Write → expands placeholders, re-filters so file stays hidden
|
|
# Stop → expands the placeholders still in the file on disk, so a
|
|
# change made by any route survives; the backup is used
|
|
# only when no placeholder is left to expand
|
|
#
|
|
# The file on disk ALWAYS has placeholders while the session is active.
|
|
# The real content is that file with its placeholders expanded; the backup
|
|
# holds the last state the hook itself saw.
|
|
#
|
|
# Dependencies: jq, shasum or sha1sum (auto-detected)
|
|
|
|
set -euo pipefail
|
|
|
|
# Bash 5.2+ turns on patsub_replacement by default, which makes `&` and
|
|
# backslash special on the replacement side of ${var//pattern/replacement}:
|
|
# `&` expands to the matched text and `\\` collapses. expand_file substitutes
|
|
# raw block content there, and code routinely contains `&&` and backslashes,
|
|
# so the option must be off or protected blocks come back corrupted on Linux.
|
|
# Older bashes do not know the option; ignore the error there.
|
|
shopt -u patsub_replacement 2>/dev/null || true
|
|
|
|
if ! command -v jq >/dev/null 2>&1; then
|
|
printf '%s\n' "error: missing jq" >&2; exit 1
|
|
fi
|
|
|
|
CACHE="${CLAUDE_PROJECT_DIR:-.}/.claude/.simplify-ignore-cache"
|
|
if [ -t 0 ]; then INPUT="{}"; else INPUT=$(cat); fi
|
|
|
|
# Parse hook input — trap errors explicitly so set -e doesn't cause
|
|
# a silent exit on malformed JSON, and surface a useful diagnostic.
|
|
parse_error=""
|
|
TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null) || {
|
|
parse_error="failed to parse .tool_name from hook input"
|
|
TOOL_NAME=""
|
|
}
|
|
FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null) || {
|
|
parse_error="failed to parse .tool_input.file_path from hook input"
|
|
FILE_PATH=""
|
|
}
|
|
if [ -n "$parse_error" ]; then
|
|
printf 'Warning: %s (input: %.120s)\n' "$parse_error" "$INPUT" >&2
|
|
fi
|
|
|
|
hash_cmd() {
|
|
if command -v shasum >/dev/null 2>&1; then shasum
|
|
elif command -v sha1sum >/dev/null 2>&1; then sha1sum
|
|
else printf '%s\n' "error: missing shasum or sha1sum" >&2; exit 1; fi
|
|
}
|
|
file_id() { printf '%s' "$1" | hash_cmd | cut -c1-16; }
|
|
block_hash() { printf '%s' "$1" | hash_cmd | cut -c1-8; }
|
|
# Escape glob metacharacters so ${var/pattern/repl} treats pattern as literal.
|
|
# Needed for Bash 3.2 (macOS) where quotes don't suppress globbing in PE patterns.
|
|
escape_glob() {
|
|
local s="$1"
|
|
s="${s//\\/\\\\}"
|
|
s="${s//\*/\\*}"
|
|
s="${s//\?/\\?}"
|
|
s="${s//\[/\\[}"
|
|
printf '%s' "$s"
|
|
}
|
|
|
|
# ── filter_file: replace simplify-ignore blocks with BLOCK_<hash> placeholders ─
|
|
# Reads $1 (source), writes filtered version to $2 (dest), saves blocks to cache.
|
|
# Returns 0 if blocks were found, 1 if none.
|
|
filter_file() {
|
|
local src="$1" dest="$2" fid="$3"
|
|
: > "$dest"
|
|
rm -f "$CACHE/${fid}".block.* "$CACHE/${fid}".reason.* "$CACHE/${fid}".prefix.* "$CACHE/${fid}".suffix.*
|
|
|
|
local count=0 in_block=0 buf="" reason="" prefix="" suffix=""
|
|
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
# Check for start marker (no fork — uses bash case)
|
|
if [ $in_block -eq 0 ]; then
|
|
case "$line" in *simplify-ignore-start*)
|
|
in_block=1
|
|
buf="$line"
|
|
# Extract comment prefix/suffix to preserve language-appropriate syntax
|
|
prefix="${line%%simplify-ignore-start*}"
|
|
suffix=""
|
|
case "$line" in *'*/'*) suffix=" */" ;; *'-->'*) suffix=" -->" ;; esac
|
|
reason=$(printf '%s' "$line" | sed -n 's/.*simplify-ignore-start:[[:space:]]*//p' \
|
|
| sed 's/[[:space:]]*\*\/.*$//' | sed 's/[[:space:]]*-->.*$//' | sed 's/[[:space:]]*$//')
|
|
# Handle single-line block (start + end on same line)
|
|
case "$line" in *simplify-ignore-end*)
|
|
in_block=0
|
|
# Write single-line block immediately and skip to next line
|
|
# to avoid the end-marker check below firing again
|
|
local h; h=$(block_hash "$buf")
|
|
count=$((count + 1))
|
|
printf '%s' "$buf" > "$CACHE/${fid}.block.${h}"
|
|
[ -n "$reason" ] && printf '%s' "$reason" > "$CACHE/${fid}.reason.${h}"
|
|
printf '%s' "$prefix" > "$CACHE/${fid}.prefix.${h}"
|
|
printf '%s' "$suffix" > "$CACHE/${fid}.suffix.${h}"
|
|
if [ -n "$reason" ]; then
|
|
printf '%s\n' "${prefix}BLOCK_${h}: ${reason}${suffix}" >> "$dest"
|
|
else
|
|
printf '%s\n' "${prefix}BLOCK_${h}${suffix}" >> "$dest"
|
|
fi
|
|
buf=""; reason=""; prefix=""; suffix=""
|
|
continue
|
|
;; *)
|
|
continue
|
|
;;
|
|
esac
|
|
;; esac
|
|
fi
|
|
# Accumulate block content
|
|
if [ $in_block -eq 1 ]; then
|
|
buf="${buf}
|
|
${line}"
|
|
fi
|
|
# Check for end marker
|
|
case "$line" in *simplify-ignore-end*)
|
|
if [ $in_block -eq 1 ]; then
|
|
local h; h=$(block_hash "$buf")
|
|
count=$((count + 1))
|
|
printf '%s' "$buf" > "$CACHE/${fid}.block.${h}"
|
|
[ -n "$reason" ] && printf '%s' "$reason" > "$CACHE/${fid}.reason.${h}"
|
|
printf '%s' "$prefix" > "$CACHE/${fid}.prefix.${h}"
|
|
printf '%s' "$suffix" > "$CACHE/${fid}.suffix.${h}"
|
|
if [ -n "$reason" ]; then
|
|
printf '%s\n' "${prefix}BLOCK_${h}: ${reason}${suffix}" >> "$dest"
|
|
else
|
|
printf '%s\n' "${prefix}BLOCK_${h}${suffix}" >> "$dest"
|
|
fi
|
|
in_block=0; buf=""; reason=""; prefix=""; suffix=""
|
|
continue
|
|
fi
|
|
;;
|
|
esac
|
|
[ $in_block -eq 0 ] && printf '%s\n' "$line" >> "$dest"
|
|
done < "$src"
|
|
|
|
# Unclosed block → flush as-is
|
|
if [ $in_block -eq 1 ] && [ -n "$buf" ]; then
|
|
printf 'Warning: unclosed simplify-ignore-start in %s (block not hidden)\n' "$src" >&2
|
|
printf '%s\n' "$buf" >> "$dest"
|
|
fi
|
|
|
|
# Preserve trailing newline status of source
|
|
if [ -s "$dest" ] && [ -s "$src" ] && [ -n "$(tail -c 1 "$src")" ]; then
|
|
perl -pe 'chomp if eof' "$dest" > "${dest}.nnl" && \
|
|
cat "${dest}.nnl" > "$dest" && rm -f "${dest}.nnl"
|
|
fi
|
|
|
|
[ $count -gt 0 ] && return 0 || return 1
|
|
}
|
|
|
|
# ── expand_file: replace BLOCK_<hash> placeholders with the real block code ───
|
|
# Reads $1 (source), writes the expanded version to $2 (dest), using the blocks
|
|
# cached under $3 (file id). Warns on placeholders that were altered or deleted.
|
|
expand_file() {
|
|
local src="$1" dest="$2" fid="$3"
|
|
local line bf h bp bs br placeholder block_content esc_placeholder esc_fuzzy bh first_line
|
|
rm -f "$dest"
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
case "$line" in *BLOCK_*)
|
|
# Expand all placeholders on this line (supports multiple per line)
|
|
for bf in "$CACHE/${fid}".block.*; do
|
|
[ -f "$bf" ] || continue
|
|
h="${bf##*.}"
|
|
case "$line" in *"BLOCK_${h}"*)
|
|
# Reconstruct the exact placeholder pattern
|
|
bp=""; bs=""; br=""
|
|
[ -f "$CACHE/${fid}.prefix.${h}" ] && bp=$(cat "$CACHE/${fid}.prefix.${h}")
|
|
[ -f "$CACHE/${fid}.suffix.${h}" ] && bs=$(cat "$CACHE/${fid}.suffix.${h}")
|
|
[ -f "$CACHE/${fid}.reason.${h}" ] && br=$(cat "$CACHE/${fid}.reason.${h}")
|
|
if [ -n "$br" ]; then
|
|
placeholder="${bp}BLOCK_${h}: ${br}${bs}"
|
|
else
|
|
placeholder="${bp}BLOCK_${h}${bs}"
|
|
fi
|
|
block_content=$(cat "$bf"; printf x); block_content="${block_content%x}"
|
|
# Escape glob metacharacters (* ? [ \) in the pattern
|
|
esc_placeholder=$(escape_glob "$placeholder")
|
|
# Bash native substitution (// = global replace): replace placeholder, keep surrounding code
|
|
line="${line//$esc_placeholder/$block_content}"
|
|
# Fallback: if model altered the reason text, try without reason
|
|
# (only trigger if BLOCK_hash is still present AND wasn't in the original block content)
|
|
case "$block_content" in *"BLOCK_${h}"*) ;; *)
|
|
case "$line" in *"BLOCK_${h}"*)
|
|
printf 'Warning: placeholder BLOCK_%s was modified by model, using fuzzy match\n' "$h" >&2
|
|
esc_fuzzy=$(escape_glob "${bp}BLOCK_${h}${bs}")
|
|
line="${line//$esc_fuzzy/$block_content}"
|
|
# Last resort: match just the hash token
|
|
case "$line" in *"BLOCK_${h}"*)
|
|
line="${line//BLOCK_${h}/$block_content}"
|
|
;; esac
|
|
;; esac
|
|
;; esac
|
|
;; esac
|
|
done
|
|
;; esac
|
|
printf '%s\n' "$line" >> "$dest"
|
|
done < "$src"
|
|
# Preserve trailing newline status
|
|
if [ -s "$dest" ] && [ -s "$src" ] && [ -n "$(tail -c 1 "$src")" ]; then
|
|
perl -pe 'chomp if eof' "$dest" > "${dest}.nnl" && \
|
|
cat "${dest}.nnl" > "$dest" && rm -f "${dest}.nnl"
|
|
fi
|
|
# Warn if model deleted a protected block entirely
|
|
for bf in "$CACHE/${fid}".block.*; do
|
|
[ -f "$bf" ] || continue
|
|
bh="${bf##*.}"
|
|
# After expansion, blocks appear as original code (simplify-ignore-start).
|
|
# If neither the expanded code nor the placeholder is in EXPANDED, it was deleted.
|
|
if ! grep -qF "BLOCK_${bh}" "$dest" 2>/dev/null; then
|
|
# Get first line of block to check if it was expanded back
|
|
first_line=$(head -1 "$bf")
|
|
if ! grep -qF "$first_line" "$dest" 2>/dev/null; then
|
|
printf 'Warning: protected block BLOCK_%s was deleted by model\n' "$bh" >&2
|
|
fi
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# -- missing_placeholders: which cached BLOCK_<hash> of $2 are gone from $1? --
|
|
# Prints the missing placeholders, one per line, and returns 0 if any is gone.
|
|
# A placeholder stands for code the model never saw, so it cannot have removed
|
|
# it on purpose; whichever route removed it, the block must not be lost with it.
|
|
missing_placeholders() {
|
|
local f="$1" fid="$2" bf h bp bs br out=""
|
|
for bf in "$CACHE/${fid}".block.*; do
|
|
[ -f "$bf" ] || continue
|
|
h="${bf##*.}"
|
|
grep -qF "BLOCK_${h}" "$f" 2>/dev/null && continue
|
|
bp=""; bs=""; br=""
|
|
[ -f "$CACHE/${fid}.prefix.${h}" ] && bp=$(cat "$CACHE/${fid}.prefix.${h}")
|
|
[ -f "$CACHE/${fid}.suffix.${h}" ] && bs=$(cat "$CACHE/${fid}.suffix.${h}")
|
|
[ -f "$CACHE/${fid}.reason.${h}" ] && br=": $(cat "$CACHE/${fid}.reason.${h}")"
|
|
out="${out} ${bp}BLOCK_${h}${br}${bs}
|
|
"
|
|
done
|
|
[ -n "$out" ] || return 1
|
|
printf '%s' "$out"
|
|
}
|
|
|
|
# ── has_placeholders: is a cached BLOCK_<hash> for $2 still present in file $1? ─
|
|
has_placeholders() {
|
|
local f="$1" fid="$2" bf h
|
|
for bf in "$CACHE/${fid}".block.*; do
|
|
[ -f "$bf" ] || continue
|
|
h="${bf##*.}"
|
|
grep -qF "BLOCK_${h}" "$f" 2>/dev/null && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# -- file_is_whole: was the real file put back on disk while it was filtered? --
|
|
# True when no placeholder of $2 is in file $1 and every cached block is there
|
|
# verbatim (blocks are content-hashed, so filtering a probe copy compares them
|
|
# exactly). A git checkout, restore, stash or reset, or an editor undo, does
|
|
# this; the model cannot, because it never saw the block text.
|
|
file_is_whole() {
|
|
local f="$1" fid="$2" probe bf whole=0
|
|
probe="${fid}.probe.$$"
|
|
has_placeholders "$f" "$fid" && return 1
|
|
grep -q 'simplify-ignore-start' -- "$f" 2>/dev/null || return 1
|
|
if filter_file "$f" "$CACHE/${probe}.tmp" "$probe" 2>/dev/null; then
|
|
whole=1
|
|
for bf in "$CACHE/${fid}".block.*; do
|
|
[ -f "$bf" ] && [ -f "$CACHE/${probe}.block.${bf##*.}" ] || { whole=0; break; }
|
|
done
|
|
fi
|
|
rm -f "$CACHE/${probe}".*
|
|
[ "$whole" -eq 1 ]
|
|
}
|
|
|
|
# -- set_aside_backup: the file on disk supersedes the backup; keep a copy ----
|
|
set_aside_backup() {
|
|
local f="$1" fid="$2" kept
|
|
cmp -s "$CACHE/${fid}.bak" "$f" && return 0
|
|
kept="$CACHE/${fid}.superseded.$$"
|
|
cp "$CACHE/${fid}.bak" "$kept"
|
|
printf 'simplify-ignore: %s was put back whole while filtered (git checkout, stash, undo); keeping it. The previous session state is kept at %s\n' \
|
|
"$f" "$kept" >&2
|
|
}
|
|
|
|
# ── Stop: expand each cached file in place, backup only as fallback ──────────
|
|
if [ -z "$TOOL_NAME" ]; then
|
|
[ -d "$CACHE" ] || exit 0
|
|
for bak in "$CACHE"/*.bak; do
|
|
[ -f "$bak" ] || continue
|
|
fid="${bak##*/}"; fid="${fid%.bak}"
|
|
pathfile="$CACHE/${fid}.path"
|
|
[ -f "$pathfile" ] || { rm -f "$bak"; continue; }
|
|
orig=$(cat "$pathfile")
|
|
if [ -f "$orig" ]; then
|
|
# A change can reach the file through a route that fires no Edit or Write
|
|
# event (a Bash command, a formatter, an external editor), and the backup
|
|
# is stale for all of them. Expand what is on disk rather than overwrite it.
|
|
if file_is_whole "$orig" "$fid"; then
|
|
# The real file is back (the change was reverted with git or undone).
|
|
# It is newer than the backup, which would bring the reverted change
|
|
# back, so keep the file and move the backup aside.
|
|
set_aside_backup "$orig" "$fid"
|
|
elif has_placeholders "$orig" "$fid" && ! missing_placeholders "$orig" "$fid" >/dev/null; then
|
|
EXPANDED="$CACHE/${fid}.$$.expanded"
|
|
expand_file "$orig" "$EXPANDED" "$fid"
|
|
cat "$EXPANDED" > "$orig"
|
|
rm -f "$EXPANDED"
|
|
else
|
|
# A placeholder is gone — the file was rewritten wholesale, or one
|
|
# block's line was deleted — so the backup is the only remaining copy
|
|
# of that protected block. Keep the rewrite in the cache (with any
|
|
# surviving placeholders expanded) before the backup overwrites it, so
|
|
# the work is recoverable rather than lost.
|
|
rewritten="$CACHE/${fid}.recovered"
|
|
if has_placeholders "$orig" "$fid"; then
|
|
expand_file "$orig" "$rewritten" "$fid" 2>/dev/null
|
|
else
|
|
cat "$orig" > "$rewritten"
|
|
fi
|
|
cat "$bak" > "$orig"
|
|
printf 'Warning: a BLOCK_ placeholder is missing from %s, restored from backup. Rewrite kept at %s\n' \
|
|
"$orig" "$rewritten" >&2
|
|
fi
|
|
rm -f "$bak" "$pathfile" "$CACHE/${fid}".block.* "$CACHE/${fid}".reason.* "$CACHE/${fid}".prefix.* "$CACHE/${fid}".suffix.*
|
|
rmdir "$CACHE/${fid}.lock" 2>/dev/null
|
|
else
|
|
# File was moved/deleted — save backup as .recovered, don't destroy it
|
|
mkdir -p "$(dirname "${orig}.recovered")"
|
|
mv "$bak" "${orig}.recovered"
|
|
rm -f "$pathfile" "$CACHE/${fid}".block.* "$CACHE/${fid}".reason.* "$CACHE/${fid}".prefix.* "$CACHE/${fid}".suffix.*
|
|
rmdir "$CACHE/${fid}.lock" 2>/dev/null
|
|
printf 'Warning: %s was moved/deleted. Recovered original to %s.recovered\n' "$orig" "$orig" >&2
|
|
fi
|
|
done
|
|
# Clean orphan locks (created but crash before backup)
|
|
for lockdir in "$CACHE"/*.lock; do
|
|
[ -d "$lockdir" ] || continue
|
|
rmdir "$lockdir" 2>/dev/null
|
|
done
|
|
exit 0
|
|
fi
|
|
|
|
[ -z "$FILE_PATH" ] && exit 0
|
|
|
|
# ── PreToolUse Read: filter in-place ──────────────────────────────────────────
|
|
if [ "$TOOL_NAME" = "Read" ]; then
|
|
[ -f "$FILE_PATH" ] || exit 0
|
|
case "$(basename "$FILE_PATH")" in simplify-ignore*|SIMPLIFY-IGNORE*) exit 0 ;; esac
|
|
|
|
mkdir -p "$CACHE"
|
|
ID=$(file_id "$FILE_PATH")
|
|
|
|
# If backup exists, file is already filtered — skip
|
|
# unless the real file was put back meanwhile (git checkout, stash, undo):
|
|
# skipping then would show the model every protected block, so take that
|
|
# file as the new original and filter it again.
|
|
if [ -f "$CACHE/${ID}.bak" ]; then
|
|
file_is_whole "$FILE_PATH" "$ID" || exit 0
|
|
set_aside_backup "$FILE_PATH" "$ID"
|
|
REFILTER=1
|
|
else
|
|
grep -q 'simplify-ignore-start' -- "$FILE_PATH" || exit 0
|
|
REFILTER=0
|
|
fi
|
|
|
|
# Atomic lock: mkdir fails if another session races us
|
|
# (a refilter already holds the lock from the first Read)
|
|
if [ "$REFILTER" -eq 0 ] && ! mkdir "$CACHE/${ID}.lock" 2>/dev/null; then
|
|
# Lock exists — reclaim only if stale (>60s old, no backup = crash leftover)
|
|
if [ ! -f "$CACHE/${ID}.bak" ] && \
|
|
[ -n "$(find "$CACHE/${ID}.lock" -maxdepth 0 -mmin +1 2>/dev/null)" ]; then
|
|
rmdir "$CACHE/${ID}.lock" 2>/dev/null || true
|
|
mkdir "$CACHE/${ID}.lock" 2>/dev/null || exit 0
|
|
else
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Back up the original (preserve trailing newline status)
|
|
cp -p "$FILE_PATH" "$CACHE/${ID}.bak" 2>/dev/null || cp "$FILE_PATH" "$CACHE/${ID}.bak"
|
|
printf '%s' "$FILE_PATH" > "$CACHE/${ID}.path"
|
|
|
|
# Filter in-place (cat > preserves inode and permissions)
|
|
FILTERED="$CACHE/${ID}.$$.tmp"
|
|
rm -f "$FILTERED"
|
|
if filter_file "$FILE_PATH" "$FILTERED" "$ID"; then
|
|
cat "$FILTERED" > "$FILE_PATH"
|
|
rm -f "$FILTERED"
|
|
else
|
|
rm -f "$FILTERED" "$CACHE/${ID}.bak" "$CACHE/${ID}.path"
|
|
rmdir "$CACHE/${ID}.lock" 2>/dev/null
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# ── PostToolUse Edit|Write: expand, then re-filter ────────────────────────────
|
|
if [ "$TOOL_NAME" = "Edit" ] || [ "$TOOL_NAME" = "Write" ]; then
|
|
ID=$(file_id "$FILE_PATH")
|
|
[ -f "$CACHE/${ID}.bak" ] || exit 0
|
|
ls "$CACHE/${ID}".block.* >/dev/null 2>&1 || exit 0
|
|
|
|
# The edit removed a placeholder. Expanding now would save a backup without
|
|
# that block, and Stop would then restore the loss. Keep the last good
|
|
# backup, leave the file as edited, and tell the model (exit 2 sends stderr
|
|
# back to it) so it can put the placeholder back; if it does not, Stop
|
|
# restores the backup and keeps this version as <id>.recovered.
|
|
if dropped=$(missing_placeholders "$FILE_PATH" "$ID"); then
|
|
printf '%s\n%s\n%s\n' \
|
|
"simplify-ignore: this $TOOL_NAME removed placeholder line(s) from $FILE_PATH. Each stands for protected code you cannot see:" \
|
|
"$dropped" \
|
|
"Put each one back exactly as shown. Until then the backup is not updated, and at session end the file is restored from it (this version is kept in the cache as .recovered)." >&2
|
|
exit 2
|
|
fi
|
|
|
|
# Expand placeholders, preserving any inline code the model added around them
|
|
EXPANDED="$CACHE/${ID}.$$.expanded"
|
|
expand_file "$FILE_PATH" "$EXPANDED" "$ID"
|
|
# Preserve inode and permissions
|
|
cat "$EXPANDED" > "$FILE_PATH"
|
|
rm -f "$EXPANDED"
|
|
|
|
# Save expanded version as new backup (this is the "real" file with model's changes)
|
|
cp "$FILE_PATH" "$CACHE/${ID}.bak"
|
|
|
|
# Re-filter in-place so the file on disk stays with placeholders
|
|
FILTERED="$CACHE/${ID}.$$.tmp"
|
|
rm -f "$FILTERED"
|
|
if filter_file "$FILE_PATH" "$FILTERED" "$ID"; then
|
|
cat "$FILTERED" > "$FILE_PATH"
|
|
rm -f "$FILTERED"
|
|
fi
|
|
|
|
exit 0
|
|
fi
|