boot: bring back pingpeer (#167)

boot: bring back pingpeer (#167)

#!/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=$(greadlink -f "$0")
  else
    SCRIPT=$(my_readlink_f "$0" )
  fi
else
  SCRIPT=$(readlink -f "$0" )
fi

# Parent directory of this script
SCRIPT_DIR=$(dirname "${SCRIPT}")
# Root directory of all releases
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="<%= release_name %>"
# Current version of the release
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 %>"<% 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="$RELEASE_ROOT_DIR/releases/start_erl.data"
# Directory containing the current version of this release
REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN"
# The lib directory for this release
REL_LIB_DIR="$RELEASE_ROOT_DIR/lib"
# Options passed to erl
ERL_OPTS="<%= release.profile.erl_opts %>"
# 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=""

# Pre-start/stop event hook paths
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 determining the version of ERTS available to the release
# This is only ever called if ERTS_VSN is not set
_detect_erts_vsn() {
    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
    "$__erl" -boot start_clean -eval 'Ver = erlang:system_info(version), io:format("~s~n", [Ver]), halt()' -noshell
}

# 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. For setting ERTS_DIR and ROOTDIR
_find_erts_dir() {
    __erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
    if [ -d "$__erts_dir" ]; then
        ERTS_DIR="$__erts_dir";
        ROOTDIR="$RELEASE_ROOT_DIR"
    else
        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
        code="io:format(\"~s\", [code:root_dir()]), halt()."
        __erl_root="$("$__erl" -noshell -eval "$code")"
        ERTS_DIR="$__erl_root/erts-$ERTS_VSN"
        ROOTDIR="$__erl_root"
    fi
}

# 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} occurances 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
}

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

# If ERTS_VSN is not set, detect it
if [ -z "$ERTS_VSN" ]; then
    ERTS_VSN="$(_detect_erts_vsn)"
    echo "$ERTS_VSN $REL_VSN" > "$START_ERL_DATA"
fi

# Allow override of where to read configuration from
# By default it's RELEASE_ROOT_DIR
if [ -z "$RELEASE_CONFIG_DIR" ]; then
    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"

# 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
        VMARGS_PATH="$RELEASE_CONFIG_DIR/vm.args"
    else
        VMARGS_PATH="$REL_DIR/vm.args"
    fi
fi
if [ "$VMARGS_PATH" != "$RELEASE_MUTABLE_DIR/vm.args" ]; then
    echo "#### Generated - edit/create $RELEASE_CONFIG_DIR/vm.args instead." \
        >  "$RELEASE_MUTABLE_DIR/vm.args"
    cat  "$VMARGS_PATH"                              \
        >> "$RELEASE_MUTABLE_DIR/vm.args"
    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
        SYS_CONFIG_PATH="$RELEASE_CONFIG_DIR/sys.config"
    else
        SYS_CONFIG_PATH="$REL_DIR/sys.config"
    fi
fi
if [ "$SYS_CONFIG_PATH" != "$RELEASE_MUTABLE_DIR/sys.config" ]; then
    echo "%% Generated - edit/create $RELEASE_CONFIG_DIR/sys.config instead." \
        >  "$RELEASE_MUTABLE_DIR/sys.config"
    cat  "$SYS_CONFIG_PATH"                              \
        >> "$RELEASE_MUTABLE_DIR/sys.config"
    SYS_CONFIG_PATH=$RELEASE_MUTABLE_DIR/sys.config
fi
if [ $REPLACE_OS_VARS ]; then
    _replace_os_vars "$SYS_CONFIG_PATH"
fi

# Extract the target node name from node.args
# Should be `-sname somename` or `-name somename@somehost`
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
NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')"
# NAME will be either `somename` or `somename@somehost`
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

_find_erts_dir
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"
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

# 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_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"

        "$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_START_HOOKS"
        ## Restart the VM without exiting the process
        if ! nodetool "restart"; then
            exit 1
        fi
        ;;

    reboot)
        _check_cookie
        _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"

        _run_hooks_from_dir "$PRE_UPGRADE_HOOKS"

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

        _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_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_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
        ;;
    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 "$?"
        ;;
    *)
        __command_path="$REL_DIR/commands/$1"
        if [ -f "$__command_path" ]; then
            _check_cookie
            . "$__command_path"
        else
            echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|pingpeer|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|escript|rpc|rpcterms|eval|command <module> <function> <args>}"
            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=$(greadlink -f "$0")
  else
    SCRIPT=$(my_readlink_f "$0" )
  fi
else
  SCRIPT=$(readlink -f "$0" )
fi

# Parent directory of this script
SCRIPT_DIR=$(dirname "${SCRIPT}")
# Root directory of all releases
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="<%= release_name %>"
# Current version of the release
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 %>"<% 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="$RELEASE_ROOT_DIR/releases/start_erl.data"
# Directory containing the current version of this release
REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN"
# The lib directory for this release
REL_LIB_DIR="$RELEASE_ROOT_DIR/lib"
# Options passed to erl
ERL_OPTS="<%= release.profile.erl_opts %>"
# 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=""

# Pre-start/stop event hook paths
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

    "$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 determining the version of ERTS available to the release
# This is only ever called if ERTS_VSN is not set
_detect_erts_vsn() {
    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
    "$__erl" -boot start_clean -eval 'Ver = erlang:system_info(version), io:format("~s~n", [Ver]), halt()' -noshell
}

# 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. For setting ERTS_DIR and ROOTDIR
_find_erts_dir() {
    __erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
    if [ -d "$__erts_dir" ]; then
        ERTS_DIR="$__erts_dir";
        ROOTDIR="$RELEASE_ROOT_DIR"
    else
        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
        code="io:format(\"~s\", [code:root_dir()]), halt()."
        __erl_root="$("$__erl" -noshell -eval "$code")"
        ERTS_DIR="$__erl_root/erts-$ERTS_VSN"
        ROOTDIR="$__erl_root"
    fi
}

# 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} occurances 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
}

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

# If ERTS_VSN is not set, detect it
if [ -z "$ERTS_VSN" ]; then
    ERTS_VSN="$(_detect_erts_vsn)"
    echo "$ERTS_VSN $REL_VSN" > "$START_ERL_DATA"
