Ensure that VMARGS_PATH/SYS_CONFIG_PATH handling is re-entrant

If users were setting VMARGS_PATH/SYS_CONFIG_PATH directly, the previous
handling of these env vars would result in incorrect behavior when used
with the `start` task, or in any instance where the boot script was
re-entrant (such as calling the boot script from a hook or custom
command). This fix ensures that this handling behaves correctly in these
scenarios.

#!/bin/sh

set -e

# Set VERBOSE to enable verbose logging of the boot script
#VERBOSE=true
if [ ! -z $DEBUG_BOOT ]; then
    set -x
fi;

my_readlink_f() {
    TARGET_FILE="$1"
    cd $(dirname "$TARGET_FILE")
    TARGET_FILE=$(basename "$TARGET_FILE")

    # Iterate down a (possible) chain of symlinks
    while [ -L "$TARGET_FILE" ]
    do
        TARGET_FILE=$(readlink "$TARGET_FILE")
        cd $(dirname "$TARGET_FILE")
        TARGET_FILE=$(basename "$TARGET_FILE")
    done
    # Compute the canonicalized name by finding the physical path
    # for the directory we're in and appending the target file.
    PHYS_DIR=$(pwd -P)
    RESULT="$PHYS_DIR/$TARGET_FILE"
    echo "$RESULT"
}

# Path to this script
if uname | grep -q 'Darwin'; then
  # on OSX, best to install coreutils from homebrew or similar
  # to get greadlink
  if command -v greadlink >/dev/null 2>&1; then
    SCRIPT="${SCRIPT:-$(greadlink -f "$0")}"
  else
    SCRIPT="${SCRIPT:-$(my_readlink_f "$0")}"
  fi
else
  SCRIPT="${SCRIPT:-$(readlink -f "$0" )}"
fi

# Parent directory of this script
SCRIPT_DIR="${SCRIPT_DIR:-$(dirname "${SCRIPT}")}"
# Root directory of all releases
RELEASE_ROOT_DIR="${RELEASE_ROOT_DIR:-$(dirname $(dirname ${SCRIPT_DIR}))}"

# Disable flow control for run_erl
# Flow control can cause several problems. On Linux, if you
# accidentally hit Ctrl-S (instead of Ctrl-D to detach) and
# then some other key, the entire beam process will hang when
# attempting to write to stdout. On Solaris, the beam process
# will hang on writing if ScrollLock is on.
RUN_ERL_DISABLE_FLOWCNTRL="${RUN_ERL_DISABLE_FLOWCNTRL:-true}"
# Name of the release
REL_NAME="${REL_NAME:-<%= release_name %>}"
# Current version of the release
REL_VSN="${REL_VSN:-<%= release_version %>}"
# Current version of ERTS being used
# If this is not present/unset, it will be detected
<%= if ((is_binary(include_erts) or include_erts) and not is_nil(erts_vsn)) do %>ERTS_VSN="${ERTS_VSN:-<%= erts_vsn %>}"<% end %>
# VM code loading mode, embedded by default, can also be interactive
# See http://erlang.org/doc/man/code.html
CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}"
# Path to start_erl.data
START_ERL_DATA="${START_ERL_DATA:-$RELEASE_ROOT_DIR/releases/start_erl.data}"
# Directory containing the current version of this release
REL_DIR="${REL_DIR:-$RELEASE_ROOT_DIR/releases/$REL_VSN}"
# The lib directory for this release
REL_LIB_DIR="${REL_LIB_DIR:-$RELEASE_ROOT_DIR/lib}"
# Options passed to erl
ERL_OPTS="${ERL_OPTS:-<%= release.profile.erl_opts %>}"
# Environment variables for run_erl
RUN_ERL_ENV="${RUN_ERL_ENV:-<%= release.profile.run_erl_env %>}"
# When stdout is piped to a file, this is the directory those files will
# be stored in. defaults to /log in the release root directory

# RELEASE_MUTABLE_DIR
RELEASE_MUTABLE_DIR="${RELEASE_MUTABLE_DIR:-$RELEASE_ROOT_DIR/var}"

RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_MUTABLE_DIR/log}"
# A string of extra options to pass to erl, here for plugins
EXTRA_OPTS="${EXTRA_OPTS:-}"

# Pre-start/stop event hook paths
PRE_CONFIGURE_HOOKS="$REL_DIR/hooks/pre_configure.d"
PRE_START_HOOKS="$REL_DIR/hooks/pre_start.d"
POST_START_HOOKS="$REL_DIR/hooks/post_start.d"
PRE_STOP_HOOKS="$REL_DIR/hooks/pre_stop.d"
POST_STOP_HOOKS="$REL_DIR/hooks/post_stop.d"
PRE_UPGRADE_HOOKS="$REL_DIR/hooks/pre_upgrade.d"
POST_UPGRADE_HOOKS="$REL_DIR/hooks/post_upgrade.d"

# Get node pid
get_pid() {
    if output="$(nodetool rpcterms os getpid)"
    then
        echo "$output" | sed -e 's/"//g'
        return 0
    else
        echo "$output"
        return 1
    fi
}

# Generate a unique nodename
gen_nodename() {
    id="longname$(gen_id)-${NAME}"
    "$BINDIR/erl" -boot start_clean -eval '[Host] = tl(string:tokens(atom_to_list(node()),"@")), io:format("~s~n", [Host]), halt()' -noshell ${NAME_TYPE} $id
}

# Generate a random id
gen_id() {
    od -t x -N 4 /dev/urandom | head -n1 | awk '{print $2}'
}

# Control a node
# Use like `nodetool "ping"`
nodetool() {
    command="$1"; shift
    name=${PEERNAME:-$NAME}
    "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$name" \
                            -setcookie "$COOKIE" "$command" $@
}

# Run an escript in the node's environment
# Use like `escript "path/to/escript"`
escript() {
    shift; scriptpath="$1"; shift
    export RELEASE_ROOT_DIR

    "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@
}

# Private. Load target cookie, either from vm.args or $HOME/.cookie
_load_cookie() {
    COOKIE_ARG="$(grep '^-setcookie' "$VMARGS_PATH" || true)"
    DEFAULT_COOKIE_FILE="$HOME/.erlang.cookie"
    if [ -z "$COOKIE_ARG" ]; then
        if [ -f "$DEFAULT_COOKIE_FILE" ]; then
            COOKIE="$(cat "$DEFAULT_COOKIE_FILE")"
        fi
    else
        # Extract cookie name from COOKIE_ARG
        COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')"
    fi
}

# Private. Ensure that cookie is set.
_check_cookie() {
    # Attempt reloading cookie in case it has been set in a hook
    if [ -z "$COOKIE" ]; then
        _load_cookie
    fi
    # Die if cookie is still not set, as connecting via distribution will fail
    if [ -z "$COOKIE" ]; then
        printf "a secret cookie must be provided in one of the following ways:\n  - with vm.args using the -setcookie parameter,\n  or\n  by writing the cookie to '$DEFAULT_COOKIE_FILE', with permissions set to 0400"
        exit 1
    fi
}

# Private. For setting up the Erlang runtime to use
_init_erts_config() {
    if [ -z "$ERTS_VSN" ]; then
        set +e # temporarily disable so we can display a nice error message to the user
        __erl="$(which erl)"
        set -e
        if [ -z "${__erl}"  ]; then
            echo 'erlang runtime not found. If erlang is installed check your $PATH. aborting.'
            exit 1
        fi
        export ROOTDIR="$("$__erl" -boot start_clean -eval 'io:format("~s~n", [code:root_dir()]), halt().' -noshell)"
        export ERTS_VSN="$(_get_erts_vsn)"
        export ERTS_DIR="$ROOTDIR"/"erts-$ERTS_VSN"
        # Update start_erl.data
        echo "$ERTS_VSN $REL_VSN" > "$START_ERL_DATA"
    else
        __erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
        if [ -d "$__erts_dir" ]; then
            export ROOTDIR="$RELEASE_ROOT_DIR"
            export ERTS_DIR="$__erts_dir"
        else
            unset ERTS_VSN
            _init_erts_config
        fi
    fi
}

# Private. For determining the version of ERTS available to the release
# This is only ever called if ERTS_VSN is not set
_get_erts_vsn() {
    if [ -z "$ERTS_VSN" ]; then
        "$ROOTDIR"/bin/erl \
            -boot start_clean \
            -eval 'Ver = erlang:system_info(version), io:format("~s~n", [Ver]), halt()' \
            -noshell
    else
        echo "$ERTS_VSN"
    fi
}

# Private. Gets a list of code paths for this release
_get_code_paths() {
    "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/release_utils.escript" "get_code_paths" "$ROOTDIR" "$ERTS_DIR" "$REL_NAME" "$REL_VSN"
}

# Private. Open a shell on a remote node
_rem_sh() {
    # Generate a unique id used to allow multiple remsh to the same node
    # transparently
    id="remsh$(gen_id)-${NAME}"

    # Get the node's ticktime so that we use the same thing.
    TICKTIME="$(nodetool rpcterms net_kernel get_net_ticktime)"

    # Setup remote shell command to control node
    if [ ! -z "$USE_ERL_SHELL" ]; then
        exec "$BINDIR/erl" \
            -hidden \
            -boot start_clean -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -kernel net_ticktime $TICKTIME \
            "$NAME_TYPE" "$id" -remsh "$NAME" -setcookie "$COOKIE"
    else
        __code_paths=$(_get_code_paths)
        exec "$BINDIR/erl" \
            -pa "$CONSOLIDATED_DIR" \
            ${__code_paths} \
            -hidden -noshell \
            -boot start_clean -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -kernel net_ticktime $TICKTIME \
            -user Elixir.IEx.CLI "$NAME_TYPE" "$id" -setcookie "$COOKIE" \
            -extra --no-halt +iex -"$NAME_TYPE" "$id" --cookie "$COOKIE" --remsh "$NAME"
    fi
}

# Output a start command for the last argument of run_erl
_start_command() {
    printf "exec \"%s\" \"%s\" -- %s %s" "$RELEASE_ROOT_DIR/bin/$REL_NAME" \
           "$START_OPTION" "${ARGS}" "${EXTRA_OPTS}"
}

# Do a textual replacement of ${VAR} occurrences in $1 and pipe to $2
_replace_os_vars() {
    awk '
        function escape(s) {
            gsub(/'\&'/, "\\\\&", s);
            return s;
        }
        {
            while(match($0,"[$]{[^}]*}")) {
                var=substr($0,RSTART+2,RLENGTH-3);
                gsub("[$]{"var"}", escape(ENVIRON[var]))
            }
        }1' < "$1" > "$1.bak"
    mv -- "$1.bak" "$1"
}

# Private. Run hooks from directory.
_run_hooks_from_dir() {
   if [ -d "$1" ]; then
      for file in $1/[0-9a-zA-Z]*.sh; do
        [ -f "$file" ] || continue
        . "$file"
      done
   fi
}

# Private. Sets config paths for sys.config and vm.args,
# and ensures that env var replacements are performed
_init_configs() {
    # Set VMARGS_PATH, the path to the vm.args file to use
    # Use $RELEASE_CONFIG_DIR/vm.args if exists, otherwise releases/VSN/vm.args
    if [ -z "$VMARGS_PATH" ]; then
        if [ -f "$RELEASE_CONFIG_DIR/vm.args" ]; then
            export SRC_VMARGS_PATH="$RELEASE_CONFIG_DIR/vm.args"
        else
            export SRC_VMARGS_PATH="$REL_DIR/vm.args"
        fi
    else
        export SRC_VMARGS_PATH="$VMARGS_PATH"
    fi
    if [ "$SRC_VMARGS_PATH" != "$RELEASE_MUTABLE_DIR/vm.args" ]; then
        echo "#### Generated - edit/create $RELEASE_CONFIG_DIR/vm.args instead." \
            >  "$RELEASE_MUTABLE_DIR/vm.args"
        cat  "$SRC_VMARGS_PATH"                              \
            >> "$RELEASE_MUTABLE_DIR/vm.args"
        export DEST_VMARGS_PATH="$RELEASE_MUTABLE_DIR"/vm.args
    fi
    if [ $REPLACE_OS_VARS ]; then
        _replace_os_vars "$DEST_VMARGS_PATH"
    fi
    export VMARGS_PATH="${VMARGS_PATH:-$DEST_VMARGS_PATH}"

    # Set SYS_CONFIG_PATH, the path to the sys.config file to use
    # Use $RELEASE_CONFIG_DIR/sys.config if exists, otherwise releases/VSN/sys.config
    if [ -z "$SYS_CONFIG_PATH" ]; then
        if [ -f "$RELEASE_CONFIG_DIR/sys.config" ]; then
            export SRC_SYS_CONFIG_PATH="$RELEASE_CONFIG_DIR/sys.config"
        else
            export SRC_SYS_CONFIG_PATH="$REL_DIR/sys.config"
        fi
    else
        export SRC_SYS_CONFIG_PATH="$SYS_CONFIG_PATH"
    fi
    if [ "$SRC_SYS_CONFIG_PATH" != "$RELEASE_MUTABLE_DIR/sys.config" ]; then
        (echo "%% Generated - edit/create $RELEASE_CONFIG_DIR/sys.config instead."; \
        cat  "$SRC_SYS_CONFIG_PATH")                              \
            > "$RELEASE_MUTABLE_DIR/sys.config"
        export DEST_SYS_CONFIG_PATH="$RELEASE_MUTABLE_DIR"/sys.config
    fi
    if [ $REPLACE_OS_VARS ]; then
        _replace_os_vars "$DEST_SYS_CONFIG_PATH"
    fi
    export SYS_CONFIG_PATH="${SYS_CONFIG_PATH:-$DEST_SYS_CONFIG_PATH}"
}

