#!/bin/bash
# Multi-call binary generated by LACKADAISICAL binbox
# daisy information:
# Contained modules: binbox calm cdz editx filewait newday own short shrc sw what
# Files included verbatim: daisy.source
# Files sourced: 
# Symlink to this binary with the module name to invoke it, or
# use 'daisy <func>' to do the same.

# Included file daisy.source
#!/bin/echo "This file can only be sourced, not run stand-alone." -- #!/bin/bash
# LACKADAISICAL SOURCE-ABLE FILE

# Source this in your RC file or manually to receive some of the simpler
# utilities, as well as aliases for `shrc` and `cdf`. Set env variable
# FROM_RC to 1 when sourcing this file to get RC-related functionality:
# FROM_RC=1 source <lackadaisical-root>/daisy.source

# This file is also sourced in some of the scripts included within
# lackadaisical for common functionality. Some of the shared functionality is
# only included if sourced from one of the included scripts, though you are
# free to bypass this by setting env variable DAISY_INTERNAL to 1.

if [[ $DAISY_INTERNAL -eq 1 ]];
then
  export DAISY_BIN=$(basename $0)
fi

# Intro function
function daisy_help()
{
   OLD_IFS="$IFS"
   IFS=
   echo -e "==================================================================="
   echo -e ""
   echo -e "Thanks for installing LACKADAISICAL!"
   echo -e "This project aims to provide useful utilities as well as learning"
   echo -e "material."
   echo -e ""
   echo -e "It is still under heavy development, not all of the things on this"
   echo -e "list are present/implemented. Utils marked with * are incomplete."
   echo -e ""
   echo -e "==================================================================="
   echo -e ""
   echo -e "This suite provides a number of functions, aliases and scripts."
   echo -e "They are all aimed at enhancing your efficiency."
   echo -e ""
   echo -e "==================================================================="
   echo -e ""
   echo -e "These are the included binaries:"
   echo -e " - calm:       Reduce a process niceness to 0."
   echo -e " - cdz:        This utility extracts an archive to /tmp and changes"
   echo -e "               directory to it in a new shell instance. Upon exit,"
   echo -e "               the files are wiped. If \`archivemount\` is present,"
   echo -e "               it will be used to mount the archive instead! You can"
   echo -e "               bypass this behavior by specifying an env value of;"
   echo -e "               NO_ARCHIVEMOUNT=1. The standard script supports zip,"
   echo -e "               tarballs, and rar archives. We recommend relying on"
   echo -e "               \`archivemount\` if you have it installed."
   echo -e " - editx:      Uses your standard CLI editor to create/modify a"
   echo -e "               file and make it executable."
   echo -e " - filewait:   This tool is given a filename of a file that does"
   echo -e "               not exist yet. When the file appears on disk, the"
   echo -e "               program quits and simply returns the filename. This"
   echo -e "               can be used in personal workflows."
   echo -e " - newday:     A basic but powerful journaling system. Recommended"
   echo -e "               to set up via crontab. Can be used for everything"
   echo -e "               from diaries to BTRFS snapshots."
   echo -e " - own:        A simple utility. It effectively uses chown -R"
   echo -e "               user:user on its target. Root permissions required!"
   echo -e " - short:      This tool allows you to set up directory shortcuts."
   echo -e "               It enhances cd t to integrate itsef using its own"
   echo -e "               syntax. It is similar to wd."
   echo -e " - shrc:       This tool allows you to edit the RC file for your"
   echo -e "               shell in your preferred editor. After saving, the"
   echo -e "               file is sourced by your shell."
   echo -e " - sw:         A basic function that swaps two files by content."
   echo -e "               Useful for restoring backups."
   echo -e " - what:       This is a tool similar to which and others, the key"
   echo -e "               difference is that it returns partial matches. It can"
   echo -e "               be used to search for binaries."
   echo -e " -*binbox:     This tool can be used to pack bash scripts into one"
   echo -e "               big megascript, much like how \`busybox\` works."
   echo -e "               You can also make symlinks to it to invoke a specific"
   echo -e "               script (current symlinks do not work well)."
   echo -e ""
   echo -e "==================================================================="
   echo -e ""
   echo -e "There are aliases and functions included within this file as well:"
   echo -e " - bak/unbak:  These small utilities make backups of files by making"
   echo -e "               a copy with a .bak suffix. Unbak reverses the process"
   echo -e "               using sw and removes the backup."
   echo -e " - lsa:        A simple alias for ls -lah."
   echo -e " - lsn:        A simple alias for ls -lah --sort=time --reverse."
   echo -e " - lss:        A simple alias for ls -lah --sort=size --reverse."
   echo -e " - editbin:    An alias for editx $\(which <x>\). Saves on typing."
   echo -e " - ched:       Like chsh but for your editor (EDITOR env). A list"
   echo -e "               from which you can choose an installed editor"
   echo -e "               (CLI or GUI) is shown."
   echo -e " - cdf:        Use fzf to find a file and then cd to its location."
   echo -e " - ldrc:       Edits this file and sources it, similarly to shrc."
   echo -e " - daisy_init: Alias for directly sourcing this file from any"
   echo -e "               LACKADAISICAL binary. You may use this yourself."
   echo -e " - daisy_cbin: Contains the name of the current LACKADAISICAL"
   echo -e "               binary being run."
   echo -e " -*daisy_enc:  Converts a file/stdin to a base64 block that can be"
   echo -e "               decoded by passing the output(s) to daisy_dec."
   echo -e " - *_multi:    A version of daisy_enc that runs encodes multiple"
   echo -e "               files and outputs daisy_base64_data blocks to a file"
   echo -e "               or stdout."
   echo -e " -*daisy_dec:  Converts daisy_base64_data blocks back to the form"
   echo -e "               it was in originally."
   echo -e " - *_multi:    A version of daisy_dec that runs on multiple input"
   echo -e "               blocks that are either stored in a file or stdin."
   echo -e ""
   echo -e "==================================================================="
   echo -e ""
   echo -e "To uninstall LACKADAISICAL, simply remove the source line from your"
   echo -e "shell RC, and reload it. This does not remove the files!"
   echo -e ""
   echo -e "To read this notice again, call the function 'daisy_help'."
   echo -e ""
   echo -e "==================================================================="

  IFS="$OLD_IFS"
}