fi

# Allow override of where to read configuration from
# By default it's RELEASE_ROOT_DIR
if [ -z "$RELEASE_CONFIG_DIR" ]; then
    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"

# 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
        VMARGS_PATH="$RELEASE_CONFIG_DIR/vm.args"
    else
        VMARGS_PATH="$REL_DIR/vm.args"
    fi
fi
if [ "$VMARGS_PATH" != "$RELEASE_MUTABLE_DIR/vm.args" ]; then
    echo "#### Generated - edit/create $RELEASE_CONFIG_DIR/vm.args instead." \
        >  "$RELEASE_MUTABLE_DIR/vm.args"
    cat  "$VMARGS_PATH"                              \
        >> "$RELEASE_MUTABLE_DIR/vm.args"
    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
        SYS_CONFIG_PATH="$RELEASE_CONFIG_DIR/sys.config"
    else
        SYS_CONFIG_PATH="$REL_DIR/sys.config"
    fi
fi
if [ "$SYS_CONFIG_PATH" != "$RELEASE_MUTABLE_DIR/sys.config" ]; then
    echo "%% Generated - edit/create $RELEASE_CONFIG_DIR/sys.config instead." \
        >  "$RELEASE_MUTABLE_DIR/sys.config"
    cat  "$SYS_CONFIG_PATH"                              \
        >> "$RELEASE_MUTABLE_DIR/sys.config"
    SYS_CONFIG_PATH=$RELEASE_MUTABLE_DIR/sys.config
fi
if [ $REPLACE_OS_VARS ]; then
    _replace_os_vars "$SYS_CONFIG_PATH"
fi

# Extract the target node name from node.args
# Should be `-sname somename` or `-name somename@somehost`
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
NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')"
# NAME will be either `somename` or `somename@somehost`
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

_find_erts_dir
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"
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

# 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_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"

        "$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_START_HOOKS"
        ## Restart the VM without exiting the process
        if ! nodetool "restart"; then
            exit 1
        fi
        ;;

    reboot)
        _check_cookie
        _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
        ;;

    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"

        _run_hooks_from_dir "$PRE_UPGRADE_HOOKS"

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

        _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_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_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
        ;;
    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 "$?"
        ;;
    *)
        __command_path="$REL_DIR/commands/$1"
        if [ -f "$__command_path" ]; then
            _check_cookie
            . "$__command_path"
        else
            echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|escript|rpc|rpcterms|eval|command <module> <function> <args>}"
            exit 1
        fi
        ;;
esac

exit 0


update other link

update other link

Talk to us

Ask your question in the chat box and Jo or Gina will reply as soon as they are free.

        <%= if @conn.assigns.version == "talk" do %>
          Leave your email address if you don't get a response straight away and we'll let you know when we're free.
        <% else %>
          Leave your email address and a message so we can get back to you and let you know when we're online to answer your questions.
        <% end %>

To speak to us again and carry on your conversation, make a not of the code below:

Your Code: <%= @user.uuid %>

      <%= if @conn.assigns.version == "talk" do %>

If you want to speak to us on the phone, arrange a time that is convenient for you.

        <%= link to: user_callback_path(@conn, :show, @user)  do %>
          <button class="<%= red_button() %>">Arrange a call</button>
        <% end %>
      <% end %>

      <%= if @conn.assigns.version == "talk" do %>
        <%= link to: page_path(@conn, :practitioners) do %>
          <button class="<%= "#{red_button()} mb2" %>">Meet our staff</button>
        <% end %>
      <% end %>

      <%= if @conn.assigns.version == "talk" do %>

We are non-judgemental, inclusive, friendly and approachable.

You can ask us any parenting or family question and we will do our best to make you feel comfortable, understood and helped.

It can be about development, behaviour, feeding, family life, wellbeing, understanding your child, sleeping etc. We really don't mind what you ask us about, we are here to help you.

So that we can best support you, please provide some context about your question.

For example, if you need advice around your child's sleeping, let us know their age and bedtime routine. This means we can give you advice really specific to you and your situation.

You might also find it useful to read some general parenting information written by Action for Children practitioners.

      <% else %>

We are friendly, don’t judge, will help everyone and are easy to talk to.

You can ask us any parent, relationship or family question and we will do our best to make you feel comfortable, understood and helped.

It can be about your child's behaviour, understanding your child, arguments, your relationship with your partner/the other parent, child care, family life, wellbeing, looking for work, etc. We really don't mind what you ask us about. We are here to help you.

So that we can help you, please give us as much information about your question as you can.

For example, if your child’s behaviour has recently changed, tell us their age and if there have been any changes in your family. This means we can give you advice specific to you and your situation.

You might also find it useful to read some general parenting information written by Action for Children practitioners.
      <% end %>


successful repeating easy volunteer adds

 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 %>
<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>


Created new student show page

Created new student show page

          <%= Enum.join([ @student.name, @student.family_name ], " ") %>

        <%= if @conn.assigns.current_user.role == "Coordinator" do %>

            <%= link "Edit", to: student_path(@conn, :edit, @student),
                             class: "mdl-button mdl-js-button mdl-button--raised"
            %>

        <% end %>

        <%= CoursePlanner.SharedView.card do %>
          <%= CoursePlanner.SharedView.card_content vpadding: true do %>

                <img
                  src="<%= CoursePlanner.SharedView.get_gravatar_url(@student.email, 500) %>"
                  class="profile-picture"
                >

Name

                    <%= @student.name %> <%= @student.family_name %>

E-mail

                    <%= @student.email %>

Phone Number

                    <%= @student.phone_number %>

Student ID

                    <%= @student.student_id %>

Participation Type

                    <%= @student.participation_type %>

Comments

                    <%= @student.comments %>

          <% end %>
        <% end %>

            Courses

        <%= CoursePlanner.SharedView.course_list student_courses(@student.id) %>