# If TERM is not set, set it to xterm
if [ -z "$TERM" ]; then
    export TERM=xterm
fi

# Make sure ERTS configuration is set
_init_erts_config

# Allow override of where to read configuration from
# By default it's RELEASE_ROOT_DIR
if [ -z "$RELEASE_CONFIG_DIR" ]; then
    export RELEASE_CONFIG_DIR="$RELEASE_ROOT_DIR"
fi

# Make sure directories exist
mkdir -p "$RELEASE_MUTABLE_DIR"
echo "Files in this directory are regenerated frequently, edits will be lost" \
    > "$RELEASE_MUTABLE_DIR/WARNING_README"
mkdir -p "$RUNNER_LOG_DIR"

# Make sure config paths are setup
_init_configs

# Extract the target node name from node.args
# Should be `-sname somename` or `-name somename@somehost`
export NAME_ARG="$(egrep '^-s?name' "$VMARGS_PATH" || true)"
if [ -z "$NAME_ARG" ]; then
    echo "vm.args needs to have either -name or -sname parameter."
    exit 1
fi

# Extract the name type and name from the NAME_ARG for REMSH
# NAME_TYPE should be -name or -sname
export NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')"
# NAME will be either `somename` or `somename@somehost`
export NAME="$(echo "$NAME_ARG" | awk '{print $2}')"

# Where the pipe will be stored when using `start`
# This is used so you can attach the running application to the current
# shell using `attach`
PIPE_DIR="${PIPE_DIR:-$RELEASE_MUTABLE_DIR/erl_pipes/$NAME/}"

# Extract the target cookie
_load_cookie

export ROOTDIR="$RELEASE_ROOT_DIR"
export BINDIR="$ERTS_DIR/bin"
export EMU="beam"
export PROGNAME="erl"
export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH"
export ERTS_LIB_DIR="$ERTS_DIR/../lib"
CONSOLIDATED_DIR="$ROOTDIR/lib/${REL_NAME}-${REL_VSN}/consolidated"

cd "$ROOTDIR"

# User can specify an sname without @hostname
# This will fail when creating remote shell
# So here we check for @ and add @hostname if missing
case $NAME in
    *@*)
        # Nothing to do
        ;;
    *)
        NAME=$NAME@$(gen_nodename)
        ;;
esac

# For Elixir runtime
export DISTILLERY_TASK="$1"