# Variables for use in other utilities
# Find the right argument for our folder
ARG=$0
if [[ ! $ARG == *daisy.source* ]];
then
  ARG="${BASH_SOURCE[0]}"
fi

export DAISY_FOLDER=$(dirname $(realpath $ARG))
export DAISY_SOURCE_FILE=$(realpath $ARG)
export DAISY_AVAILABLE=0

# Config folder setup
export DAISY_CONFIG_FOLDER="$HOME/.config/lackadaisical"
NEW_INSTALL=0

if [[ ! -d "$DAISY_CONFIG_FOLDER" ]];
then
  # Create the folder with its basics
  mkdir -p "$DAISY_CONFIG_FOLDER"
  echo "export EDITOR=$EDITOR" > "$DAISY_CONFIG_FOLDER/editor.src"
  daisy_help
  NEW_INSTALL=1
fi

# Installation into PATH
if [[ ! $PATH == *"$DAISY_FOLDER"* ]];
then
  export PATH="$PATH:$DAISY_FOLDER"
  [[ NEW_INSTALL -eq 1 ]] && echo -e "Lackadaisical binaries have been added to your PATH variable."
fi

# Load override from config (default is $EDITOR - so no change is made)
_EDITOR=$(cat "$DAISY_CONFIG_FOLDER"/editor.src | grep "EDITOR=" | sed 's/export EDITOR=//g')

NEED_CHED=0
if [[ -z $EDITOR ]];
then
  NEED_CHED=1
fi

# Never call if we're in internal mode
if [[ $DAISY_INTERNAL -eq 1 ]];
then
  NEED_CHED=0
fi