Show student

     First Name:
    <%= @student.name %>

     Family Name:
    <%= @student.family_name %>

     Nickname:
    <%= @student.nickname %>

     Email:
    <%= @student.email %>

     Student ID:
    <%= @student.student_id %>

     Participation Type:
    <%= @student.participation_type %>

     Comments:
    <%= @student.comments %>

       Term
       Course
       Number of sessions
       Action

  <%= for offered_course <- student_courses(@student.id) do %>

          <%= link "#{offered_course.term.name}", to: term_path(@conn, :show, offered_course.term), class: "btn btn-default btn-xs" %>

          <%= link "#{offered_course.course.name}", to: course_path(@conn, :show, offered_course.course), class: "btn btn-default btn-xs" %>

        <%= offered_course.number_of_sessions %>

          <%= link "Show", to: offered_course_path(@conn, :show, offered_course), class: "btn btn-default btn-xs" %>

  <% end %>

<%= link "Edit", to: student_path(@conn, :edit, @student) %>
<%= link "Back", to: student_path(@conn, :index) %>


Better page title

Better page title

<!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>Cave mapping software</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> <!-- /container -->
    <script src="<%= static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>

<!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>Hello Cavemapper!</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> <!-- /container -->
    <script src="<%= static_path(@conn, "/js/app.js") %>"></script>
  </body>
</html>


Fix pagination

Fix pagination

  <%= if @page_number > 1 do %>
    <%= link(gettext("Previous"),
      to: offer_page_path(@conn, :index, @page_number - 1),
      class: "item item-older") %>
  <% else %>
    <%= gettext("Previous") %>
  <% end %>
  <%= if @page_number < @total_pages do %>
    <%= link(gettext("Next"),
      to: offer_page_path(@conn, :index, @page_number + 1),
      class: "item item-newer") %>
  <% else %>
    <%= gettext("Next") %>
  <% end %>

  <%= if @page_number > 1 do %>
    <%= link(gettext("Previous"),
      to: offer_page_path(@conn, :index, page: @page_number - 1),
      class: "item item-older") %>
  <% else %>
    <%= gettext("Previous") %>
  <% end %>
  <%= if @page_number < @total_pages do %>
    <%= link(gettext("Next"),
      to: offer_page_path(@conn, :index, page: @page_number + 1),
      class: "item item-newer") %>
  <% else %>
    <%= gettext("Next") %>
  <% end %>


More semantic markup for the different sections

<!DOCTYPE html>

    <meta http-equiv="content-type" content="text/html; charset=utf8">

Comparison

    <%= for {name, _} <- suite.run_times do %>

 <%= name %>

 Run time Histogram

          <div class="sorted-run-times" data-job-name="<%= name %>">

 Raw run times

          <div class="raw-run-times" data-job-name="<%= name %>">

    <% end %>

<!DOCTYPE html>

    <meta http-equiv="content-type" content="text/html; charset=utf8">

    <%= for {name, _} <- suite.run_times do %>
      <div class="sorted-run-times" data-job-name="<%= name %>">

      <div class="raw-run-times" data-job-name="<%= name %>">

    <% end %>


removes the wrong link

removes the wrong link

      Courses

    <%= if @conn.assigns.current_user.role == "Coordinator" do %>

        <%= link "New course", to: offered_course_path(@conn, :new), class: "mdl-button mdl-js-button mdl-button--raised" %>

    <% end %>

  <%= for term <- @terms do %>

            <%= term.name %>

            Course type
            Number of sessions

          <%= Enum.with_index(term.offered_courses) |> Enum.map(fn {offered_course,index} -> %>

                <%= offered_course.course.name %>

                <%= offered_course.number_of_sessions %>

                <button id="tr_menu_<%= offered_course.id %>"
                        class="mdl-button mdl-js-button mdl-button--icon"
                >
                  more_vert
                </button>
                <ul
                  class="
                    mdl-menu mdl-js-menu
                    <%=
                      if index > 10 and index > length(term.offered_courses)-4 do
                        'mdl-menu--top-right'
                      else
                        'mdl-menu--bottom-right'
                      end
                    %>
                  "
                  for="tr_menu_<%= offered_course.id %>"
                >

                    <%= link "Show", to: offered_course_path(@conn, :show, offered_course) %>

                  <%= if @conn.assigns.current_user.role == "Coordinator" do %>

                      <%= link "Edit", to: offered_course_path(@conn, :edit, offered_course) %>

                      <%= link "Delete", to: offered_course_path(@conn, :delete, offered_course), method: :delete,
                      data: [confirm: """
                      Are you sure?
                      All of its attached classes and relevant attendances will be removed.
                      """] %>

                  <% end %>
                  <%= if @conn.assigns.current_user.role == "Teacher" do %>

                      <%= link "Edit", to: offered_course_path(@conn, :edit, offered_course) %>

                  <% end %>

          <% end) %>

  <% end %>

      Courses

    <%= if @conn.assigns.current_user.role == "Coordinator" do %>

        <%= link "New course", to: offered_course_path(@conn, :new), class: "mdl-button mdl-js-button mdl-button--raised" %>

    <% end %>

  <%= for term <- @terms do %>

            <%= term.name %>

            Course type
            Number of sessions

          <%= Enum.with_index(term.offered_courses) |> Enum.map(fn {offered_course,index} -> %>

                <%= offered_course.course.name %>

                <%= offered_course.number_of_sessions %>

                <button id="tr_menu_<%= offered_course.id %>"
                        class="mdl-button mdl-js-button mdl-button--icon"
                >
                  more_vert
                </button>
                <ul
                  class="
                    mdl-menu mdl-js-menu
                    <%=
                      if index > 10 and index > length(@offered_courses)-4 do
                        'mdl-menu--top-right'
                      else
                        'mdl-menu--bottom-right'
                      end
                    %>
                  "
                  for="tr_menu_<%= offered_course.id %>"
                >

                    <%= link "Show", to: offered_course_path(@conn, :show, offered_course) %>

                  <%= if @conn.assigns.current_user.role == "Coordinator" do %>

                      <%= link "Edit", to: offered_course_path(@conn, :edit, offered_course) %>

                      <%= link "Delete", to: offered_course_path(@conn, :delete, offered_course), method: :delete,
                      data: [confirm: """
                      Are you sure?
                      All of its attached classes and relevant attendances will be removed.
                      """] %>

                  <% end %>
                  <%= if @conn.assigns.current_user.role == "Teacher" do %>

                      <%= link "Edit", to: offered_course_path(@conn, :edit, offered_course) %>

                  <% end %>

          <% end) %>

  <% end %>