# Check the first argument for instructions
case "$1" in
    start|start_boot)

        # Make sure there is not already a node running
        #RES=`$NODETOOL ping`
        #if [ "$RES" = "pong" ]; then
        #    echo "Node is already running!"
        #    exit 1
        #fi
        # Save this for later.
        CMD=$1
        case "$1" in
            start)
                shift
                START_OPTION="console"
                HEART_OPTION="start"
                ;;
            start_boot)
                shift
                START_OPTION="console_boot"
                HEART_OPTION="start_boot"
                ;;
        esac
        ARGS="$@"
        RUN_PARAM="$@"

        _check_cookie
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"

        # Set arguments for the heart command
        set -- "$SCRIPT_DIR/$REL_NAME" "$HEART_OPTION"
        [ "$RUN_PARAM" ] && set -- "$@" "$RUN_PARAM"

        # Export the HEART_COMMAND
        HEART_COMMAND="$RELEASE_ROOT_DIR/bin/$REL_NAME $CMD"
        export HEART_COMMAND

        mkdir -p "$PIPE_DIR"

        env $RUN_ERL_ENV "$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \
                          "$(_start_command)"

        _run_hooks_from_dir "$POST_START_HOOKS"
        ;;

    stop)
        _check_cookie
        _run_hooks_from_dir "$PRE_STOP_HOOKS"
        # Wait for the node to completely stop...
        PID="$(get_pid)"
        if ! nodetool "stop"; then
            exit 1
        fi
        while $(kill -s 0 "$PID" 2>/dev/null);
        do
            sleep 1
        done
        _run_hooks_from_dir "$POST_STOP_HOOKS"
        ;;

    restart)
        _check_cookie
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"
        ## Restart the VM without exiting the process
        if ! nodetool "restart"; then
            exit 1
        fi
        ;;

    reboot)
        _check_cookie
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"
        ## Restart the VM completely (uses heart to restart it)
        if ! nodetool "reboot"; then
            exit 1
        fi
        ;;

    pid)
        ## Get the VM's pid
        _check_cookie
        if ! get_pid; then
            exit 1
        fi
        ;;

    ping)
        _check_cookie
        ## See if the VM is alive
        if ! nodetool "ping"; then
            exit 1
        fi
        ;;

    pingpeer)
        PEERNAME=$2 nodetool "ping"
        exit_status=$?
        if [ "$exit_status" -ne 0 ]; then
            exit $exit_status
        fi
        ;;

    escript)
        _check_cookie
        ## Run an escript under the node's environment
        if ! escript $@; then
            exit 1
        fi
        ;;

    attach)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift
        exec "$BINDIR/to_erl" "$PIPE_DIR"
        ;;

    remote_console)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift
        _rem_sh
        ;;

    upgrade|downgrade|install)
        if [ -z "$2" ]; then
            echo "Missing package argument"
            echo "Usage: $REL_NAME $1 {package base name}"
            echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
            exit 1
        fi

        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        SOURCE_VERSION="$REL_VSN"
        TARGET_VERSION="$2"

        "$BINDIR/escript" "$ROOTDIR/bin/release_utils.escript" \
             "unpack_release" "$REL_NAME" "$NAME_TYPE"  "$NAME" "$COOKIE" "$TARGET_VERSION"

        # Update environment to reflect target version environment
        REL_VSN="$TARGET_VERSION"
        REL_DIR="$RELEASE_ROOT_DIR/releases/$TARGET_VERSION"

        # Prepare new configs
        _init_configs
        # We have to do some juggling to ensure the correct config is used by the upgrade handler
        # First, we detect if there was a failed upgrade, so we can start over
        if [ -f "$REL_DIR/sys.config.bak" ]; then
            mv "$REL_DIR/sys.config.bak" "$REL_DIR/sys.config"
        fi
        if [ -f "$REL_DIR/vm.args.bak" ]; then
            mv "$REL_DIR/vm.args.bak" "$REL_DIR/vm.args"
        fi
        # Then, backup the packaged configs
        cp "$REL_DIR/sys.config" "$REL_DIR/sys.config.bak"
        cp "$REL_DIR/vm.args" "$REL_DIR/vm.args.bak"
        # Then, substitute in the prepared configs
        cp "$SYS_CONFIG_PATH" "$REL_DIR/sys.config"
        cp "$VMARGS_PATH" "$REL_DIR/vm.args"
        # Make sure any pre-configuration hooks are run
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        # Run any pre-upgrade tasks
        _run_hooks_from_dir "$PRE_UPGRADE_HOOKS"

        "$BINDIR/escript" "$ROOTDIR/bin/release_utils.escript" \
             "install_release" "$REL_NAME" "$NAME_TYPE"  "$NAME" "$COOKIE" "$TARGET_VERSION"

        # We were successful, clean up the configs
        mv "$REL_DIR/sys.config.bak" "$REL_DIR/sys.config"
        mv "$REL_DIR/vm.args.bak" "$REL_DIR/vm.args"

        # Run any post-upgrade hooks
        _run_hooks_from_dir "$POST_UPGRADE_HOOKS"

        ;;
    unpack)
        if [ -z "$2" ]; then
            echo "Missing package argument"
            echo "Usage: $REL_NAME $1 {package base name}"
            echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
            exit 1
        fi

        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        exec "$BINDIR/escript" "$ROOTDIR/bin/release_utils.escript" \
             "unpack_release" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2"
        ;;

    console|console_clean|console_boot)
        # .boot file typically just $REL_NAME (ie, the app name)
        # however, for debugging, sometimes start_clean.boot is useful.
        # For e.g. 'setup', one may even want to name another boot script.
        case "$1" in
            console)
                if [ -f "$REL_DIR/$REL_NAME.boot" ]; then
                  BOOTFILE="$REL_DIR/$REL_NAME"
                else
                  BOOTFILE="$REL_DIR/start"
                fi
                ;;
            console_clean)
                BOOTFILE="$ROOTDIR/bin/start_clean"
                __code_paths=$(_get_code_paths)
                EXTRA_CODE_PATHS=${__code_paths}
                ;;
            console_boot)
                shift
                BOOTFILE="$1"
                shift
                ;;
        esac
        # Setup beam-required vars
        EMU="beam"
        PROGNAME="${0#*/}"

        export EMU
        export PROGNAME

        # Store passed arguments since they will be erased by `set`
        ARGS="$@"

        _check_cookie

        # Start the VM, executing pre_start hook along
        # the way. We can't run the post_start hook because
        # the console will crash with no TTY attached
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"

        # Build an array of arguments to pass to exec later on
        # Build it here because this command will be used for logging.
        set -- "$BINDIR/erlexec" \
            -boot "$BOOTFILE" \
            -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -env ERL_LIBS "$REL_LIB_DIR" \
            -pa "$CONSOLIDATED_DIR" \
            ${EXTRA_CODE_PATHS} \
            -args_file "$VMARGS_PATH" \
            -config "$SYS_CONFIG_PATH" \
            -mode "$CODE_LOADING_MODE" \
            ${ERL_OPTS} \
            -user Elixir.IEx.CLI \
            -extra --no-halt +iex

        # Dump environment info for logging purposes
        if [ ! -z $VERBOSE ]; then
            echo "Exec: $@" -- ${1+$ARGS} ${EXTRA_OPTS}
            echo "Root: $ROOTDIR"

            # Log the startup
            echo "$RELEASE_ROOT_DIR"
        fi;

        logger -t "$REL_NAME[$$]" "Starting up"

        exec "$@" -- ${1+$ARGS} ${EXTRA_OPTS}
        ;;

    foreground)
        # start up the release in the foreground for use by runit
        # or other supervision services

        [ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
        FOREGROUNDOPTIONS="-noshell -noinput +Bd"

        # Setup beam-required vars
        EMU=beam
        PROGNAME="${0#*/}"

        export EMU
        export PROGNAME

        # Store passed arguments since they will be erased by `set`
        ARGS="$@"

        _check_cookie

        # Start the VM, executing pre and post start hooks
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"

        # Build an array of arguments to pass to exec later on
        # Build it here because this command will be used for logging.
        set -- "$BINDIR/erlexec" $FOREGROUNDOPTIONS \
            -boot "$REL_DIR/$BOOTFILE" \
            -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -env ERL_LIBS "$REL_LIB_DIR" \
            -pa "$CONSOLIDATED_DIR" \
            -args_file "$VMARGS_PATH" \
            -config "$SYS_CONFIG_PATH" \
            -mode "$CODE_LOADING_MODE" \
            ${ERL_OPTS} \
            -extra ${EXTRA_OPTS}

        # Dump environment info for logging purposes
        if [ ! -z $VERBOSE ]; then
            echo "Exec: $@" -- ${1+$ARGS}
            echo "Root: $ROOTDIR"
        fi;

        "$@" -- ${1+$ARGS} &
        __bg_pid=$!
        _run_hooks_from_dir "$POST_START_HOOKS"
        wait $__bg_pid
        _run_hooks_from_dir "$POST_STOP_HOOKS"
        ;;
    rpc)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift

        nodetool rpc $@
        ;;
    rpcterms)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift

        nodetool rpcterms $@
        ;;
    eval)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift
        nodetool "eval" $@
        ;;
    command)
        # Execute as command-line utility
        #
        # Like the escript command, this does not start the OTP application.
        # If your command depends on a running OTP application,
        # use
        #
        #     {:ok, _} = Application.ensure_all_started(:your_app)

        _check_cookie

        shift
        MODULE="$1"; shift
        FUNCTION="$1"; shift

        # Save extra arguments
        ARGS="$@"

        # Build arguments for erlexec
        __code_paths=$(_get_code_paths)
        set -- "$ERL_OPTS"
        [ "$SYS_CONFIG_PATH" ] && set -- "$@" -config "$SYS_CONFIG_PATH"
        set -- "$@" -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR"
        set -- "$@" -noshell
        set -- "$@" -boot start_clean
        set -- "$@" -pa "$CONSOLIDATED_DIR"
        set -- "$@" ${__code_paths}
        set -- "$@" -s "$MODULE" "$FUNCTION"

        $BINDIR/erlexec $@ -extra $ARGS
        exit "$?"
        ;;
    reload_config)
        # Reload the running system's configuration
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"

        shift
        nodetool "reload_config" "$SYS_CONFIG_PATH"
        ;;
    describe)
        ## Print a summary of information about this release
        echo "$REL_NAME-$REL_VSN\n"
        echo "erts:        $ERTS_VSN"
        echo "path:        $REL_DIR"
        echo "sys.config:  $SYS_CONFIG_PATH"
        echo "vm.args:     $VMARGS_PATH"
        echo "name:        $NAME"
        echo "cookie:      $COOKIE"
        echo "erl_opts:    ${ERL_OPTS:-none provided}"
        echo "run_erl_env: ${RUN_ERL_ENV:-none provided}"
        echo ""
        echo "hooks:"
        __has_hooks=0
        for hook in "$REL_DIR"/hooks/*.d/[0-9a-zA-Z]*.sh; do
            [ -f "$hook" ] || continue
            __has_hooks=1
            echo "$hook"
        done
        if [ $__has_hooks -eq 0 ]; then
            echo "No custom hooks found."
        fi
        echo ""
        echo "commands:"
        __has_commands=0
        for command in "$REL_DIR"/commands/*.sh; do
            [ -f "$command" ] || continue
            __has_commands=1
            echo "$command"
        done
        if [ $__has_commands -eq 0 ]; then
            echo "No custom commands found."
        fi
        exit 0
        ;;
    *)
        __command_path="$REL_DIR/commands/$1"
        if [ -f "$__command_path" ]; then
            _check_cookie
            . "$__command_path"
        else
            echo "Usage: $REL_NAME <task>"
            echo
            echo "Service Control"
            echo "======================="
            echo "start                          # start $REL_NAME as a daemon"
            echo "start_boot <file>              # start $REL_NAME as a daemon, but supply a custom .boot file"
            echo "foreground                     # start $REL_NAME in the foreground"
            echo "console                        # start $REL_NAME with a console attached"
            echo "console_clean                  # start a console with code paths set but no apps loaded/started"
            echo "console_boot <file>            # start $REL_NAME with a console attached, but supply a custom .boot file"
            echo "stop                           # stop the $REL_NAME daemon"
            echo "restart                        # restart the $REL_NAME daemon without shutting down the VM"
            echo "reboot                         # restart the $REL_NAME daemon"
            echo "reload_config                  # reload the current system's configuration from disk"
            echo
            echo "Upgrades"
            echo "======================="
            echo "upgrade <version>              # upgrade $REL_NAME to <version>"
            echo "downgrade <version>            # downgrade $REL_NAME to <version>"
            echo "install <version>              # install the $REL_NAME-<version> release, but do not upgrade to it"
            echo
            echo "Utilities"
            echo "======================="
            echo "attach                         # attach the current TTY to $REL_NAME's console"
            echo "remote_console                 # remote shell to $REL_NAME's console"
            echo "pid                            # get the pid of the running $REL_NAME instance"
            echo "ping                           # checks if $REL_NAME is running, pong is returned if successful"
            echo "pingpeer <peer>                # check if a peer node is running, pong is returned if successful"
            echo "escript <file>                 # execute an escript"
            echo "rpc <mod> <fun> [<args..>]     # execute an RPC call using the given MFA"
            echo "rpcterms <mod> <fun> [<expr>]  # execute an RPC call using the given Erlang expression for args"
            echo "eval <expr>                    # execute the given Erlang expression on the running node"
            echo "command <mod> <fun> [<args..>] # execute the given MFA"
            echo "describe                       # print useful information about the $REL_NAME release"
            echo
            echo "Custom Commands"
            echo "======================="
            __has_commands=0
            for command in "$REL_DIR"/commands/*.sh; do
                [ -f "$command" ] || continue
                __has_commands=1
                echo "$command"
            done
            if [ $__has_commands -eq 0 ]; then
                echo "No custom commands found."
            fi
            echo ""
            exit 1
        fi
        ;;
esac

exit 0

#!/bin/sh

set -e

# Set VERBOSE to enable verbose logging of the boot script
#VERBOSE=true
if [ ! -z $DEBUG_BOOT ]; then
    set -x
fi;

my_readlink_f() {
    TARGET_FILE="$1"
    cd $(dirname "$TARGET_FILE")
    TARGET_FILE=$(basename "$TARGET_FILE")

    # Iterate down a (possible) chain of symlinks
    while [ -L "$TARGET_FILE" ]
    do
        TARGET_FILE=$(readlink "$TARGET_FILE")
        cd $(dirname "$TARGET_FILE")
        TARGET_FILE=$(basename "$TARGET_FILE")
    done
    # Compute the canonicalized name by finding the physical path
    # for the directory we're in and appending the target file.
    PHYS_DIR=$(pwd -P)
    RESULT="$PHYS_DIR/$TARGET_FILE"
    echo "$RESULT"
}

# Path to this script
if uname | grep -q 'Darwin'; then
  # on OSX, best to install coreutils from homebrew or similar
  # to get greadlink
  if command -v greadlink >/dev/null 2>&1; then
    SCRIPT="${SCRIPT:-$(greadlink -f "$0")}"
  else
    SCRIPT="${SCRIPT:-$(my_readlink_f "$0")}"
  fi
else
  SCRIPT="${SCRIPT:-$(readlink -f "$0" )}"
fi

# Parent directory of this script
SCRIPT_DIR="${SCRIPT_DIR:-$(dirname "${SCRIPT}")}"
# Root directory of all releases
RELEASE_ROOT_DIR="${RELEASE_ROOT_DIR:-$(dirname $(dirname ${SCRIPT_DIR}))}"

# Disable flow control for run_erl
# Flow control can cause several problems. On Linux, if you
# accidentally hit Ctrl-S (instead of Ctrl-D to detach) and
# then some other key, the entire beam process will hang when
# attempting to write to stdout. On Solaris, the beam process
# will hang on writing if ScrollLock is on.
RUN_ERL_DISABLE_FLOWCNTRL="${RUN_ERL_DISABLE_FLOWCNTRL:-true}"
# Name of the release
REL_NAME="${REL_NAME:-<%= release_name %>}"
# Current version of the release
REL_VSN="${REL_VSN:-<%= release_version %>}"
# Current version of ERTS being used
# If this is not present/unset, it will be detected
<%= if ((is_binary(include_erts) or include_erts) and not is_nil(erts_vsn)) do %>ERTS_VSN="${ERTS_VSN:-<%= erts_vsn %>}"<% end %>
# VM code loading mode, embedded by default, can also be interactive
# See http://erlang.org/doc/man/code.html
CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}"
# Path to start_erl.data
START_ERL_DATA="${START_ERL_DATA:-$RELEASE_ROOT_DIR/releases/start_erl.data}"
# Directory containing the current version of this release
REL_DIR="${REL_DIR:-$RELEASE_ROOT_DIR/releases/$REL_VSN}"
# The lib directory for this release
REL_LIB_DIR="${REL_LIB_DIR:-$RELEASE_ROOT_DIR/lib}"
# Options passed to erl
ERL_OPTS="${ERL_OPTS:-<%= release.profile.erl_opts %>}"
# Environment variables for run_erl
RUN_ERL_ENV="${RUN_ERL_ENV:-<%= release.profile.run_erl_env %>}"
# When stdout is piped to a file, this is the directory those files will
# be stored in. defaults to /log in the release root directory

# RELEASE_MUTABLE_DIR
RELEASE_MUTABLE_DIR="${RELEASE_MUTABLE_DIR:-$RELEASE_ROOT_DIR/var}"

RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_MUTABLE_DIR/log}"
# A string of extra options to pass to erl, here for plugins
EXTRA_OPTS="${EXTRA_OPTS:-}"

# Pre-start/stop event hook paths
PRE_CONFIGURE_HOOKS="$REL_DIR/hooks/pre_configure.d"
PRE_START_HOOKS="$REL_DIR/hooks/pre_start.d"
POST_START_HOOKS="$REL_DIR/hooks/post_start.d"
PRE_STOP_HOOKS="$REL_DIR/hooks/pre_stop.d"
POST_STOP_HOOKS="$REL_DIR/hooks/post_stop.d"
PRE_UPGRADE_HOOKS="$REL_DIR/hooks/pre_upgrade.d"
POST_UPGRADE_HOOKS="$REL_DIR/hooks/post_upgrade.d"

# Get node pid
get_pid() {
    if output="$(nodetool rpcterms os getpid)"
    then
        echo "$output" | sed -e 's/"//g'
        return 0
    else
        echo "$output"
        return 1
    fi
}

# Generate a unique nodename
gen_nodename() {
    id="longname$(gen_id)-${NAME}"
    "$BINDIR/erl" -boot start_clean -eval '[Host] = tl(string:tokens(atom_to_list(node()),"@")), io:format("~s~n", [Host]), halt()' -noshell ${NAME_TYPE} $id
}

# Generate a random id
gen_id() {
    od -t x -N 4 /dev/urandom | head -n1 | awk '{print $2}'
}

# Control a node
# Use like `nodetool "ping"`
nodetool() {
    command="$1"; shift
    name=${PEERNAME:-$NAME}
    "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$name" \
                            -setcookie "$COOKIE" "$command" $@
}

# Run an escript in the node's environment
# Use like `escript "path/to/escript"`
escript() {
    shift; scriptpath="$1"; shift
    export RELEASE_ROOT_DIR

    "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@
}

# Private. Load target cookie, either from vm.args or $HOME/.cookie
_load_cookie() {
    COOKIE_ARG="$(grep '^-setcookie' "$VMARGS_PATH" || true)"
    DEFAULT_COOKIE_FILE="$HOME/.erlang.cookie"
    if [ -z "$COOKIE_ARG" ]; then
        if [ -f "$DEFAULT_COOKIE_FILE" ]; then
            COOKIE="$(cat "$DEFAULT_COOKIE_FILE")"
        fi
    else
        # Extract cookie name from COOKIE_ARG
        COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')"
    fi
}

# Private. Ensure that cookie is set.
_check_cookie() {
    # Attempt reloading cookie in case it has been set in a hook
    if [ -z "$COOKIE" ]; then
        _load_cookie
    fi
    # Die if cookie is still not set, as connecting via distribution will fail
    if [ -z "$COOKIE" ]; then
        printf "a secret cookie must be provided in one of the following ways:\n  - with vm.args using the -setcookie parameter,\n  or\n  by writing the cookie to '$DEFAULT_COOKIE_FILE', with permissions set to 0400"
        exit 1
    fi
}

# Private. For setting up the Erlang runtime to use
_init_erts_config() {
    if [ -z "$ERTS_VSN" ]; then
        set +e # temporarily disable so we can display a nice error message to the user
        __erl="$(which erl)"
        set -e
        if [ -z "${__erl}"  ]; then
            echo 'erlang runtime not found. If erlang is installed check your $PATH. aborting.'
            exit 1
        fi
        export ROOTDIR="$("$__erl" -boot start_clean -eval 'io:format("~s~n", [code:root_dir()]), halt().' -noshell)"
        export ERTS_VSN="$(_get_erts_vsn)"
        export ERTS_DIR="$ROOTDIR"/"erts-$ERTS_VSN"
        # Update start_erl.data
        echo "$ERTS_VSN $REL_VSN" > "$START_ERL_DATA"
    else
        __erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
        if [ -d "$__erts_dir" ]; then
            export ROOTDIR="$RELEASE_ROOT_DIR"
            export ERTS_DIR="$__erts_dir"
        else
            unset ERTS_VSN
            _init_erts_config
        fi
    fi
}

# Private. For determining the version of ERTS available to the release
# This is only ever called if ERTS_VSN is not set
_get_erts_vsn() {
    if [ -z "$ERTS_VSN" ]; then
        "$ROOTDIR"/bin/erl \
            -boot start_clean \
            -eval 'Ver = erlang:system_info(version), io:format("~s~n", [Ver]), halt()' \
            -noshell
    else
        echo "$ERTS_VSN"
    fi
}

# Private. Gets a list of code paths for this release
_get_code_paths() {
    "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/release_utils.escript" "get_code_paths" "$ROOTDIR" "$ERTS_DIR" "$REL_NAME" "$REL_VSN"
}

# Private. Open a shell on a remote node
_rem_sh() {
    # Generate a unique id used to allow multiple remsh to the same node
    # transparently
    id="remsh$(gen_id)-${NAME}"

    # Get the node's ticktime so that we use the same thing.
    TICKTIME="$(nodetool rpcterms net_kernel get_net_ticktime)"

    # Setup remote shell command to control node
    if [ ! -z "$USE_ERL_SHELL" ]; then
        exec "$BINDIR/erl" \
            -hidden \
            -boot start_clean -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -kernel net_ticktime $TICKTIME \
            "$NAME_TYPE" "$id" -remsh "$NAME" -setcookie "$COOKIE"
    else
        __code_paths=$(_get_code_paths)
        exec "$BINDIR/erl" \
            -pa "$CONSOLIDATED_DIR" \
            ${__code_paths} \
            -hidden -noshell \
            -boot start_clean -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -kernel net_ticktime $TICKTIME \
            -user Elixir.IEx.CLI "$NAME_TYPE" "$id" -setcookie "$COOKIE" \
            -extra --no-halt +iex -"$NAME_TYPE" "$id" --cookie "$COOKIE" --remsh "$NAME"
    fi
}

# Output a start command for the last argument of run_erl
_start_command() {
    printf "exec \"%s\" \"%s\" -- %s %s" "$RELEASE_ROOT_DIR/bin/$REL_NAME" \
           "$START_OPTION" "${ARGS}" "${EXTRA_OPTS}"
}

# Do a textual replacement of ${VAR} occurrences in $1 and pipe to $2
_replace_os_vars() {
    awk '
        function escape(s) {
            gsub(/'\&'/, "\\\\&", s);
            return s;
        }
        {
            while(match($0,"[$]{[^}]*}")) {
                var=substr($0,RSTART+2,RLENGTH-3);
                gsub("[$]{"var"}", escape(ENVIRON[var]))
            }
        }1' < "$1" > "$1.bak"
    mv -- "$1.bak" "$1"
}

# Private. Run hooks from directory.
_run_hooks_from_dir() {
   if [ -d "$1" ]; then
      for file in $1/[0-9a-zA-Z]*.sh; do
        [ -f "$file" ] || continue
        . "$file"
      done
   fi
}

# Private. Sets config paths for sys.config and vm.args,
# and ensures that env var replacements are performed
_init_configs() {
    # Set VMARGS_PATH, the path to the vm.args file to use
    # Use $RELEASE_CONFIG_DIR/vm.args if exists, otherwise releases/VSN/vm.args
    if [ -z "$VMARGS_PATH" ]; then
        if [ -f "$RELEASE_CONFIG_DIR/vm.args" ]; then
            export VMARGS_PATH="$RELEASE_CONFIG_DIR/vm.args"
        else
            export VMARGS_PATH="$REL_DIR/vm.args"
        fi
        export SRC_VMARGS_PATH="$VMARGS_PATH"
    else
        if [ "$VMARGS_PATH" != "$RELEASE_MUTABLE_DIR/vm.args" ]; then
            export SRC_VMARGS_PATH="$VMARGS_PATH"
        else
            if [ -f "$RELEASE_CONFIG_DIR/vm.args" ]; then
                export VMARGS_PATH="$RELEASE_CONFIG_DIR/vm.args"
            else
                export VMARGS_PATH="$REL_DIR/vm.args"
            fi
            export SRC_VMARGS_PATH="$VMARGS_PATH"
        fi
    fi
    if [ "$SRC_VMARGS_PATH" != "$RELEASE_MUTABLE_DIR/vm.args" ]; then
        echo "#### Generated - edit/create $RELEASE_CONFIG_DIR/vm.args instead." \
            >  "$RELEASE_MUTABLE_DIR/vm.args"
        cat  "$SRC_VMARGS_PATH"                              \
            >> "$RELEASE_MUTABLE_DIR/vm.args"
        export VMARGS_PATH="$RELEASE_MUTABLE_DIR"/vm.args
    fi
    if [ $REPLACE_OS_VARS ]; then
        _replace_os_vars "$VMARGS_PATH"
    fi

    # Set SYS_CONFIG_PATH, the path to the sys.config file to use
    # Use $RELEASE_CONFIG_DIR/sys.config if exists, otherwise releases/VSN/sys.config
    if [ -z "$SYS_CONFIG_PATH" ]; then
        if [ -f "$RELEASE_CONFIG_DIR/sys.config" ]; then
            export SYS_CONFIG_PATH="$RELEASE_CONFIG_DIR/sys.config"
        else
            export SYS_CONFIG_PATH="$REL_DIR/sys.config"
        fi
        export SRC_SYS_CONFIG_PATH="$SYS_CONFIG_PATH"
    else
        if [ "$SYS_CONFIG_PATH" != "$RELEASE_MUTABLE_DIR/sys.config" ]; then
            export SRC_SYS_CONFIG_PATH="$SYS_CONFIG_PATH"
        else
            if [ -f "$RELEASE_CONFIG_DIR/sys.config" ]; then
                export SYS_CONFIG_PATH="$RELEASE_CONFIG_DIR/sys.config"
            else
                export SYS_CONFIG_PATH="$REL_DIR/sys.config"
            fi
            export SRC_SYS_CONFIG_PATH="$SYS_CONFIG_PATH"
        fi
    fi
    if [ "$SRC_SYS_CONFIG_PATH" != "$RELEASE_MUTABLE_DIR/sys.config" ]; then
        (echo "%% Generated - edit/create $RELEASE_CONFIG_DIR/sys.config instead."; \
        cat  "$SRC_SYS_CONFIG_PATH")                              \
            > "$RELEASE_MUTABLE_DIR/sys.config"
        export SYS_CONFIG_PATH="$RELEASE_MUTABLE_DIR"/sys.config
    fi
    if [ $REPLACE_OS_VARS ]; then
        _replace_os_vars "$SYS_CONFIG_PATH"
    fi
}

# If TERM is not set, set it to xterm
if [ -z "$TERM" ]; then
    export TERM=xterm
fi

# Make sure ERTS configuration is set
_init_erts_config

# Allow override of where to read configuration from
# By default it's RELEASE_ROOT_DIR
if [ -z "$RELEASE_CONFIG_DIR" ]; then
    export RELEASE_CONFIG_DIR="$RELEASE_ROOT_DIR"
fi

# Make sure directories exist
mkdir -p "$RELEASE_MUTABLE_DIR"
echo "Files in this directory are regenerated frequently, edits will be lost" \
    > "$RELEASE_MUTABLE_DIR/WARNING_README"
mkdir -p "$RUNNER_LOG_DIR"

# Make sure config paths are setup
_init_configs

# Extract the target node name from node.args
# Should be `-sname somename` or `-name somename@somehost`
export NAME_ARG="$(egrep '^-s?name' "$VMARGS_PATH" || true)"
if [ -z "$NAME_ARG" ]; then
    echo "vm.args needs to have either -name or -sname parameter."
    exit 1
fi

# Extract the name type and name from the NAME_ARG for REMSH
# NAME_TYPE should be -name or -sname
export NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')"
# NAME will be either `somename` or `somename@somehost`
export NAME="$(echo "$NAME_ARG" | awk '{print $2}')"

# Where the pipe will be stored when using `start`
# This is used so you can attach the running application to the current
# shell using `attach`
PIPE_DIR="${PIPE_DIR:-$RELEASE_MUTABLE_DIR/erl_pipes/$NAME/}"

# Extract the target cookie
_load_cookie

export ROOTDIR="$RELEASE_ROOT_DIR"
export BINDIR="$ERTS_DIR/bin"
export EMU="beam"
export PROGNAME="erl"
export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH"
export ERTS_LIB_DIR="$ERTS_DIR/../lib"
CONSOLIDATED_DIR="$ROOTDIR/lib/${REL_NAME}-${REL_VSN}/consolidated"

cd "$ROOTDIR"

# User can specify an sname without @hostname
# This will fail when creating remote shell
# So here we check for @ and add @hostname if missing
case $NAME in
    *@*)
        # Nothing to do
        ;;
    *)
        NAME=$NAME@$(gen_nodename)
        ;;
esac

# For Elixir runtime
export DISTILLERY_TASK="$1"

# Check the first argument for instructions
case "$1" in
    start|start_boot)

        # Make sure there is not already a node running
        #RES=`$NODETOOL ping`
        #if [ "$RES" = "pong" ]; then
        #    echo "Node is already running!"
        #    exit 1
        #fi
        # Save this for later.
        CMD=$1
        case "$1" in
            start)
                shift
                START_OPTION="console"
                HEART_OPTION="start"
                ;;
            start_boot)
                shift
                START_OPTION="console_boot"
                HEART_OPTION="start_boot"
                ;;
        esac
        ARGS="$@"
        RUN_PARAM="$@"

        _check_cookie
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"

        # Set arguments for the heart command
        set -- "$SCRIPT_DIR/$REL_NAME" "$HEART_OPTION"
        [ "$RUN_PARAM" ] && set -- "$@" "$RUN_PARAM"

        # Export the HEART_COMMAND
        HEART_COMMAND="$RELEASE_ROOT_DIR/bin/$REL_NAME $CMD"
        export HEART_COMMAND

        mkdir -p "$PIPE_DIR"

        env $RUN_ERL_ENV "$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \
                          "$(_start_command)"

        _run_hooks_from_dir "$POST_START_HOOKS"
        ;;

    stop)
        _check_cookie
        _run_hooks_from_dir "$PRE_STOP_HOOKS"
        # Wait for the node to completely stop...
        PID="$(get_pid)"
        if ! nodetool "stop"; then
            exit 1
        fi
        while $(kill -s 0 "$PID" 2>/dev/null);
        do
            sleep 1
        done
        _run_hooks_from_dir "$POST_STOP_HOOKS"
        ;;

    restart)
        _check_cookie
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"
        ## Restart the VM without exiting the process
        if ! nodetool "restart"; then
            exit 1
        fi
        ;;

    reboot)
        _check_cookie
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"
        ## Restart the VM completely (uses heart to restart it)
        if ! nodetool "reboot"; then
            exit 1
        fi
        ;;

    pid)
        ## Get the VM's pid
        _check_cookie
        if ! get_pid; then
            exit 1
        fi
        ;;

    ping)
        _check_cookie
        ## See if the VM is alive
        if ! nodetool "ping"; then
            exit 1
        fi
        ;;

    pingpeer)
        PEERNAME=$2 nodetool "ping"
        exit_status=$?
        if [ "$exit_status" -ne 0 ]; then
            exit $exit_status
        fi
        ;;

    escript)
        _check_cookie
        ## Run an escript under the node's environment
        if ! escript $@; then
            exit 1
        fi
        ;;

    attach)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift
        exec "$BINDIR/to_erl" "$PIPE_DIR"
        ;;

    remote_console)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift
        _rem_sh
        ;;

    upgrade|downgrade|install)
        if [ -z "$2" ]; then
            echo "Missing package argument"
            echo "Usage: $REL_NAME $1 {package base name}"
            echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
            exit 1
        fi

        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        SOURCE_VERSION="$REL_VSN"
        TARGET_VERSION="$2"

        "$BINDIR/escript" "$ROOTDIR/bin/release_utils.escript" \
             "unpack_release" "$REL_NAME" "$NAME_TYPE"  "$NAME" "$COOKIE" "$TARGET_VERSION"

        # Update environment to reflect target version environment
        REL_VSN="$TARGET_VERSION"
        REL_DIR="$RELEASE_ROOT_DIR/releases/$TARGET_VERSION"

        # Prepare new configs
        _init_configs
        # We have to do some juggling to ensure the correct config is used by the upgrade handler
        # First, we detect if there was a failed upgrade, so we can start over
        if [ -f "$REL_DIR/sys.config.bak" ]; then
            mv "$REL_DIR/sys.config.bak" "$REL_DIR/sys.config"
        fi
        if [ -f "$REL_DIR/vm.args.bak" ]; then
            mv "$REL_DIR/vm.args.bak" "$REL_DIR/vm.args"
        fi
        # Then, backup the packaged configs
        cp "$REL_DIR/sys.config" "$REL_DIR/sys.config.bak"
        cp "$REL_DIR/vm.args" "$REL_DIR/vm.args.bak"
        # Then, substitute in the prepared configs
        cp "$SYS_CONFIG_PATH" "$REL_DIR/sys.config"
        cp "$VMARGS_PATH" "$REL_DIR/vm.args"
        # Make sure any pre-configuration hooks are run
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        # Run any pre-upgrade tasks
        _run_hooks_from_dir "$PRE_UPGRADE_HOOKS"

        "$BINDIR/escript" "$ROOTDIR/bin/release_utils.escript" \
             "install_release" "$REL_NAME" "$NAME_TYPE"  "$NAME" "$COOKIE" "$TARGET_VERSION"

        # We were successful, clean up the configs
        mv "$REL_DIR/sys.config.bak" "$REL_DIR/sys.config"
        mv "$REL_DIR/vm.args.bak" "$REL_DIR/vm.args"

        # Run any post-upgrade hooks
        _run_hooks_from_dir "$POST_UPGRADE_HOOKS"

        ;;
    unpack)
        if [ -z "$2" ]; then
            echo "Missing package argument"
            echo "Usage: $REL_NAME $1 {package base name}"
            echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
            exit 1
        fi

        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        exec "$BINDIR/escript" "$ROOTDIR/bin/release_utils.escript" \
             "unpack_release" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2"
        ;;

    console|console_clean|console_boot)
        # .boot file typically just $REL_NAME (ie, the app name)
        # however, for debugging, sometimes start_clean.boot is useful.
        # For e.g. 'setup', one may even want to name another boot script.
        case "$1" in
            console)
                if [ -f "$REL_DIR/$REL_NAME.boot" ]; then
                  BOOTFILE="$REL_DIR/$REL_NAME"
                else
                  BOOTFILE="$REL_DIR/start"
                fi
                ;;
            console_clean)
                BOOTFILE="$ROOTDIR/bin/start_clean"
                __code_paths=$(_get_code_paths)
                EXTRA_CODE_PATHS=${__code_paths}
                ;;
            console_boot)
                shift
                BOOTFILE="$1"
                shift
                ;;
        esac
        # Setup beam-required vars
        EMU="beam"
        PROGNAME="${0#*/}"

        export EMU
        export PROGNAME

        # Store passed arguments since they will be erased by `set`
        ARGS="$@"

        _check_cookie

        # Start the VM, executing pre_start hook along
        # the way. We can't run the post_start hook because
        # the console will crash with no TTY attached
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"

        # Build an array of arguments to pass to exec later on
        # Build it here because this command will be used for logging.
        set -- "$BINDIR/erlexec" \
            -boot "$BOOTFILE" \
            -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -env ERL_LIBS "$REL_LIB_DIR" \
            -pa "$CONSOLIDATED_DIR" \
            ${EXTRA_CODE_PATHS} \
            -args_file "$VMARGS_PATH" \
            -config "$SYS_CONFIG_PATH" \
            -mode "$CODE_LOADING_MODE" \
            ${ERL_OPTS} \
            -user Elixir.IEx.CLI \
            -extra --no-halt +iex

        # Dump environment info for logging purposes
        if [ ! -z $VERBOSE ]; then
            echo "Exec: $@" -- ${1+$ARGS} ${EXTRA_OPTS}
            echo "Root: $ROOTDIR"

            # Log the startup
            echo "$RELEASE_ROOT_DIR"
        fi;

        logger -t "$REL_NAME[$$]" "Starting up"

        exec "$@" -- ${1+$ARGS} ${EXTRA_OPTS}
        ;;

    foreground)
        # start up the release in the foreground for use by runit
        # or other supervision services

        [ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
        FOREGROUNDOPTIONS="-noshell -noinput +Bd"

        # Setup beam-required vars
        EMU=beam
        PROGNAME="${0#*/}"

        export EMU
        export PROGNAME

        # Store passed arguments since they will be erased by `set`
        ARGS="$@"

        _check_cookie

        # Start the VM, executing pre and post start hooks
        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
        _run_hooks_from_dir "$PRE_START_HOOKS"

        # Build an array of arguments to pass to exec later on
        # Build it here because this command will be used for logging.
        set -- "$BINDIR/erlexec" $FOREGROUNDOPTIONS \
            -boot "$REL_DIR/$BOOTFILE" \
            -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
            -env ERL_LIBS "$REL_LIB_DIR" \
            -pa "$CONSOLIDATED_DIR" \
            -args_file "$VMARGS_PATH" \
            -config "$SYS_CONFIG_PATH" \
            -mode "$CODE_LOADING_MODE" \
            ${ERL_OPTS} \
            -extra ${EXTRA_OPTS}

        # Dump environment info for logging purposes
        if [ ! -z $VERBOSE ]; then
            echo "Exec: $@" -- ${1+$ARGS}
            echo "Root: $ROOTDIR"
        fi;

        "$@" -- ${1+$ARGS} &
        __bg_pid=$!
        _run_hooks_from_dir "$POST_START_HOOKS"
        wait $__bg_pid
        _run_hooks_from_dir "$POST_STOP_HOOKS"
        ;;
    rpc)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift

        nodetool rpc $@
        ;;
    rpcterms)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift

        nodetool rpcterms $@
        ;;
    eval)
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        shift
        nodetool "eval" $@
        ;;
    command)
        # Execute as command-line utility
        #
        # Like the escript command, this does not start the OTP application.
        # If your command depends on a running OTP application,
        # use
        #
        #     {:ok, _} = Application.ensure_all_started(:your_app)

        _check_cookie

        shift
        MODULE="$1"; shift
        FUNCTION="$1"; shift

        # Save extra arguments
        ARGS="$@"

        # Build arguments for erlexec
        __code_paths=$(_get_code_paths)
        set -- "$ERL_OPTS"
        [ "$SYS_CONFIG_PATH" ] && set -- "$@" -config "$SYS_CONFIG_PATH"
        set -- "$@" -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR"
        set -- "$@" -noshell
        set -- "$@" -boot start_clean
        set -- "$@" -pa "$CONSOLIDATED_DIR"
        set -- "$@" ${__code_paths}
        set -- "$@" -s "$MODULE" "$FUNCTION"

        $BINDIR/erlexec $@ -extra $ARGS
        exit "$?"
        ;;
    reload_config)
        # Reload the running system's configuration
        _check_cookie

        # Make sure a node IS running
        if ! nodetool "ping" > /dev/null; then
            echo "Node is not running!"
            exit 1
        fi

        _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"

        shift
        nodetool "reload_config" "$SYS_CONFIG_PATH"
        ;;
    describe)
        ## Print a summary of information about this release
        echo "$REL_NAME-$REL_VSN\n"
        echo "erts:        $ERTS_VSN"
        echo "path:        $REL_DIR"
        echo "sys.config:  $SYS_CONFIG_PATH"
        echo "vm.args:     $VMARGS_PATH"
        echo "name:        $NAME"
        echo "cookie:      $COOKIE"
        echo "erl_opts:    ${ERL_OPTS:-none provided}"
        echo "run_erl_env: ${RUN_ERL_ENV:-none provided}"
        echo ""
        echo "hooks:"
        __has_hooks=0
        for hook in "$REL_DIR"/hooks/*.d/[0-9a-zA-Z]*.sh; do
            [ -f "$hook" ] || continue
            __has_hooks=1
            echo "$hook"
        done
        if [ $__has_hooks -eq 0 ]; then
            echo "No custom hooks found."
        fi
        echo ""
        echo "commands:"
        __has_commands=0
        for command in "$REL_DIR"/commands/*.sh; do
            [ -f "$command" ] || continue
            __has_commands=1
            echo "$command"
        done
        if [ $__has_commands -eq 0 ]; then
            echo "No custom commands found."
        fi
        exit 0
        ;;
    *)
        __command_path="$REL_DIR/commands/$1"
        if [ -f "$__command_path" ]; then
            _check_cookie
            . "$__command_path"
        else
            echo "Usage: $REL_NAME <task>"
            echo
            echo "Service Control"
            echo "======================="
            echo "start                          # start $REL_NAME as a daemon"
            echo "start_boot <file>              # start $REL_NAME as a daemon, but supply a custom .boot file"
            echo "foreground                     # start $REL_NAME in the foreground"
            echo "console                        # start $REL_NAME with a console attached"
            echo "console_clean                  # start a console with code paths set but no apps loaded/started"
            echo "console_boot <file>            # start $REL_NAME with a console attached, but supply a custom .boot file"
            echo "stop                           # stop the $REL_NAME daemon"
            echo "restart                        # restart the $REL_NAME daemon without shutting down the VM"
            echo "reboot                         # restart the $REL_NAME daemon"
            echo "reload_config                  # reload the current system's configuration from disk"
            echo
            echo "Upgrades"
            echo "======================="
            echo "upgrade <version>              # upgrade $REL_NAME to <version>"
            echo "downgrade <version>            # downgrade $REL_NAME to <version>"
            echo "install <version>              # install the $REL_NAME-<version> release, but do not upgrade to it"
            echo
            echo "Utilities"
            echo "======================="
            echo "attach                         # attach the current TTY to $REL_NAME's console"
            echo "remote_console                 # remote shell to $REL_NAME's console"
            echo "pid                            # get the pid of the running $REL_NAME instance"
            echo "ping                           # checks if $REL_NAME is running, pong is returned if successful"
            echo "pingpeer <peer>                # check if a peer node is running, pong is returned if successful"
            echo "escript <file>                 # execute an escript"
            echo "rpc <mod> <fun> [<args..>]     # execute an RPC call using the given MFA"
            echo "rpcterms <mod> <fun> [<expr>]  # execute an RPC call using the given Erlang expression for args"
            echo "eval <expr>                    # execute the given Erlang expression on the running node"
            echo "command <mod> <fun> [<args..>] # execute the given MFA"
            echo "describe                       # print useful information about the $REL_NAME release"
            echo
            echo "Custom Commands"
            echo "======================="
            __has_commands=0
            for command in "$REL_DIR"/commands/*.sh; do
                [ -f "$command" ] || continue
                __has_commands=1
                echo "$command"
            done
            if [ $__has_commands -eq 0 ]; then
                echo "No custom commands found."
            fi
            echo ""
            exit 1
        fi
        ;;
esac

exit 0


Add optional white space after doctype definition

document <- (space? crlf)* doctype? tags? eof;

doctype <- space? 'doctype' space name:(!eol .)+ eol (space? crlf)*;

tag <- comment / verbatim_text / tag_item;
tag_item <- space? (embedded_engine / inline_html / code / slime_tag);

tags <- (tag crlf*)+;
nested_tags <- crlf+ indent tags dedent;

inline_html <- &'<' text_item+ nested_tags?;

slime_tag <- tag_shortcut tag_spaces space? tag_attributes_and_content;

% NOTE: tag content cannot begin with attribute wrappers if attributes are not present.
tag_attributes_and_content <- attributes space? tag_content
  / !('<%= attr_list_delims |> Map.keys |> Enum.join("' / '") %>') tag_content;

tag_content <- '/' / inline_tag / nested_tags / dynamic_content / inline_text / '';

inline_tag <- ':' space? slime_tag;

inline_text <- !eol text_block;

dynamic_content <- '=' '='? space? (!eol .)+;

code <- output:('=' '='? tag_spaces? / '-') space?
  code:code_lines children:nested_tags? optional_else:code_else_condition?;
code_else_condition <- crlf* space? '-' space? 'else' children:nested_tags?;
code_lines <- code_line / code_line_with_break crlf code_lines;
code_line <- (!(. eol) .)* !code_line_break . &eol;
code_line_with_break <- (!(. eol) .)* code_line_break &eol;
code_line_break <-  ',' / '\\';

tag_spaces <- leading:'<'? trailing:'>'?;

tag_shortcut <- tag:tag_name attrs:shortcuts / tag:tag_name / attrs:shortcuts;

shortcuts <- head:shortcut tail:(shortcut)*;

shortcut <- type:('.' / '#' / '@' / '$' / '%' / '^' / '&' / '+' / '!') value:tag_name;

attributes <- wrapped_attributes / plain_attributes;

wrapped_attributes <-
  <%=
    attr_list_delims
    |> Enum.flat_map(fn ({open, close}) -> [
        "'#{open}' crlf+ indent wrapped_attribute+ (eol / space)+ '#{close}'",
        "'#{open}' wrapped_attribute+ '#{close}'"
      ]
    end)
    |> Enum.join(" / ")
  %>;

wrapped_attribute <- (space / eol)* (attribute:attribute / attribute_name:tag_name);

plain_attributes <- head:attribute tail:(space attribute)*;

attribute <- attribute_name '=' '='? attribute_value;

attribute_value <- simple:string / dynamic:(string_with_interpolation / attribute_code);

string <- '"' ('\\' . / !('"' / '#{') .)* '"';
string_with_interpolation <- '"' (elixir_interpolation / '\\' . / !'"' .)* '"';

attribute_code <- (parentheses / brackets / braces / !(space / eol / ')' / ']' / '}') .)+;

text_item <- static:text / dynamic:(safe:safe_interpolation / interpolation);
text <- ('\\' . / !('#{' / eol) .)+;
elixir_interpolation <- '#{' (string / string_with_interpolation / !'}' .)* '}';
interpolation <- '#{' (string / string_with_interpolation / !'}' .)* '}';
safe_interpolation <- '#{{' (string / string_with_interpolation / !'}}' .)* '}}';

parentheses <- '(' (parentheses / !')' .)* ')';
brackets <- '[' (brackets / !']' .)* ']';
braces <- '{' (braces / !'}' .)* '}';

comment <- html_comment / space? code_comment;

html_comment <- indent:space? type:'/!' content:text_block;

code_comment <- '/' text_block;

verbatim_text <- indent:space? type:[|'] content:text_block;

text_block <- indented_text_line (crlf
  indent lines:text_block_nested_lines dedent)?;
text_block_nested_lines <- indented_text_line (crlf (
  indent lines:text_block_nested_lines dedent / lines:text_block_nested_lines
))*;

embedded_engine <- tag_name ':' (crlf indent lines:embedded_engine_lines dedent);
embedded_engine_lines <- indented_text_line (crlf indented_text_line)*;

indented_text_line <- space? text_item*;

tag_name <- [a-zA-Z0-9_-]+;
attribute_name <- [a-zA-Z0-9._@:-]+;
space <- [ \t]+;
indent <- '\x{0E}';
dedent <- '\x{0F}';
crlf <- '\r'? '\n';
eof <- !.;
eol <- dedent / crlf / eof;

document <- (space? crlf)* doctype? tags? eof;

doctype <- space? 'doctype' space name:(!eol .)+ eol;

tag <- comment / verbatim_text / tag_item;
tag_item <- space? (embedded_engine / inline_html / code / slime_tag);

tags <- (tag crlf*)+;
nested_tags <- crlf+ indent tags dedent;

inline_html <- &'<' text_item+ nested_tags?;

slime_tag <- tag_shortcut tag_spaces space? tag_attributes_and_content;

% NOTE: tag content cannot begin with attribute wrappers if attributes are not present.
tag_attributes_and_content <- attributes space? tag_content
  / !('<%= attr_list_delims |> Map.keys |> Enum.join("' / '") %>') tag_content;

tag_content <- '/' / inline_tag / nested_tags / dynamic_content / inline_text / '';

inline_tag <- ':' space? slime_tag;

inline_text <- !eol text_block;

dynamic_content <- '=' '='? space? (!eol .)+;

code <- output:('=' '='? tag_spaces? / '-') space?
  code:code_lines children:nested_tags? optional_else:code_else_condition?;
code_else_condition <- crlf* space? '-' space? 'else' children:nested_tags?;
code_lines <- code_line / code_line_with_break crlf code_lines;
code_line <- (!(. eol) .)* !code_line_break . &eol;
code_line_with_break <- (!(. eol) .)* code_line_break &eol;
code_line_break <-  ',' / '\\';

tag_spaces <- leading:'<'? trailing:'>'?;

tag_shortcut <- tag:tag_name attrs:shortcuts / tag:tag_name / attrs:shortcuts;

shortcuts <- head:shortcut tail:(shortcut)*;

shortcut <- type:('.' / '#' / '@' / '$' / '%' / '^' / '&' / '+' / '!') value:tag_name;

attributes <- wrapped_attributes / plain_attributes;

wrapped_attributes <-
  <%=
    attr_list_delims
    |> Enum.flat_map(fn ({open, close}) -> [
        "'#{open}' crlf+ indent wrapped_attribute+ (eol / space)+ '#{close}'",
        "'#{open}' wrapped_attribute+ '#{close}'"
      ]
    end)
    |> Enum.join(" / ")
  %>;

wrapped_attribute <- (space / eol)* (attribute:attribute / attribute_name:tag_name);

plain_attributes <- head:attribute tail:(space attribute)*;

attribute <- attribute_name '=' '='? attribute_value;

attribute_value <- simple:string / dynamic:(string_with_interpolation / attribute_code);

string <- '"' ('\\' . / !('"' / '#{') .)* '"';
string_with_interpolation <- '"' (elixir_interpolation / '\\' . / !'"' .)* '"';

attribute_code <- (parentheses / brackets / braces / !(space / eol / ')' / ']' / '}') .)+;

text_item <- static:text / dynamic:(safe:safe_interpolation / interpolation);
text <- ('\\' . / !('#{' / eol) .)+;
elixir_interpolation <- '#{' (string / string_with_interpolation / !'}' .)* '}';
interpolation <- '#{' (string / string_with_interpolation / !'}' .)* '}';
safe_interpolation <- '#{{' (string / string_with_interpolation / !'}}' .)* '}}';

parentheses <- '(' (parentheses / !')' .)* ')';
brackets <- '[' (brackets / !']' .)* ']';
braces <- '{' (braces / !'}' .)* '}';

comment <- html_comment / space? code_comment;

html_comment <- indent:space? type:'/!' content:text_block;

code_comment <- '/' text_block;

verbatim_text <- indent:space? type:[|'] content:text_block;

text_block <- indented_text_line (crlf
  indent lines:text_block_nested_lines dedent)?;
text_block_nested_lines <- indented_text_line (crlf (
  indent lines:text_block_nested_lines dedent / lines:text_block_nested_lines
))*;

embedded_engine <- tag_name ':' (crlf indent lines:embedded_engine_lines dedent);
embedded_engine_lines <- indented_text_line (crlf indented_text_line)*;

indented_text_line <- space? text_item*;

tag_name <- [a-zA-Z0-9_-]+;
attribute_name <- [a-zA-Z0-9._@:-]+;
space <- [ \t]+;
indent <- '\x{0E}';
dedent <- '\x{0F}';
crlf <- '\r'? '\n';
eof <- !.;
eol <- dedent / crlf / eof;


Inspecting stats

Inspecting stats

Yearly Statistics

<%= inspect @stats %>
<%# <%= for key <- @stats do %>
    <%#
<%= key %>
 %>
  <%# <% end %> %> %>

<%# <%= render "statistic_card.html", conn: @conn, stat: @stats.current_month, previous: @stats.previous_month, title: "Current Month", type: "current_month" %>

<%# <%= render "statistic_card.html", conn: @conn, stat: @stats.current_year, previous: @stats.previous_year, title: "Current Year", type: "current_year" %> %>

<%# <%= render "statistic_card.html", conn: @conn, stat: @stats.all_time, previous: 0, title: "All Time", type: "all_time"  %> %> %>

Yearly Statistics

<%= for key <- @stats do %>

<%= key %>

  <% end %>

<%# <%= render "statistic_card.html", conn: @conn, stat: @stats.current_month, previous: @stats.previous_month, title: "Current Month", type: "current_month" %>

<%# <%= render "statistic_card.html", conn: @conn, stat: @stats.current_year, previous: @stats.previous_year, title: "Current Year", type: "current_year" %> %>

<%# <%= render "statistic_card.html", conn: @conn, stat: @stats.all_time, previous: 0, title: "All Time", type: "all_time"  %> %> %>


Improve watchdog script

Improve watchdog script

#!/usr/bin/env bash

# This is meant to be executed periodically. It will check if the application is
# running. If it's not, it will start it.

# on crontab:
#    * * * * * /bin/bash -l -c '/path/to/watchdog/watchdog.sh'

app="<%= app %>"
user="<%= user %>"
dir="/home/$user/$app/current"
log="$dir/log/$app.log"
touch $log # ensure existence

# test proof of life
alive="$dir/tmp/alive"
if [ -f $alive ]; then
  mtime=$(ls -l --time-style=+%s $alive | awk '{print $6}')
  let "last = $(date +%s) - 60"
  [ $mtime -gt $last ] && exit
fi
touch $alive # ensure existence

# start in a detached erlang VM
cmd="erl -boot $dir/boot/start -config $dir/boot/sys -env ERL_LIBS $dir/lib"
cmd="$cmd -name $app@localhost -detached"

echo "$(date) Running: $cmd" >> $log

$cmd 2>&1 >> $log

########################################
#
#     Some ways to run your app:
#
#     To run (embedded erlang):
#     ```
#         run_erl -daemon /home/$user/$app/pipes/ /home/$user/$app/log
#           "erl -boot $dir/boot/start
#                -config $dir/boot/sys
#                -env ERL_LIBS $dir/lib
#                -sname $app"
#     ```
#
#     To connect (embedded erlang):
#     ```
#         to_erl /home/$user/$app/pipes/erlang.pipe.1
#     ```
#
#     To run (interactive erlang):
#     ```
#         erl -boot $dir/boot/start
#             -config $dir/boot/sys
#             -env ERL_LIBS $dir/lib
#             -name $app@localhost
#     ```
#
#     To run (interactive elixir, using app's own `iex`):
#     ```
#         erl -boot $dir/boot/start
#             -config $dir/boot/sys
#             -env ERL_LIBS $dir/lib
#             -name $app@localhost
#             -noshell -user Elixir.IEx.CLI -extra --no-halt
#     ```
#
#     To run (detached elixir):
#     ```
#         iex --erl "-boot $dir/boot/start
#                    -config $dir/boot/sys
#                    -env ERL_LIBS $dir/lib"
#             --name $app@localhost
#             --detached
#     ```
#
#     To run (detached erlang):
#     ```
#         erl -boot $dir/boot/start
#             -config $dir/boot/sys
#             -env ERL_LIBS $dir/lib
#             -name $app@localhost
#             -detached
#     ```
#
#     To connect (interactive elixir):
#     ```
#         iex --remsh $app@localhost --sname connector
#     ```
#
#     To connect (interactive erlang):
#     ```
#         erl -remsh $app@localhost -sname connector
#     ```
#
#     To connect (interactive elixir, using app's own `iex`):
#     ```
#         erl -remsh $app@localhost -sname connector
#         # and then ...
#         ($app@localhost)1> 'Elixir.IEx':start().
#     ```
#

#!/usr/bin/env bash

# This is meant to be executed periodically. It will check if the application is
# running. If it's not, it will start it.

# on crontab:
#    * * * * * /bin/bash -l -c '/path/to/watchdog/watchdog.sh'

app="<%= app %>"
user="<%= user %>"
dir="/home/$user/$app/current"
log="$dir/log/$app.log"

# test proof of life
alive="$dir/tmp/alive"
mtime=$(ls -l --time-style=+%s $alive | awk '{print $6}')
let "last = $(date +%s) - 60"
[ -f $alive ] && [ $mtime -gt $last ] && exit

# start in a detached erlang VM
cmd="erl -boot $dir/boot/start -config $dir/boot/sys -env ERL_LIBS $dir/lib"
cmd="$cmd -name $app@localhost -detached"

echo "$(date) Running: $cmd" >> $log

$cmd 2>&1 >> $log


tweak indenting

tweak indenting

overlay opacity

<!- div id="coords">

<input id="opacity" class="range-slider" type="range" value= "0.8" min="0.0" max="1.0" step="0.05" />


use browser url

use browser url

 Name and Time

 Location

<%= for ev <- @events do %>

 <%= ev.title %>

       <%= ev.date_line %>

      <a class="little-button" href="<%= ev.browser_url %>" style="display: block;" target="_blank"> RSVP

 <%= ev.location.venue %>

      <%= ev.location.address_lines |> List.first() %>

      <%= ev.location.locality %> <%= ev.location.region %>

<% end %>

<%= if assigns[:person] != nil do %>
  <form>
  Done: <%= assigns[:person] %>
 </form>
<% end %>
No events? Can they not attend the events above? Sign them up below to be added to our volunteer list for future events.
<form method="post" action="/call-aid/<%= @slug %>">
  <input type="hidden" name="_csrf_token" value="<%= csrf_token() %>" />

  First Name

  <input type="text" name="first_name" style="padding: 10px; font-size: larger;" />

  Last Name

  <input type="text" name="last_name" style="padding: 10px; font-size: larger;" />

  Phone Number

  <input type="tel" name="phone" style="padding: 10px; font-size: larger;" />

  Email

  <input type="email" name="email" style="padding: 10px; font-size: larger;" />

  <input
    type="submit"
    value="Mark as Volunteer" class="primary-button"
    style="padding: 5px; width: 225px;"/>
</form>

 Name and Time

 Location

<%= for ev <- @events do %>

 <%= ev.title %>

       <%= ev.date_line %>

      <a class="little-button" href="/events/<%= ev.name %>" style="display: block;" target="_blank"> RSVP

 <%= ev.location.venue %>

      <%= ev.location.address_lines |> List.first() %>

      <%= ev.location.locality %> <%= ev.location.region %>

<% end %>

<%= if assigns[:person] != nil do %>
  <form>
  Done: <%= assigns[:person] %>
 </form>
<% end %>
No events? Can they not attend the events above? Sign them up below to be added to our volunteer list for future events.
<form method="post" action="/call-aid/<%= @slug %>">
  <input type="hidden" name="_csrf_token" value="<%= csrf_token() %>" />

  First Name

  <input type="text" name="first_name" style="padding: 10px; font-size: larger;" />

  Last Name

  <input type="text" name="last_name" style="padding: 10px; font-size: larger;" />

  Phone Number

  <input type="tel" name="phone" style="padding: 10px; font-size: larger;" />

  Email

  <input type="email" name="email" style="padding: 10px; font-size: larger;" />

  <input
    type="submit"
    value="Mark as Volunteer" class="primary-button"
    style="padding: 5px; width: 225px;"/>
</form>


no manual submit, respects requireds

no manual submit, respects requireds

<meta name="description" content="<%=@title%>" />
<meta name="keywords" content="<%=@title <> "" <> copyright(@brand)%>" />
<meta name="author" content="copyright(@brand)%>" />
<meta name="copyright" content="copyright(@brand)%>" />

<meta property="og:url" content="<%= core_deployment(@brand) <> "/petition/" <> @slug%>" />
<meta property="og:title" content="<%=@title%>" />
<meta property="og:type" content="article" />
<meta property="og:image" content="<%=@share_image%>" />
<meta property="og:description" content="<%=@content%>" />

<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="<%=@title%>" />
<meta name="twitter:description" content="<%=@content%>" />
<meta name="twitter:image" content="<%=@share_image%>" />

    <%= if not @signed do %>

        <%= raw(@content) %>

      <%= if @count do %>

          <div class="count-bar" style="width: <%= @progress %>%;">

           <%= @count %> people have signed. Help us get to <%= @target %>!

      <% end %>

      <%= form_tag("/petition/#{@slug}", method: :post, id: "main-form") %>

          <input type="hidden" name="_csrf_token" value="<%= csrf_token() %>" />

          <fieldset style="margin-top: 20px;">
            <legend style="color:white;">Your Info</legend>

              Name
              <input type="text" name="name" required="required"/>

              Email
              <input type="email" name="email" required="required"/>

              Mobile Phone Number
              <input type="tel" name="phone" />

              Zip
              <input type="text" name="zip" maxlength="5" required="required" />

              <%= if @brand == "jd" do %>
                <button onclick="fbq('track', 'Lead');" type="submit" class="button-block"><%=@sign_button_text%></button>
              <% else %>
                <button type="submit" class="button-block"><%=@sign_button_text%></button>
              <% end %>

          </fieldset>

            By signing this petition, I consent to receiving emails from
            <%= if @slug == "jd-stop-war" do %>
              <a target="_blank" href="<%=homepage(@brand)%>"><%=copyright(@brand)%> and
              Ro Khanna.
            <% else %>
              <a target="_blank" href="<%=homepage(@brand)%>"><%=copyright(@brand)%>.
            <% end %>

      </form>

    <% else %>

        <%= raw(@post_sign_text) %>

 Next Steps

      <fieldset style="margin-top: 20px; color: white;">
        <legend style="color:white;">Help us get to <%= @target %> signatures by sharing on social media</legend>

        <a class="twitter-share-button" href="<%=@twitter_href%>" data-size="large">
          Tweet

        <div class="fb-share-button" data-href="<%=@url%>" data-layout="button_count" data-size="large" style="float:right;">
          <a class="fb-xfbml-parse-ignore" target="_blank"
            style="background-color: #3b5998; color: white; padding: 5px; text-decoration: none; margin-top: 5px;"
            href="<%=@fb_href%>"
          >
            Share on Facebook

      </fieldset>

      <%= if @call_power_campaign_id != nil and @call_power_campaign_id != "" do %>

        <fieldset style="color:white;">
          <legend> <%= @call_power_header %> </legend>

            <%= raw(@call_power_prompt) %>

          <form id="call_form">
            <input id="phone_id" type="hidden" value="<%= @submitted_phone %>"/>
            <input id="location_id" type="hidden" value="<%= @submitted_zip %>" />
            <button type="submit" style="width: 100%; margin-top: 10px;" id="call-power-go"> Call Me At <%= @submitted_phone %> </button>
          </form>

          <%= form_tag("/petition/#{@slug}", method: :post, id: "number-replace-form", style: "margin-top: 10px;") %>
            <input name="name" value="<%= @submitted_name %>" type="hidden" />
            <input name="email" value="<%= @submitted_email %>" type="hidden" />
            <input name="zip" value="<%= @submitted_zip %>" type="hidden" />

              Different Number
              <input type="tel" name="phone" />

              <button id="number-replace-button" class="button-block">Call Me at a Different Number</button>

          </form>
        </fieldset>
      <% end %>

    <% end %>

<%= if @brand == "jd" do %>

<% end %>

<meta name="description" content="<%=@title%>" />
<meta name="keywords" content="<%=@title <> "" <> copyright(@brand)%>" />
<meta name="author" content="copyright(@brand)%>" />
<meta name="copyright" content="copyright(@brand)%>" />

<meta property="og:url" content="<%= core_deployment(@brand) <> "/petition/" <> @slug%>" />
<meta property="og:title" content="<%=@title%>" />
<meta property="og:type" content="article" />
<meta property="og:image" content="<%=@share_image%>" />
<meta property="og:description" content="<%=@content%>" />

<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="<%=@title%>" />
<meta name="twitter:description" content="<%=@content%>" />
<meta name="twitter:image" content="<%=@share_image%>" />

    <%= if not @signed do %>

        <%= raw(@content) %>

      <%= if @count do %>

          <div class="count-bar" style="width: <%= @progress %>%;">

           <%= @count %> people have signed. Help us get to <%= @target %>!

      <% end %>

      <%= form_tag("/petition/#{@slug}", method: :post, id: "main-form") %>

          <input type="hidden" name="_csrf_token" value="<%= csrf_token() %>" />

          <fieldset style="margin-top: 20px;">
            <legend style="color:white;">Your Info</legend>

              Name
              <input type="text" name="name" required="required"/>

              Email
              <input type="email" name="email" required="required"/>

              Mobile Phone Number
              <input type="tel" name="phone" />

              Zip
              <input type="text" name="zip" maxlength="5" required="required" />

              <%= if @brand == "jd" do %>
                <button onclick="fbq('track', 'Lead'); document.querySelector('#main-form').submit();" type="submit" class="button-block"><%=@sign_button_text%></button>
              <% else %>
                <button type="submit" class="button-block"><%=@sign_button_text%></button>
              <% end %>

          </fieldset>

            By signing this petition, I consent to receiving emails from
            <%= if @slug == "jd-stop-war" do %>
              <a target="_blank" href="<%=homepage(@brand)%>"><%=copyright(@brand)%> and
              Ro Khanna.
            <% else %>
              <a target="_blank" href="<%=homepage(@brand)%>"><%=copyright(@brand)%>.
            <% end %>

      </form>

    <% else %>

        <%= raw(@post_sign_text) %>

 Next Steps

      <fieldset style="margin-top: 20px; color: white;">
        <legend style="color:white;">Help us get to <%= @target %> signatures by sharing on social media</legend>

        <a class="twitter-share-button" href="<%=@twitter_href%>" data-size="large">
          Tweet

        <div class="fb-share-button" data-href="<%=@url%>" data-layout="button_count" data-size="large" style="float:right;">
          <a class="fb-xfbml-parse-ignore" target="_blank"
            style="background-color: #3b5998; color: white; padding: 5px; text-decoration: none; margin-top: 5px;"
            href="<%=@fb_href%>"
          >
            Share on Facebook

      </fieldset>

      <%= if @call_power_campaign_id != nil and @call_power_campaign_id != "" do %>

        <fieldset style="color:white;">
          <legend> <%= @call_power_header %> </legend>

            <%= raw(@call_power_prompt) %>

          <form id="call_form">
            <input id="phone_id" type="hidden" value="<%= @submitted_phone %>"/>
            <input id="location_id" type="hidden" value="<%= @submitted_zip %>" />
            <button type="submit" style="width: 100%; margin-top: 10px;" id="call-power-go"> Call Me At <%= @submitted_phone %> </button>
          </form>

          <%= form_tag("/petition/#{@slug}", method: :post, id: "number-replace-form", style: "margin-top: 10px;") %>
            <input name="name" value="<%= @submitted_name %>" type="hidden" />
            <input name="email" value="<%= @submitted_email %>" type="hidden" />
            <input name="zip" value="<%= @submitted_zip %>" type="hidden" />

              Different Number
              <input type="tel" name="phone" />

              <button id="number-replace-button" class="button-block">Call Me at a Different Number</button>

          </form>
        </fieldset>
      <% end %>

    <% end %>

<%= if @brand == "jd" do %>

<% end %>


Adapt HTML title.

Adapt HTML title.

<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Yearly - Leap years as an online service!</title>
    <link rel="stylesheet" href="/css/phoenix.css">

Get Started

      <%= @inner %>

phoenixframework.org

<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Hello Phoenix!</title>
    <link rel="stylesheet" href="/css/phoenix.css">

Get Started

      <%= @inner %>

phoenixframework.org


Resolve the issue 112 (#125)

Resolve the issue 112 (#125)

<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Online Experiments System for Economic Education">
    <meta name="author" content="Ryohei HAYASHI">

    <%= if assigns[:title] do %>
      <title>XEE.JP - <%= @title %> -</title>
    <% else %>
      <title>XEE.JP</title>
    <% end %>

    <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
    <link rel="shortcut icon" href="<%= static_path(@conn, "/favicon.ico") %>">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css">

    <link href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.1.0/introjs.min.css" rel="stylesheet" type="text/css">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

<a href="<%= host_path(@conn, :index) %>">実験管理画面

<%= link "ログアウト", to: session_path(@conn, :delete) %>

            XEE.JP
            <%= if assigns[:title] do %>
              <%= @title %>
            <%= end %>

              <%= if logged_in?(@conn) do %>

<%= current_user(@conn).name %>

              <% else %>
                <%= unless assigns[:title] do %>

<%= link "教師用ページ", to: registration_path(@conn, :new) %>

<%= link "ログイン", to: session_path(@conn, :new) %>

                <% end %>
              <% end %>

<%= get_flash(@conn, :info) %>

<%= get_flash(@conn, :error) %>

      <%= render @view_module, @view_template, assigns %>

© 2015 Ryohei HAYASHI All Rights Reserved.

Powered by <a href="<%= page_path(@conn, :about) %>">Xee System.

<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Online Experiments System for Economic Education">
    <meta name="author" content="Ryohei HAYASHI">

    <%= if assigns[:title] do %>
      <title>XEE.JP - <%= @title %> -</title>
    <% else %>
      <title>XEE.JP</title>
    <% end %>

    <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
    <link rel="shortcut icon" href="<%= static_path(@conn, "/favicon.ico") %>">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css">

    <link href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/2.1.0/introjs.min.css" rel="stylesheet" type="text/css">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

<a href="<%= host_path(@conn, :index) %>">実験管理画面

<%= link "ログアウト", to: session_path(@conn, :delete) %>

            XEE.JP
            <%= if assigns[:title] do %>
              <%= @title %>
            <%= end %>

              <%= if logged_in?(@conn) do %>

<%= current_user(@conn).name %>

              <% else %>

<%= link "教師用ページ", to: registration_path(@conn, :new) %>

<%= link "ログイン", to: session_path(@conn, :new) %>

              <% end %>

<%= get_flash(@conn, :info) %>

<%= get_flash(@conn, :error) %>

      <%= render @view_module, @view_template, assigns %>

© 2015 Ryohei HAYASHI All Rights Reserved.

Powered by <a href="<%= page_path(@conn, :about) %>">Xee System.


changed text

changed text

username: <%= @identity.username %>

<%= @identity.name %>

<a href="/identities/<%= @identity.id %>/delegations/from">made <%= @num_delegations_from %> <%= ngettext("delegation", "delegations", @num_delegations_from) %>
  |
<a href="/identities/<%= @identity.id %>/delegations/to">receiving <%= @num_delegations_to %> <%= ngettext("delegation", "delegations", @num_delegations_to) %>
  |
<a href="/identities/<%= @identity.id %>/votes">voted on <%= @num_votes %> <%= ngettext("poll", "polls", @num_votes) %>

<%= unless @is_in_trust_metric do %>

NOT IN TRUST METRIC

<% end %>

<%= if @is_me do %>

Share the URL of your identity with others, so they can trust or delegate to you.

Calculation preferences

	<form method="POST" action="preferences" class="pure-form">
		<input type="hidden" name="_csrf_token" value="<%= get_csrf_token() %>" />

				Trust metric URL

				<input type="url" name="trust_metric_url" value="<%= @identity.trust_metric_url %>" placeholder="<%= @default_trust_metric_url %>" />

				Polls

					<input type="range" name="minimum_voting_power" id="minimum_voting_power_range" value="<%= @identity.minimum_voting_power || 0 %>" min="0" max="1" step="any" oninput="minimum_voting_power_value.value = 'Expecting at least ' + Math.round(100 * minimum_voting_power_range.value) + '% turnout.'" />
					<output id="minimum_voting_power_value"><%= "Expecting at least #{round(100 * (@identity.minimum_voting_power || 0))}% turnout." %></output>

					<input type="range" name="vote_weight_halving_days" id="vote_weight_halving_days_range" value="<%= @identity.vote_weight_halving_days || 1000 %>" min="1" max="1000" step="1" oninput="vote_weight_halving_days_value.value = Math.round(vote_weight_halving_days_range.value) == 1000 ? 'Votes don\'t lose power with time.' : 'Votes will lose half remaining power every ' + Math.round(vote_weight_halving_days_range.value) + ' days.'" />
					<output id="vote_weight_halving_days_value">
						<%= if @identity.vote_weight_halving_days do "Votes will lose half remaining power every #{round(@identity.vote_weight_halving_days)} days." else "Votes don't lose power with time." end %>
					</output>

				Reference approvals

					<input type="range" name="soft_quorum_t" id="soft_quorum_t_range" value="<%= @identity.soft_quorum_t || 0 %>" min="0" max="1" step="any" oninput="soft_quorum_t_value.value = 'Turnout importance set at ' + Math.round(100 * soft_quorum_t_range.value) + '%.'">
					<output id="soft_quorum_t_value"><%= "Turnout importance set at #{round(100 * (@identity.soft_quorum_t || 0))}%." %></output>

					<input type="range" name="minimum_reference_approval_score" id="minimum_score_range" value="<%= @identity.minimum_reference_approval_score || 0 %>" min="0" max="1" step="any" oninput="minimum_score_value.value = 'Score at least ' + Math.round(100 * minimum_score_range.value) + '% using above turnout importance.'">
					<output id="minimum_score_value"><%= "Score at least #{round(100 * (@identity.minimum_reference_approval_score || 0.5))}% using above turnout importance." %></output>

				<button type="submit" class="pure-button pure-button-primary">Update</button>

	</form>
<% else %>

I trust this identity

	<%= render Liquio.HtmlPollView, "cast_vote.html",
		to_path: "/identities/#{@identity.id}",
		poll: %{:id => @identity.trust_metric_poll_id, :choice_type => "probability"},
		own_vote: @own_is_human_vote,
		allow_numeric: false
	%>

Delegation to this identity

	<form method="POST" action="/identities/<%= @identity.id %>/delegations" class="pure-form">
		<input type="hidden" name="_csrf_token" value="<%= get_csrf_token() %>" />

Relative weight

			<input type="number" step="any" min="0.01" name="weight" style="max-width: 150px;"<%= if @delegation do %> value="<%= number_format_simple @delegation.data.weight %>"<% end %> placeholder="1" />

Topics

			<input type="text" name="topics" style="max-width: 400px;"<%= if @delegation != nil and @delegation.data.topics != nil do %> value="<%= @delegation.data.topics |> Enum.join(", ") %>"<% end %> placeholder="All topics" />

		<%= if @delegation do %>
			<button type="submit" class="pure-button pure-button-primary">Update delegation</button>
			<button type="submit" name="weight" value="0" class="pure-button delete-button">Remove delegation</button>
		<% else %>
			<button type="submit" class="pure-button pure-button-primary">Set delegation</button>
		<% end %>
	</form>
<% end %>

username: <%= @identity.username %>

<%= @identity.name %>

<a href="/identities/<%= @identity.id %>/delegations/from">made <%= @num_delegations_from %> <%= ngettext("delegation", "delegations", @num_delegations_from) %>
  |
<a href="/identities/<%= @identity.id %>/delegations/to">receiving <%= @num_delegations_to %> <%= ngettext("delegation", "delegations", @num_delegations_to) %>
  |
<a href="/identities/<%= @identity.id %>/votes">voted on <%= @num_votes %> <%= ngettext("poll", "polls", @num_votes) %>

<%= unless @is_in_trust_metric do %>

NOT IN TRUST METRIC

<% end %>

<%= if @is_me do %>

Share the URL of your identity with others, so they can trust or delegate to you.

Your preferences

	<form method="POST" action="preferences" class="pure-form">
		<input type="hidden" name="_csrf_token" value="<%= get_csrf_token() %>" />

				Trust metric URL

				<input type="url" name="trust_metric_url" value="<%= @identity.trust_metric_url %>" placeholder="<%= @default_trust_metric_url %>" />

				Polls

					<input type="range" name="minimum_voting_power" id="minimum_voting_power_range" value="<%= @identity.minimum_voting_power || 0 %>" min="0" max="1" step="any" oninput="minimum_voting_power_value.value = 'Expecting at least ' + Math.round(100 * minimum_voting_power_range.value) + '% turnout.'" />
					<output id="minimum_voting_power_value"><%= "Expecting at least #{round(100 * (@identity.minimum_voting_power || 0))}% turnout." %></output>

					<input type="range" name="vote_weight_halving_days" id="vote_weight_halving_days_range" value="<%= @identity.vote_weight_halving_days || 1000 %>" min="1" max="1000" step="1" oninput="vote_weight_halving_days_value.value = Math.round(vote_weight_halving_days_range.value) == 1000 ? 'Votes don\'t lose power with time.' : 'Votes will lose half remaining power every ' + Math.round(vote_weight_halving_days_range.value) + ' days.'" />
					<output id="vote_weight_halving_days_value">
						<%= if @identity.vote_weight_halving_days do "Votes will lose half remaining power every #{round(@identity.vote_weight_halving_days)} days." else "Votes don't lose power with time." end %>
					</output>

				Reference approvals

					<input type="range" name="soft_quorum_t" id="soft_quorum_t_range" value="<%= @identity.soft_quorum_t || 0 %>" min="0" max="1" step="any" oninput="soft_quorum_t_value.value = 'Turnout importance set at ' + Math.round(100 * soft_quorum_t_range.value) + '%.'">
					<output id="soft_quorum_t_value"><%= "Turnout importance set at #{round(100 * (@identity.soft_quorum_t || 0))}%." %></output>

					<input type="range" name="minimum_reference_approval_score" id="minimum_score_range" value="<%= @identity.minimum_reference_approval_score || 0 %>" min="0" max="1" step="any" oninput="minimum_score_value.value = 'Score at least ' + Math.round(100 * minimum_score_range.value) + '% using above turnout importance.'">
					<output id="minimum_score_value"><%= "Score at least #{round(100 * (@identity.minimum_reference_approval_score || 0.5))}% using above turnout importance." %></output>

				<button type="submit" class="pure-button pure-button-primary">Update</button>

	</form>
<% else %>

I trust this identity

	<%= render Liquio.HtmlPollView, "cast_vote.html",
		to_path: "/identities/#{@identity.id}",
		poll: %{:id => @identity.trust_metric_poll_id, :choice_type => "probability"},
		own_vote: @own_is_human_vote,
		allow_numeric: false
	%>

Delegation to this identity

	<form method="POST" action="/identities/<%= @identity.id %>/delegations" class="pure-form">
		<input type="hidden" name="_csrf_token" value="<%= get_csrf_token() %>" />

Relative weight

			<input type="number" step="any" min="0.01" name="weight" style="max-width: 150px;"<%= if @delegation do %> value="<%= number_format_simple @delegation.data.weight %>"<% end %> placeholder="1" />

Topics

			<input type="text" name="topics" style="max-width: 400px;"<%= if @delegation != nil and @delegation.data.topics != nil do %> value="<%= @delegation.data.topics |> Enum.join(", ") %>"<% end %> placeholder="All topics" />

		<%= if @delegation do %>
			<button type="submit" class="pure-button pure-button-primary">Update delegation</button>
			<button type="submit" name="weight" value="0" class="pure-button delete-button">Remove delegation</button>
		<% else %>
			<button type="submit" class="pure-button pure-button-primary">Set delegation</button>
		<% end %>
	</form>
<% end %>


Remove header from auth layout

Remove header from auth layout

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Pullhub!</title>
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
  </head>

  <body>
    <div class="container">
      <main role="main">
        <%= render @view_module, @view_template, assigns %>
      </main>
    </div>
    <script src="<%= static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>

<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Pullhub!</title>
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">

          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            Toggle navigation

          </button>
          PullHub

<%= get_flash(@conn, :info) %>

<%= get_flash(@conn, :error) %>

        <%= render @view_module, @view_template, assigns %>


proper homepage link

proper homepage link

<%
  background_color = case @brand do
    "bnc" -> "white"
    "jd" -> "#2a5058"
  end
%>

<header class="header" style="background-color: <%= background_color %>">

    <a href="<%= homepage(@brand) %>">
      <%= if @brand == "jd" do %>

        <%= if @mobile do %>
          <img class="mobile" src="<%= static_path(@conn, "/images/horizontal-logo-jd.png")%>" />
        <% else %>
          <img class="desktop" src="<%= static_path(@conn, "/images/horizontal-logo-jd.png")%>" />
        <% end %>

      <% else %>

        <%= if @mobile do %>
          <img class="mobile" src="<%= static_path(@conn, "/images/horizontal-logo-smaller-bnc.png")%>" />
        <% else %>
          <img class="desktop" src="<%= static_path(@conn, "/images/horizontal-logo-bnc.png")%>" />
        <% end %>

      <% end %>

    <%= if (not @mobile) do %>
      <a class="donate-link" target="_blank" href="https://<%= homepage(@brand) %>/donate?refcode=nowheader">
        Support <%= abbr(@brand) %>

    <% end %>

<%= if @mobile do %>

<% else %>

<% end %>

<%
  background_color = case @brand do
    "bnc" -> "white"
    "jd" -> "#2a5058"
  end
%>

<header class="header" style="background-color: <%= background_color %>">

    <a href="https://<%= homepage(@brand) %>">
      <%= if @brand == "jd" do %>

        <%= if @mobile do %>
          <img class="mobile" src="<%= static_path(@conn, "/images/horizontal-logo-jd.png")%>" />
        <% else %>
          <img class="desktop" src="<%= static_path(@conn, "/images/horizontal-logo-jd.png")%>" />
        <% end %>

      <% else %>

        <%= if @mobile do %>
          <img class="mobile" src="<%= static_path(@conn, "/images/horizontal-logo-smaller-bnc.png")%>" />
        <% else %>
          <img class="desktop" src="<%= static_path(@conn, "/images/horizontal-logo-bnc.png")%>" />
        <% end %>

      <% end %>

    <%= if (not @mobile) do %>
      <a class="donate-link" target="_blank" href="https://<%= homepage(@brand) %>/donate?refcode=nowheader">
        Support <%= abbr(@brand) %>

    <% end %>

<%= if @mobile do %>

<% else %>

<% end %>