# Set up the basic alias for `shrc`
# Do not set these up if DAISY_INTERNAL=1 is set, or infinite recursion could
# occur!
if [[ ! -v DAISY_INTERNAL ]];
then
  alias shrc=". shrc"
fi

###############################################################################
# FUNCTIONS and ALIASES #######################################################
###############################################################################

# bak and unbak
function bak()
{
  # Input: <file>
  target=$1

  # Check if file exists
  if ! test -f "$target";
  then
    echo "Path not found: \"$target\""
    return 2
  fi

  # Handle both cases
  if [[ UNBAK_MODE -eq 1 ]];
  then
    cp -R "$target.bak" "$target"
    rm -rf "$target.bak"
    echo "Restored backup: $target <-- $target.bak"
  else
    cp -R "$target" "$target.bak"
    echo "Backup made: $target --> $target.bak"
  fi
}

alias unbak="UNBAK_MODE=1 bak"
alias lsa="ls -a -l -h"
alias lsn="ls -a -l -tu -r -h"
alias lss="ls -a -l -S -r -h"

# Simple version of `cdf`
function cdf()
{
  cd $(dirname $(fzf))
}

# for convenience purposes
function editbin()
{
  editx $(which $1)
}

# sets a new editor based on commony available ones, and some visual ones
function ched()
{
  editors=("nano" "vim" "nvim" "vi" "emacs" "gedit" "kate" "mousepad" "micro" \
           "code" "subl" "joe" "kwrite" "gnome-text-editor")

  # Find which editors are installed
  available_editors=()
  for editor in "${editors[@]}";
  do
    EDITOR_REAL=$(which $editor)
    if command -v "$EDITOR_REAL" >/dev/null 2>&1;
    then
      if [[ $(realpath "$EDITOR") == "$EDITOR_REAL" ]];
      then
	available_editors+=("$EDITOR_REAL" "$editor (current choice)")
      else
        available_editors+=("$EDITOR_REAL", "$editor")
      fi
    fi
  done

  if [[ ! -z $@ ]];
  then
    TEXT="$@"
    dialog --msgbox "$TEXT" 0 0
  fi

  # Present all choices
  CHOICE=$(dialog --clear --title "Select Text Editor (Recommendation: nano)" \
                  --menu "Choose one of the installed text editors:" 15 50 6 \
                  "${available_editors[@]}" 3>&1 1>&2 2>&3)
  DIALOG_RET=$?

  if [ $DIALOG_RET -ne 0 ];
  then
    echo "No editor selected."
    return
  fi

  CHOICE=$(which $CHOICE)
  echo export EDITOR=$CHOICE > "$DAISY_CONFIG_FOLDER/editor.src"
  echo export DAISY_OLD_EDITOR=$EDITOR >> "$DAISY_CONFIG_FOLDER/editor.src"

  # Seems silly but this is also where we should export these
  source "$DAISY_CONFIG_FOLDER/editor.src"
}

function wait_for_editor()
{
  pname="$1"
  fname="$2"

  # Give some time for a process to launch
  sleep 1

  while true;
  do
    ALIVE=$(ps aux | grep $fname | grep $pname)
    if [[ $ALIVE == "" ]]
    then
      break
    fi
    sleep 1
  done
}

function ldrc()
{
  FROM_RC=0 $EDITOR "$DAISY_SOURCE_FILE"
  wait_for_editor $EDITOR "$DAISY_SOURCE_FILE"
  source "$DAISY_SOURCE_FILE"
}

function daisy_enc()
{
  has_file=$([[ ! -z $1 ]] && file $1 1>/dev/null; echo $?)
  has_file=$([[ has_file -eq 0 ]] && echo 1)
  file_info="no data"
  file_name="null"
  if [[ has_file -eq 1 ]];
  then
    file_info=$(file $1)
    file_name=$(basename $1)
  fi

  base64_inner=$(cat ${1:-/dev/stdin} | base64 | tr -d '\n')

  # Print out our block
  echo -e "# File info: $file_info"
  echo -e "daisy_data_base64_$file_name=\"$base64_inner\""
}