no double https

no double https

<%
  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="<%= 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="<%= 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 %>


Fix root SVG element sizing

Fix root SVG element sizing

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="<%= (@cols + 2) * 8.64556962 %>" height="<%= (@rows + 1) * 14 * 1.4 %>" font-family="Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols'" font-size="14px">
  <style>
   <%= render "_svg_theme_#{@theme_name}.css" %>
   <%= render "_svg_256_colors.css" %>
   .br { font-weight: bold }
   .it { font-style: italic }
   .un { text-decoration: underline }
  </style>

  <rect width="100%" height="100%" class="default-bg-fill"></rect>

  <svg x="<%= percent(1.0 * 100 / (@cols + 2)) %>" y="<%= percent(0.5 * 100 / (@rows + 1)) %>" class="default-text-fill">
    <g style="shape-rendering: optimizeSpeed">
    <%= for chunks <- @chunk_lines do %><%= for chunk <- chunks do %><%= if c = svg_rect_class(chunk.attrs) do %><rect x="<%= percent(100 * chunk.x / (@cols + 2)) %>" y="<%= percent(100 * chunk.y / (@rows + 1)) %>" width="<%= percent(100 * chunk.width / (@cols + 2)) %>" height="<%= percent(102 / (@rows + 1)) %>" class="<%= c %>"></rect>
<% end %><% end %><% end %>
    </g>

    <text>
      <%= for chunks <- @char_lines do %><%= for chunk <- chunks do %><%= if String.trim(chunk.text) != "" do %><tspan dy="1.0em" x="<%= percent(100 * chunk.x / (@cols + 2)) %>" y="<%= percent(100 * chunk.y / (@rows + 1)) %>"<%= if c = svg_text_class(chunk.attrs) do %> class="<%= c %>"<% end %><%= if s = svg_style(chunk.attrs) do %> style="<%= s %>"<% end %>><%= chunk.text %></tspan>
<% end %><% end %><% end %>
    </text>

    <g transform="translate(-50 -50)">
      <svg x="50%" y="50%" width="100" height="100">
        <%= render "_logo.svg" %>
      </svg>
    </g>
  </svg>
</svg>

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="width: <%= @cols + 2 %>ch; height: <%= (@rows + 1) * 1.4 %>em" font-family="Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols'" font-size="14px">
  <style>
   <%= render "_svg_theme_#{@theme_name}.css" %>
   <%= render "_svg_256_colors.css" %>
   .br { font-weight: bold }
   .it { font-style: italic }
   .un { text-decoration: underline }
  </style>

  <rect width="100%" height="100%" class="default-bg-fill"></rect>

  <svg x="<%= percent(1.0 * 100 / (@cols + 2)) %>" y="<%= percent(0.5 * 100 / (@rows + 1)) %>" class="default-text-fill">
    <g style="shape-rendering: optimizeSpeed">
    <%= for chunks <- @chunk_lines do %><%= for chunk <- chunks do %><%= if c = svg_rect_class(chunk.attrs) do %><rect x="<%= percent(100 * chunk.x / (@cols + 2)) %>" y="<%= percent(100 * chunk.y / (@rows + 1)) %>" width="<%= percent(100 * chunk.width / (@cols + 2)) %>" height="<%= percent(102 / (@rows + 1)) %>" class="<%= c %>"></rect>
<% end %><% end %><% end %>
    </g>

    <text>
      <%= for chunks <- @char_lines do %><%= for chunk <- chunks do %><%= if String.trim(chunk.text) != "" do %><tspan dy="1.0em" x="<%= percent(100 * chunk.x / (@cols + 2)) %>" y="<%= percent(100 * chunk.y / (@rows + 1)) %>"<%= if c = svg_text_class(chunk.attrs) do %> class="<%= c %>"<% end %><%= if s = svg_style(chunk.attrs) do %> style="<%= s %>"<% end %>><%= chunk.text %></tspan>
<% end %><% end %><% end %>
    </text>

    <g transform="translate(-50 -50)">
      <svg x="50%" y="50%" width="100" height="100">
        <%= render "_logo.svg" %>
      </svg>
    </g>
  </svg>
</svg>


Revisions to layout of FeedSource show page

Feed Source: <%= @feed_source.feed_name %>

<%= link @feed_source.feed_url, to: @feed_source.feed_url, target: "_blank" %>

<%= raw @feed_source.summary %>

Some attributes retrieved from feed.

      Title
      <%= @feed_source.title %>

      Subtitle
      <%= @feed_source.subtitle %>

      Schedule
      <%= @feed_source.schedule %>

      Last Retrieved
      <%= @feed_source.last_retrieved %>

      Author
      <%= @feed_source.author %>

      Image
      <%= if !is_nil(@feed_source.image), do: link(@feed_source.image, to: @feed_source.image, target: "_blank") %>

      Link
      <%= if !is_nil(@feed_source.link), do: link(@feed_source.link, to: @feed_source.link, target: "_blank") %>

      Language
      <%= @feed_source.language %>

<%= link "Back", to: feed_source_path(@conn, :index) %>
<%= link "Edit", to: feed_source_path(@conn, :edit, @feed_source) %>

<%= @feed_source.feed_name %>

<%= link @feed_source.feed_url, to: @feed_source.feed_url, target: "_blank" %>

Some attributes retrieved from feed.

      Title
      <%= @feed_source.title %>

      Subtitle
      <%= @feed_source.subtitle %>

      Summary
      <%= @feed_source.summary %>

      Schedule
      <%= @feed_source.schedule %>

      Last Retrieved
      <%= @feed_source.last_retrieved %>

      Author
      <%= @feed_source.author %>

      Image
      <%= if !is_nil(@feed_source.image), do: link(@feed_source.image, to: @feed_source.image) %>

      Link
      <%= if !is_nil(@feed_source.link), do: link(@feed_source.link, to: @feed_source.link) %>

      Language
      <%= @feed_source.language %>

<%= link "Back", to: feed_source_path(@conn, :index) %>
<%= link "Edit", to: feed_source_path(@conn, :edit, @feed_source) %>


Improved search english text

Improved search english text

  <%= render "form.html", conn: @conn, changeset: @changeset,
                            action: search_query_path(@conn, :create) %>

	<%= if(@conn.assigns[:query]) do %>
  <%= gen_breadcrumbs([
    {gettext("Search"), search_query_path(@conn, :new)},
    gettext("Results")]) %>
  <% else %>
  <%= gen_breadcrumbs([
    gettext("Search")]) %>
  <% end %>

  <%= unless(@conn.assigns[:query]) do %>

<%= gettext "Search Tips" %>

        <%= gettext "You can search for a name, email, or skill." %>

        <%= gettext "Our search will try to match similar names to your search, so don't worry about spelling." %>

  <% end %>

    <%= render Vutuv.SharedView, "_ad.html" %>

<%= if @conn.assigns[:user_results] do %>

  <%= if(@conn.params["skills"] == "true") do %>
  	<%= if Enum.count(@user_results) > 0 do %>

Show user results

	  <% end %>
	<% else %>
		<%= if Enum.count(@skill_results) > 0 do %>

Show skill results

	  <% end %>
	<% end %>

	<%= if(@conn.params["skills"] == "true") do %>
    <%= render Vutuv.SkillView, "card_list.html", conn: @conn, skills: @skill_results, current_user: @current_user, current_user_id: @current_user_id, work_string_length: 45 %>
  <% else %>
    <%= render Vutuv.UserView, "card_list.html", conn: @conn, users: @user_results, current_user: @current_user, current_user_id: @current_user_id, work_string_length: 45 %>
  <% end %>
  <%= if Enum.count(@skill_results) == 0 and Enum.count(@user_results) == 0 do %>

  		<%= gettext "No results" %>

  <% end %>

<% end %>

  <%= render "form.html", conn: @conn, changeset: @changeset,
                            action: search_query_path(@conn, :create) %>

	<%= if(@conn.assigns[:query]) do %>
  <%= gen_breadcrumbs([
    {gettext("Search"), search_query_path(@conn, :new)},
    gettext("Results")]) %>
  <% else %>
  <%= gen_breadcrumbs([
    gettext("Search")]) %>
  <% end %>

  <%= unless(@conn.assigns[:query]) do %>

<%= gettext "Search How-To" %>

        <%= gettext "Please enter a name of a person, an email address or a skill." %>

        <%= gettext "The search for first and last names is fuzzy." %>

  <% end %>

    <%= render Vutuv.SharedView, "_ad.html" %>

<%= if @conn.assigns[:user_results] do %>

  <%= if(@conn.params["skills"] == "true") do %>
  	<%= if Enum.count(@user_results) > 0 do %>

Show user results

	  <% end %>
	<% else %>
		<%= if Enum.count(@skill_results) > 0 do %>

Show skill results

	  <% end %>
	<% end %>

	<%= if(@conn.params["skills"] == "true") do %>
    <%= render Vutuv.SkillView, "card_list.html", conn: @conn, skills: @skill_results, current_user: @current_user, current_user_id: @current_user_id, work_string_length: 45 %>
  <% else %>
    <%= render Vutuv.UserView, "card_list.html", conn: @conn, users: @user_results, current_user: @current_user, current_user_id: @current_user_id, work_string_length: 45 %>
  <% end %>

<% end %>


Change Urls to static references

Change Urls to static references

          <img class='logo' src="<%= static_url(@conn, "/images/michelada-white-logo.svg") %>" />
          <img class='text' src="<%= static_url(@conn, "/images/michelada-white-text.svg") %>" />

      <s class='bar'></s>
      <s class='bar'></s>

Services

<%= link("Blog", to: page_path(@conn, :index)) %>

About Us

Get in Touch


Alias class in rtf eex view

Alias class in rtf eex view

\par \pard\plain \s24\b\langfe255\afs30\lang255\ab\loch\f3\fs30\lang255{\rtlch \ltrch\loch
<% alias ClassList.DirectoryView %>
<%= @student.first_name %> <%= @student.last_name %>}
<%= if @student.bus.should_display do %>
\par \pard\plain \s25\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= @student.bus.name %>}
<% end %>
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs21\rtlch \ltrch\loch\fs21\loch\f3
}
<%= for {parent_list, address} <- DirectoryView.group_parents(@student) do %>
<%= for parent <- parent_list do %>
\par \pard\plain \s26\b\langfe255\afs22\lang255\ab\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= parent.first_name %> <%= parent.last_name %>}
<%= if DirectoryView.not_empty(parent.email) do %>
\par \pard\plain \s27\li58\ri0\lin58\rin0\fi0\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= parent.email %>}
<% end %>
<%= if DirectoryView.not_empty(parent.mobile_phone) do %>
\par \pard\plain \s27\li58\ri0\lin58\rin0\fi0\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
Cell: <%= parent.mobile_phone %>}
<% end %>
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs21\rtlch \ltrch\loch\fs21\loch\f3
}
<% end %>

<%= if DirectoryView.not_empty(address.address1) do %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= address.address1 %>}
<% end %>
<%= if DirectoryView.not_empty(address.address2) do %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= address.address2 %>}
<% end %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= if DirectoryView.not_empty(address.city) do %><%= address.city %><% end %>, <%= if DirectoryView.not_empty(address.state) do %><%= address.state %><% end %>  <%= if DirectoryView.not_empty(address.zip) do %><%= address.zip %><% end %>}
<%= if DirectoryView.not_empty(address.phone) do %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
Home Phone: <%= address.phone %>}
<% end %>
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs22\rtlch \ltrch\loch\fs22\loch\f3
}

<% end %>

<%= if DirectoryView.not_empty(@student.notes) do %>
\par \pard\plain \s29\cf3\i\langfe255\afs22\lang255\ai\loch\f3\fs22\lang255{\rtlch \ltrch\loch
*<%= @student.notes %>}
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs21\rtlch \ltrch\loch\fs21\loch\f3
}
<% end %>