# Will only take input files, always outputs to stdout
function daisy_enc_multi()
{
  [[ ! -d $1 ]] && echo "daisy_dec_multi: No input files specified" && return
  for file in "$@"; do
    if [[ -f "$file" ]]; then
      daisy_enc "$file"
      echo    # separate blocks with a newline
    else
      echo "daisy_enc_multi: Skipping non-file: $file"
    fi
  done
}

function daisy_dec()
{
  data=$(cat ${1:-/dev/stdin} | grep -v "#" )
  echo -e "$data" | cut -d "=" -f 2- | cut -b 2- | head -c -2 | base64 -d
}

# Will only take a file and directory, sources it to find all encoded data
# Extracts to the directory
function daisy_dec_multi()
{
  [[ ! -f $1 ]] && echo "daisy_dec_multi: No input file specified" && return
  [[ ! -d $2 ]] && echo "daisy_dec_multi: No output directory specified" && return
  declare -a vars=( $(cat $1 | grep -v "# File") )
  for enc in "${vars[@]}";
  do
    file=$(echo -e "$enc" | cut -d "_" -f 4- | cut -d "=" -f 1)

    if [[ ! "$file" == '' ]]
    then
      daisy_dec <(echo "$enc") | tee  "$2"/"$file"
    fi
  done
}

alias daisy_init='source "$DAISY_SOURCE_FILE"'

###############################################################################
# end of FUNCTIONS and ALIASES ################################################
###############################################################################
if [[ $NEED_CHED -eq 1 ]];
then
  # Editor is unset, pick one, set `vi` as backup
  TXT1="There is no standard EDITOR environment variable defined. Choose one of the installed text editors."
  TXT2="You can always change it later wih `ched`, part of the Lackadaisical suite."
  ched $TXT1 $TXT2
fi

# End of user section!
export DAISY_AVAILABLE=1

# Start of internal section

# Check for dependencies
function daisy_dependency_check()
{
  command -v $1 1>/dev/null 2>/dev/null;
  res=$?
  echo $(($res ^ 1))
}

DAISY_HAS_fzf=$(daisy_dependency_check fzf)
DAISY_HAS_md5sum=$(daisy_dependency_check md5sum)

function daisy_quit_if_no()
{
  has_dep=$DAISY_HAS_$1

  # Check first if we have checked for this dependency, if not, print a fixme!
  # TODO: Remove upon release, or convert into self-modifying code.
  if [[ ! -v DAISY_HAS_$1 ]];
  then
    echo "FIXME: Dependency `$1` should have an env variable, checking ad-hoc"
    has_dep=$(daisy_dependency_check $1)
  fi

  if [[ $has_dep -eq 0 ]];
  then
    echo "$DAISY_BIN: The dependency $1 was not found! Please install it" \
         "to be able to use this utility!"
    exit 1
  fi
}

[ -d "$DAISY_FOLDER" ] && export DAISY_AVAILABLE=1