\par \pard\plain \s24\b\langfe255\afs30\lang255\ab\loch\f3\fs30\lang255{\rtlch \ltrch\loch
<%= @student.first_name %> <%= @student.last_name %>}
<%= if @student.bus.should_display do %>
\par \pard\plain \s25\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= @student.bus.name %>}
<% end %>
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs21\rtlch \ltrch\loch\fs21\loch\f3
}
<%= for {parent_list, address} <- ClassList.DirectoryView.group_parents(@student) do %>
<%= for parent <- parent_list do %>
\par \pard\plain \s26\b\langfe255\afs22\lang255\ab\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= parent.first_name %> <%= parent.last_name %>}
<%= if ClassList.DirectoryView.not_empty(parent.email) do %>
\par \pard\plain \s27\li58\ri0\lin58\rin0\fi0\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= parent.email %>}
<% end %>
<%= if ClassList.DirectoryView.not_empty(parent.mobile_phone) do %>
\par \pard\plain \s27\li58\ri0\lin58\rin0\fi0\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
Cell: <%= parent.mobile_phone %>}
<% end %>
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs21\rtlch \ltrch\loch\fs21\loch\f3
}
<% end %>

<%= if ClassList.DirectoryView.not_empty(address.address1) do %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= address.address1 %>}
<% end %>
<%= if ClassList.DirectoryView.not_empty(address.address2) do %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= address.address2 %>}
<% end %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
<%= if ClassList.DirectoryView.not_empty(address.city) do %><%= address.city %><% end %>, <%= if ClassList.DirectoryView.not_empty(address.state) do %><%= address.state %><% end %>  <%= if ClassList.DirectoryView.not_empty(address.zip) do %><%= address.zip %><% end %>}
<%= if ClassList.DirectoryView.not_empty(address.phone) do %>
\par \pard\plain \s28\langfe255\afs22\lang255\loch\f3\fs22\lang255{\rtlch \ltrch\loch
Home Phone: <%= address.phone %>}
<% end %>
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs22\rtlch \ltrch\loch\fs22\loch\f3
}

<% end %>

<%= if ClassList.DirectoryView.not_empty(@student.notes) do %>
\par \pard\plain \s29\cf3\i\langfe255\afs22\lang255\ai\loch\f3\fs22\lang255{\rtlch \ltrch\loch
*<%= @student.notes %>}
\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\aspalpha\ltrpar\langfe255\lang255\cf0\kerning1\hich\af4\dbch\af6\afs24\lang255\loch\f0\fs24{\afs21\rtlch \ltrch\loch\fs21\loch\f3
}
<% end %>


Have detail graphs sorted correctly

Have detail graphs sorted correctly

<!DOCTYPE html>

    <title>Benchee Report</title>
    <meta charset="utf-8">
    <meta http-equiv="content-type" content="text/html; charset=utf8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="assets/stylesheets/benchee.css">

benchee report

      Elixir <%= suite.system.elixir%>, Erlang <%= suite.system.erlang %>

Comparison

Data Table

              Name
              Iterations per Second
              Average
              Deviation
              median
              minimum
              maximum
              Sample size

            <%= for {name, statistics} <- suite.statistics do %>

                <a href="#<%= name %>"><%= name %>
                <%= format_count statistics.ips %>
                <%= format_duration statistics.average %>
                <%= format_percent statistics.std_dev_ratio %>
                <%= format_duration statistics.median %>
                <%= statistics.minimum %>
                <%= statistics.maximum %>
                <%= statistics.sample_size %>

            <% end %>

        <div id="ips-comparison" class="<%= max_width_class(suite.job_count) %> plot">

        <div id="box-plot" class="<%= max_width_class(suite.job_count) %> plot">

    <%= for {name, _} <- suite.statistics do %>

<a name="<%= name %>"><%= name %>

          <div class="sorted-run-times plot" data-job-name="<%= name %>">

          <div class="raw-run-times plot" data-job-name="<%= name %>">

    <% end %>

<!DOCTYPE html>

    <title>Benchee Report</title>
    <meta charset="utf-8">
    <meta http-equiv="content-type" content="text/html; charset=utf8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="assets/stylesheets/benchee.css">

benchee report

      Elixir <%= suite.system.elixir%>, Erlang <%= suite.system.erlang %>

Comparison

Data Table

              Name
              Iterations per Second
              Average
              Deviation
              median
              minimum
              maximum
              Sample size

            <%= for {name, statistics} <- suite.statistics do %>

                <a href="#<%= name %>"><%= name %>
                <%= format_count statistics.ips %>
                <%= format_duration statistics.average %>
                <%= format_percent statistics.std_dev_ratio %>
                <%= format_duration statistics.median %>
                <%= statistics.minimum %>
                <%= statistics.maximum %>
                <%= statistics.sample_size %>

            <% end %>

        <div id="ips-comparison" class="<%= max_width_class(suite.job_count) %> plot">

        <div id="box-plot" class="<%= max_width_class(suite.job_count) %> plot">

    <%= for {name, _} <- suite.run_times do %>

<a name="<%= name %>"><%= name %>

          <div class="sorted-run-times plot" data-job-name="<%= name %>">

          <div class="raw-run-times plot" data-job-name="<%= name %>">

    <% end %>


Clear the activities list when the date changes.

Add Activity

    <%= form_for @changeset, activity_feed_path(@conn, :create), fn f -> %>

          Date
          <%= text_input f, :date, value: @date, type: "date" %>

          Activity

            <input type="hidden" name="record[activity_id]" />

Select an activity

              <%= for activity <- @activities do %>
                <div class="item" data-value="<%= activity.id %>" data-duration="<%= activity.default_duration %>"><%= activity.name %>

              <% end %>

          Duration
          <%= number_input f, :duration, value: 1, min: 0, step: "any" %>

          Notes
          <%= textarea f, :note, rows: 2 %>

      <button type="submit" class="ui primary basic right floated button">Add</button>

    <% end %>

      <%= for item <- @records do %>
          <%= render "event.html", e: item %>
      <% end %>


Copy: prefer extended dashes in copy

Copy: prefer extended dashes in copy

Frequently Asked Questions

What's a retro?

'Retro' is short for retrospective. Retrospectives are used by software teams to reflect on their recent work, with the aim of identifying where they can improve, and—more importantly—of generating action items that will help them make those improvements.

How much does RemoteRetro cost?

Zero! Zilch! Nada! It's FREE.

Who can use RemoteRetro?

Anyone with a Google account of any kind can enter a retrospective!

What's RemoteRetro's privacy policy?

Read it!

My team is entirely colocated. Should we use RemoteRetro?

That depends. If you have a large TV on which to show the board, RemoteRetro will expedite the idea submission, grouping, and voting process, but be mindful that once you get to the discussion/action items stage, non-facilitators should put their laptops away to maximize face-to-face communication.

Where can I learn about planned features and updates?

Our backlog is public, and resides in GitHub issues, which can be viewed in priority order via the wonderful ZenHub Chrome extension.

How many people should participate in a retro?

Ideally, a retrospective will contain no more than 10 people. Exceed 10, and participants will check out because they feel they can go unnoticed. If you can, keep the numbers low!

How can I submit feedback on my experience?

Bugs and feature requests can be filed via GitHub issues at https://github.com/stride-nyc/remote_retro/issues/new or via email at remote_retro@stridenyc.com

  <%= if !assigns[:current_user] do %>

    <%= render("sign_in_with_google_to_get_started.html") %>
  <% end %>

Frequently Asked Questions

What's a retro?

'Retro' is short for retrospective. Retrospectives are used by software teams to reflect on their recent work, with the aim of identifying where they can improve, and--more importantly--of generating action items that will help them make those improvements.

How much does RemoteRetro cost?

Zero! Zilch! Nada! It's FREE.

Who can use RemoteRetro?

Anyone with a Google account of any kind can enter a retrospective!

What's RemoteRetro's privacy policy?

Read it!

My team is entirely colocated. Should we use RemoteRetro?

That depends. If you have a large TV on which to show the board, RemoteRetro will expedite the idea submission, grouping, and voting process, but be mindful that once you get to the discussion/action items stage, non-facilitators should put their laptops away to maximize face-to-face communication.

Where can I learn about planned features and updates?

Our backlog is public, and resides in GitHub issues, which can be viewed in priority order via the wonderful ZenHub Chrome extension.

How many people should participate in a retro?

Ideally, a retrospective will contain no more than 10 people. Exceed 10, and participants will check out because they feel they can go unnoticed. If you can, keep the numbers low!

How can I submit feedback on my experience?

Bugs and feature requests can be filed via GitHub issues at https://github.com/stride-nyc/remote_retro/issues/new or via email at remote_retro@stridenyc.com

  <%= if !assigns[:current_user] do %>

    <%= render("sign_in_with_google_to_get_started.html") %>
  <% end %>


feat(admin): add object, object_type to menu

<!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>Admin</title>
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/admin.css") %>">

      Lyn Admin

        <li class="nav-item <%= active_class(@conn, admin_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= admin_path(@conn, :index) %>">Home (current)

        <li class="nav-item <%= active_class(@conn, object_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= object_path(@conn, :index) %>">Objects (current)

        <li class="nav-item <%= active_class(@conn, object_type_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= object_type_path(@conn, :index) %>">Object Types (current)

        <li class="nav-item <%= active_class(@conn, language_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= language_path(@conn, :index) %>">Languages (current)

        <li class="nav-item <%= active_class(@conn, domain_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= domain_path(@conn, :index) %>">Domains (current)

        <li class="nav-item <%= active_class(@conn, site_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= site_path(@conn, :index) %>">Sites (current)

      <form class="form-inline pull-xs-right">
        <input class="form-control" type="text" placeholder="Search">
        <button class="btn btn-success-outline" type="submit">Search</button>
      </form>

          sidebar

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

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

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

<!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>Admin</title>
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/admin.css") %>">

      Lyn Admin

        <li class="nav-item <%= active_class(@conn, admin_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= admin_path(@conn, :index) %>">Home (current)

        <li class="nav-item <%= active_class(@conn, language_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= language_path(@conn, :index) %>">Languages (current)

        <li class="nav-item <%= active_class(@conn, domain_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= domain_path(@conn, :index) %>">Domains (current)

        <li class="nav-item <%= active_class(@conn, site_path(@conn, :index)) %>">
          <a class="nav-link" href="<%= site_path(@conn, :index) %>">Sites (current)

      <form class="form-inline pull-xs-right">
        <input class="form-control" type="text" placeholder="Search">
        <button class="btn btn-success-outline" type="submit">Search</button>
      </form>

          sidebar

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

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

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


Fix URL to Distillery docs

Fix URL to Distillery docs

use Mix.Releases.Config,
    # This sets the default release built by `mix release`
    default_release: :default,
    # This sets the default environment used by `mix release`
    default_environment: :dev
<%= unless no_docs do %>
# For a full list of config options for both releases
# and environments, visit https://hexdocs.pm/distillery/config/distillery.html
<% end %>
<%= unless no_docs do %>
# You may define one or more environments in this file,
# an environment's settings will override those of a release
# when building in that environment, this combination of release
# and environment configuration is called a profile
<% end %>
environment :dev do
  set cookie: <%= inspect(cookie) %>
end

environment :prod do
  set cookie: <%= inspect(cookie) %>
end
<%= unless no_docs do %>
# You may define one or more releases in this file.
# If you have not set a default release, or selected one
# when running `mix release`, the first release in the file
# will be used by default<% end %>
<%= for release <- releases do %><%= if Keyword.get(release, :is_umbrella) do %>
release :<%= Keyword.get(release, :release_name) %> do
  set version: "0.1.0"
  set applications: [
<%= Enum.map(Keyword.get(release, :release_applications), fn {app, start_type} ->
    "    #{app}: :#{start_type}"
    end) |> Enum.join(",\n") %>
  ]
  plugin Nerves
  plugin Shoehorn
end<% else %>
release :<%= Keyword.get(release, :release_name) %> do
  set version: current_version(:<%= Keyword.get(release, :release_name)%>)
  plugin Nerves
  plugin Shoehorn
end<% end %>
<% end %>

use Mix.Releases.Config,
    # This sets the default release built by `mix release`
    default_release: :default,
    # This sets the default environment used by `mix release`
    default_environment: :dev