# Source everything in the config folder
# We do this at the end so that we do not run into isues
for file in "$DAISY_CONFIG_FOLDER"/*; do
    [ -f "$file" ] && source "$file"
done
# Module 'binbox':
function binbox()
{
# binbox: Creates a multi-binary script that self-contains the input scripts.
#         Symlinking to the resulting binary with the name of one of the original scripts will trigger
#         said script. The idea is similar to `busybox`.

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

ARGS=$@

function help()
{
  echo "$DAISY_BIN is a utility that allows you to generate busybox-style combined binaries."
  echo "To access the original functionality of an input binary, you can either use a symlink or"
  echo "call the function like so: 'combi-bin input-bin <input-bin args>."
  echo ""
  echo "> Usage:"
  echo "Creating boxed binary:        $DAISY_BIN -o <BOXED_BIN> <-s source files> <-p include files verbatim> -i INPUT_BINS ..."
  echo "<X> Unpacking a boxed binary: $DAISY_BIN -e <BOXED_BIN>"
  echo "View this screen:             $DAISY_BIN <noargs>"
  exit 0
}

if [[ $@ == '' ]]; then
  help
fi

# Define some building blocks
CASE_P1="case $BINARY in"
CASE_PM1="  $OPTION)"
CASE_PM2="  exec $OTPION_fn"
CASE_PM3="  ;;"
CASE_CM1="  *)"
CASE_CM2="  exec help_fn"
CASE_CM3="  ;;"
CASE_P2="esac"

FUNC_P1="function $OPTION_fn() {"
FUNC_P2="  exit($?)"
FUNC_P3="}"

BASIC_P1="BINARY=$0"

# Start parsing args
inputs=()
output=""

inputs=()
output=""
includes=()
sources=()

args=("$@")
i=0
b=0
s=0
p=0
while [ $i -lt $# ]; do
  case "${args[$i]}" in
    -i)
      ((i++))
      while [ $i -lt $# ] && [[ ! "${args[$i]}" =~ ^- ]]; do
        inputs+=("${args[$i]}")
        ((i++))
        ((b++))
      done
      continue
      ;;
    -s)
      ((i++))
      while [ $i -lt $# ] && [[ ! "${args[$i]}" =~ ^- ]]; do
        sources+=("${args[$i]}")
        ((i++))
        ((s++))
      done
      continue
      ;;
    -p)
      ((i++))
      while [ $i -lt $# ] && [[ ! "${args[$i]}" =~ ^- ]]; do
        includes+=("${args[$i]}")
        ((i++))
        ((p++))
      done
      continue
      ;;
    -o)
      ((i++))
      output="${args[$i]}"
      ;;
  esac
  ((i++))
done

echo "Input binaries: ${inputs[*]}"
echo "Include files: ${includes[*]}"
echo "Source files: ${sources[*]}"
echo "Output binary: $output"

if [ "$b" -eq 0 ]; then
  echo "Missing input binaries!"
  exit 1
fi

if [[ "$output" == "" ]]; then
  echo "Missing output file!"
  exit 1
fi

function add()
{
  echo "$@" >> "$output"
}

rm -rf "$output"

# Now to construct the binary
# >>> Section 1, includes
add "# Multi-call binary generated by LACKADAISICAL binbox"
add "# $output information:"
add "# Contained modules: ${inputs[*]}"
add "# Files included verbatim: ${includes[*]}"
add "# Files sourced: ${sources[*]}"
add "# Symlink to this binary with the module name to invoke it, or"
add "# use '$output <func>' to do the same."

for f in "${sources[@]}"; do
  add ". $f"
done

for f in "${includes[@]}"; do
  add ""
  add "# Included file $f"
  add "$(cat "$f")"
done


# >>> Section 2: Modules
for f in "${inputs[@]}"; do
    add "# Module '$f':"
    add "function $f()"
    add "{"
    add "}"
done

# >>> Section 3: Module selection
add "SYMED=1"
add "BINSELF=\$(basename \$0)"
add "BOXFILE=\"$output\""
add "if [[ \$BINSELF == \$BOXFILE  ]]; then"
add "  SYMED=0"
add "  if [[ \$# -eq 0 ]]; then"
add "    echo 'Available modules:'"
  for f in "${inputs[@]}"; do
    add "    echo '$f'"
  done
add "    exit 0"
add "  fi"
add "fi"

add "if [[ \$SYMED -eq 0 ]]; then"
add "  eval \$@"
add "  exit \$?"
add "fi"

add "if [[ \$SYMED -eq 1 ]]; then"
add "  eval \$(basename \$0) \$@"
add "fi"


chmod +x "$output"
}
# Module 'calm':
function calm()
{
# Calm a process down
# NEEDS_WORK: cleanup
#  calm <pid> == only one process
#  calm <bin> == all processes that match query
#  calm * == if used in proc or a folder with just PID files, if not you will get an error
#  calm <pid> <bin> .... OK
# set's NICE value to 0
# need sudo

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

PIDS=$@

errorFn()
{
  echo calm: Invalid operation or no such PID/process \(\"$(echo "$PIDS" | tr '\n' ' ' | cut -c -20)...\"\)
  exit
}

for pid in $PIDS
do
  # Process to PID in elegant way
  NEWPIDS=$(pidof "$pid")
  if [ "$NEWPIDS" ]
  then
    BINNY=$pid
    pid=$NEWPIDS
  else
    NEWBINS=$pid
    BINNY=$(ps -p "$pid" -o comm= 2>/dev/null )
    if [ $? != 0 ]
    then
      errorFn
    fi
  fi

  echo Calming down $pid \("$BINNY"\)...
  sudo renice -n 0 -p $pid;
done
}
# Module 'cdz':
function cdz()
{

if [[ $DAISY_INTERNAL -ne 1 ]];
then
  export DAISY_INTERNAL=1
  . $(dirname $(realpath $0))/daisy.source
fi

target=$1

# Check if file exists
if [[ -z "$target" ]];
then
  echo "No target specified."
  exit 1
fi

if ! test -f "$target";
then
  echo "File not found: \"$target\""
  exit 2
fi

# Check if archivemount is present
which archivemount 1>/dev/null 2>/dev/null
hasmounter=$?

file "$target" 1>/dev/null
exitcode=$?
report=$(file "$target")

# Check for archive type, supported types are zip/tar/rar
comm1=(:)
comm2=(echo "Unsupported archive type$add: \"$target\"")
comm3=(:)
comm4=(:)
comm5=(:)

echo $report | grep "tar archive" 1>/dev/null
istar=$?
echo $report | grep "Zip archive" 1>/dev/null
iszip=$?
echo $report | grep "Android" 1>/dev/null
iszip=$?
echo $report | grep "RAR archive" 1>/dev/null
israr=$?

# TAR archives come in many forms, if none of our tests say it's tar
# ...but it looks like tar and barks like tar, let's take the shot.
# Seems to work fairly well for the record.
RES=$(echo "$target" | grep ".tar")
if [[ $RES != "" ]];
then
  istar=0
fi

if [[ $NO_ARCHIVEMOUNT -eq 1 ]]; then
	hasmounter=1
fi

if (( $hasmounter == 0 )); then
	echo "We have \`archivemount\`, so we'll use that!"
	echo "If you'd prefer we not use it, please specify NO_ARCHIVEMOUNT=1"
	istar=1
	iszip=1
	israr=1
fi

# Now we set the right command
if (( $istar == 0 )); then
	comm2=(tar xvf "$target" -C)
elif (( $iszip == 0 )); then
	which unzip 1>/dev/null
	exitcode=$?
	if (( $exitcode == 0 )); then
		comm2=(unzip -q "$target" -d)
	else
		comm1=(echo "The utility 'unzip' is missing, please install it")
		comm3=(exit 1)
	fi
elif (( $israr == 0 )); then
	which unrar 1>/dev/null
	exitcode=$?
	if (( exitcode == 0 )); then
		comm2=(unrar -i nul "$target")
	else
		comm1=(echo "The utility 'unrar' is missing, please install it")
		comm3=(exit 1)
	fi
elif (( $hasmounter == 0 )); then
	comm2=(archivemount "$target")
	comm4=(cd ..)
	comm5=(umount)
fi

# Create the temp dir, usually
dir=$(mktemp -d /tmp/extracted.XXXXXXXX)

# And the rest of the commands
"${comm1[@]}"
"${comm2[@]}" $dir
"${comm3[@]}"

currentpath=$(realpath .)
cd $dir

# With archivemount, making a symlink will alter the archive
if (( $hasmounter == 1 )); then
	ln -s $currentpath ./link-back
	echo "A symlink to your original path has been created under the name \`link-back\`."
	echo "You can use this to copy out files, but you can also just access your filesystem regularly."
fi

echo "Type 'exit' to exit the extracted archive's folder and auto-delete it."
eval $SHELL
"${comm4[@]}"
"${comm5[@]}" $dir
rm -rf $dir
}
# Module 'editx':
function editx()
{
# !/bin/sh
# This utility pre-allocs a file and adds execution permissions. It also
# removes the resulting file if it is empty after the editor closes.

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

if [[ -z $1 ]];
then
  echo "No filename specified."
  exit 2
fi

if [[ -z "${EDITOR}" ]];
then
  ched "EDITOR env variable not set! You will have to set it yourself in the next screen."
fi

exists=$(file "$1" >/dev/null && echo $?)

touch "$1"
chmod +x "$1" 
$EDITOR "$1"
wait $!
SIZE=$(du "$1" | cut -f 1)

if [[ $SIZE -eq 0 && $exists -ne 0 ]];
then
  rm -rf "$1"
fi
}
# Module 'filewait':
function filewait()
{
# A simple utility that waits for a file to become available, infinitely

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

FILE=$@
while [ ! -f "$FILE" ]
do
	sleep 0.1
done
echo $FILE
}
# Module 'newday':
function newday()
{
# This script is intended to be run via cron.

# It creates a folder structure in home for the current date in the following format:
# $HOME/ByDate/<Year>/<Month>/<Day>

# It also sets up a symlink in home: $HOME/Today
# This symlink will always point to the folder for the current date.

# Finally, it removes any folders without data, to prevent clutter.

# - Why did you make this?
# I remember things better when they have a date attached to them.
# You can use this for a primitive form of note-taking, but aside from notes -
# you can store any data this way.

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

BINSELF=$(basename $0)
DIR_NAME=ByDate
ROOT_DIR=$HOME/$DIR_NAME
TODAY_SYM=$HOME/Today

# Present day
TODAY=$(date -I)
YEAR=$(echo $TODAY | awk -F"-" '{print $1}')
MONTH=$(echo $TODAY | awk -F"-" '{print $2}')
DAY=$(echo $TODAY | awk -F"-" '{print $3}')

set -e

function errorFn()
{
  ERROR=$?
  if [[ $ERROR -gt 0 ]];
  then
    echo "$BINSELF error ($ERROR): "
    perl -E 'say $!=shift' $ERROR
  fi
	exit $ERROR
}

# Error handling
trap errorFn ERR

# First we clear out empty folders, and remove the symlink if it exists
test -e "$ROOT_DIR" &&	find "$ROOT_DIR" -maxdepth 3 -type d -empty -print | xargs rm -rf
test -L "$TODAY_SYM" && rm -rf "$TODAY_SYM"

# Now we can set up today's directory
mkdir -p "$ROOT_DIR/$YEAR/$MONTH/$DAY"
cd $ROOT_DIR
ln -s "./$DIR_NAME/$YEAR/$MONTH/$DAY" "$TODAY_SYM"
exitcode=@?
}
# Module 'own':
function own()
{
# Simple program that changes ownership to the current
# user, recursively.

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

if [[ $@ == '' ]];
then
  echo "$DAISY_BIN: Used to quickly take ownership of files/folders."
  echo "Requires sudo. If sudo is not installed, this tool will fai."
  echo "Usage: $DAISY_BIN <folders or files>"
  echo "Means: chown -R <youruser>:<youruser> <folders or files>"
  exit 2
fi

sudo chown -R $(whoami):$(whoami) $@
}
# Module 'short':
function short()
{
# short: Creates shortcuts that can be used anywhere.
#        Can also be used as an alternative for "alias".
#
# Example usage:
#   Add a shortcut:         short -A dev "/home/john/Development"
#   Print shortcut content: short dev -> "/home/john/Development"
#	  Remove shortcut:        short -D dev
#
# One could use this to do things like:
#   cp -R files $(short dev)
#   cd $(short www)
#   ssh $(short server)
#
# Uses a file named .shortcuts in $HOME

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

SHORT_FILE="$DAISY_CONFIG_FOLDER/.shortcuts"
}
# Module 'shrc':
function shrc()
{
# `FROM_RC=1 source shrc` in your RC file to set up an alias.

# Just opens your .rc file easily, for your current shell
# and sources the .rc afterwards!

# Source standard setup
if [[ $DAISY_INTERNAL -ne 1 ]];
then
  DAISY_INTERNAL=1 source $DAISY_SOURCE_FILE
fi

function md5_opt()
{
  if [[ $DAISY_HAS_md5sum -eq 1 ]];
  then
    echo $(md5sum "$1" | awk '{print $1}')
  fi
}

if [[ $FROM_RC -eq 1 ]]; then
	alias shrc=". shrc"
else
	BASENAME=$(basename $SHELL)
	RC_NAME="."$BASENAME"rc"
	RC_PATH="$HOME/$RC_NAME"

	# Optional MD5 checks
	HAS_CHANGED=1
	SUM1=$(md5_opt "$RC_PATH")
	SUM2=

	# This sets a default if the variable does not exist.
	EDITOR=${EDITOR:-$(ched)}
	$EDITOR "$RC_PATH"
	wait_for_editor $EDITOR "$RC_PATH"

  SUM2=$(md5_opt "$RC_PATH")

  if [[ $DAISY_HAS_md5sum -eq 1 && "$SUM1" == "$SUM2" ]];
  then
    echo "The RC-file $RC_NAME has not changed on disk. Not sourcing."
    return
  fi
	
  source "$RC_PATH"
fi
}
# Module 'sw':
function sw()
{
# It just swaps two files

export DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

FILE1=$1
FILE2=$2

function helpFn()
{
  ERROR=$?
  if [[ $ERROR -gt 0 ]];
  then
    ERROR_TEXT=$(perl -E 'say $!=shift' $ERROR)
    echo "$DAISY_BIN error ($ERROR): $ERROR_TEXT"
  fi
  echo "Usage: $DAISY_BIN <file1> <file2>"
  echo Swap two files in a filesystem.
	exit $ERROR
}

if [[ $@ == *"--help"*  ]];
then
	helpFn
elif [[ $@ == '' ]];
then
	echo "No arguments specified."
	helpFn
fi

# We set a trap here, together with 'set -e' above,
# this makes sure we exit gracefully if we have an
# error in one of the ls or mv calls.
trap helpFn ERR

# We want to swap two files
# Easy, but let's be safe about it
ls "$FILE1" >/dev/null
ls "$FILE2" >/dev/null

# Files should exist, now we move
mv "$FILE1" "$FILE1.sw"
mv "$FILE2" "$FILE2.sw"

# We got our moved copies, now we simply rename
mv "$FILE1.sw" "$FILE2"
mv "$FILE2.sw" "$FILE1"
}
# Module 'what':
function what()
{
# Where is the binary?
# Usage: what [<keyword>]
# Returns:
#   With no parameters, all visible binaries in PATH.
#   With parameter, all binaries that match the pattern
#   given. Accepts default grep patterns, case insensitive
#
# Examples:
# $ what zs.*
#  pzstd
#  zsh
#  zstd
#
# $ what ftp
#  ftppass
#  sftp
#  vsftpd
#
# $ what ftp | xargs which
#  /usr/bin/ftppass
#  /usr/bin/sftp
#  /usr/sbin/vsftpd
#

DAISY_INTERNAL=1
. $(dirname $(realpath $0))/daisy.source

PWD=/
ALL_BINS=$(cd / && echo $PATH | sed 's/[:]/ /g' |  xargs ls -A | grep -v ":" | sort | uniq)
OUTPUT=$(printf '%s\n' "-n" $ALL_BINS | grep -i "$1")
echo "$OUTPUT"
}
SYMED=1
BINSELF=$(basename $0)
BOXFILE="daisy"
if [[ $BINSELF == $BOXFILE  ]]; then
  SYMED=0
  if [[ $# -eq 0 ]]; then
    echo 'Available modules:'
    echo 'binbox'
    echo 'calm'
    echo 'cdz'
    echo 'editx'
    echo 'filewait'
    echo 'newday'
    echo 'own'
    echo 'short'
    echo 'shrc'
    echo 'sw'
    echo 'what'
    exit 0
  fi
fi
if [[ $SYMED -eq 0 ]]; then
  eval $@
  exit $?
fi
if [[ $SYMED -eq 1 ]]; then
  eval $(basename $0) $@
fi