<%= unless no_docs do %>
# For a full list of config options for both releases
# and environments, visit https://hexdocs.pm/distillery/configuration.html
<% end %>
<%= unless no_docs do %>
# You may define one or more environments in this file,
# an environment's settings will override those of a release
# when building in that environment, this combination of release
# and environment configuration is called a profile
<% end %>
environment :dev do
  set cookie: <%= inspect(cookie) %>
end

environment :prod do
  set cookie: <%= inspect(cookie) %>
end
<%= unless no_docs do %>
# You may define one or more releases in this file.
# If you have not set a default release, or selected one
# when running `mix release`, the first release in the file
# will be used by default<% end %>
<%= for release <- releases do %><%= if Keyword.get(release, :is_umbrella) do %>
release :<%= Keyword.get(release, :release_name) %> do
  set version: "0.1.0"
  set applications: [
<%= Enum.map(Keyword.get(release, :release_applications), fn {app, start_type} ->
    "    #{app}: :#{start_type}"
    end) |> Enum.join(",\n") %>
  ]
  plugin Nerves
  plugin Shoehorn
end<% else %>
release :<%= Keyword.get(release, :release_name) %> do
  set version: current_version(:<%= Keyword.get(release, :release_name)%>)
  plugin Nerves
  plugin Shoehorn
end<% end %>
<% end %>


Add link back to games

Add link back to games

<%= link "Back to games", to: game_path(@conn, :index) %>

<div id="app" data-game-id="<%= @game.id %>">


improve sign up form and add the first line of defence

<%= form_for @changeset, @action, fn f -> %>
  <%= if @changeset.action do %>

Oops, something went wrong! Please check the errors below.

  <% end %>

    <%= text_input f, :name,
                      class: "form-control",
                      required: true,
                      placeholder: "Your name" %>
    <%= error_tag f, :name %>

  <%= if @behaviour == "create" do %>

      <%= text_input f, :email,
                        class: "form-control",
                        placeholder: "Your email",
                        required: true,
                        pattern: "^[^@\\s]+@[^@\\s]+\\.[^@\\s]{2,}$" %>
      <%= error_tag f, :email %>

  <% end %>

    <%= password_input f, :password,
                          class: "form-control",
                          required: true,
                          placeholder: "Your password" %>
    <%= error_tag f, :password %>

    <%= password_input f, :password_confirmation,
                          class: "form-control",
                          required: true,
                          placeholder: "Confirm your password" %>
    <%= error_tag f, :password_confirmation %>

    <%= submit (if @behaviour == "create", do: "SignUp", else: "Update"), class: "btn btn-primary" %>

<% end %>

<%= form_for @changeset, @action, fn f -> %>
  <%= if @changeset.action do %>

Oops, something went wrong! Please check the errors below.

  <% end %>

    <%= label f, :name, class: "control-label" %>
    <%= text_input f, :name, class: "form-control" %>
    <%= error_tag f, :name %>

  <%= if @behaviour == "create" do %>

      <%= label f, :email, class: "control-label" %>
      <%= email_input f, :email, class: "form-control" %>
      <%= error_tag f, :email %>

  <% end %>

    <%= label f, :password, class: "control-label" %>
    <%= password_input f, :password, class: "form-control" %>
    <%= error_tag f, :password %>

    <%= label f, :password_confirmation, class: "control-label" %>
    <%= password_input f, :password_confirmation, class: "form-control" %>
    <%= error_tag f, :password_confirmation %>

    <%= submit (if @behaviour == "create", do: "SignUp", else: "Update"), class: "btn btn-primary" %>

<% end %>


Add icon to page head

Add icon to page head

<!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="">
    <link rel="icon" type="image/png" href="'<%= static_path(@conn, "/images/readerl-icon.png") %>" sizes="180x95" />

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

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

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

      <%= @inner %>

<!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>ReadErl</title>
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">

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

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

      <%= @inner %>


Update exec script to use pwsh over powershell, when available

:: Discover the current release directory from the directory
:: of this script and the start_erl.data file
@echo off
set script_dir=%~dp0
for %%A in ("%script_dir%\..") do (
  set release_root_dir=%%~fA
)
set rel_name=<%= release_name %>
set rel_vsn=<%= release_version %>
set boot_script=%release_root_dir%\releases\%rel_vsn%\%rel_name%.ps1

:: Use pwsh.exe rather than powershell.exe if available
set prog=powershell
where pwsh
if %ERRORLEVEL% eq 0 (
  set prog=pwsh
)
%prog% -NonInteractive -NoProfile -ExecutionPolicy Bypass -Command "& "%boot_script%" @args" %*

:: Discover the current release directory from the directory
:: of this script and the start_erl.data file
@echo off
set script_dir=%~dp0
for %%A in ("%script_dir%\..") do (
  set release_root_dir=%%~fA
)
set rel_name=<%= release_name %>
set rel_vsn=<%= release_version %>
set boot_script=%release_root_dir%\releases\%rel_vsn%\%rel_name%.ps1
powershell -NonInteractive -NoProfile -ExecutionPolicy Bypass -Command "& "%boot_script%" @args" %*


Add simple email privacy message

Add simple email privacy message

<%= gettext "Register" %>

  <%= form_for @changeset, registration_path(@conn, :create), [class: "create-registration"], fn f -> %>
    <%= if @changeset.action do %>

          <%= gettext "Oops, something went wrong! Please check the errors below." %>

    <% end %>

        <%= input f, :name %>

        <%= input f, :email, as: :email %>

<%= gettext("Your email address will only ever be used to send you notifications of new games and moves.") %>

        <%= input f, :password, as: :password %>

      <%= submit gettext("Register"), class: "btn btn-primary" %>

  <% end %>

<%= gettext "Register" %>

  <%= form_for @changeset, registration_path(@conn, :create), [class: "create-registration"], fn f -> %>
    <%= if @changeset.action do %>

          <%= gettext "Oops, something went wrong! Please check the errors below." %>

    <% end %>

        <%= input f, :name %>

        <%= input f, :email, as: :email %>

        <%= input f, :password, as: :password %>

      <%= submit gettext("Register"), class: "btn btn-primary" %>

  <% end %>


added github ribbons

added github ribbons