sys.config and vm.args not being copied correctly during upgrade if they are symlinks (#272)

#!/bin/sh

set -e

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

## Run hooks for one of the configured startup phases
run_hooks() {
  case $1 in
    pre_configure)
      _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
      ;;
    pre_start)
      _run_hooks_from_dir "$PRE_START_HOOKS"
      ;;
    pre_stop)
      _run_hooks_from_dir "$PRE_STOP_HOOKS"
      ;;
    post_start)
      _run_hooks_from_dir "$POST_START_HOOKS"
      ;;
    post_stop)
      _run_hooks_from_dir "$POST_STOP_HOOKS"
      ;;
    pre_upgrade)
      _run_hooks_from_dir "$PRE_UPGRADE_HOOKS"
      ;;
    post_upgrade)
      _run_hooks_from_dir "$POST_UPGRADE_HOOKS"
      ;;
  esac
}

# 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 '%s', with permissions set to 0400", "$DEFAULT_COOKIE_FILE"
        exit 1
    fi
}

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

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

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

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

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

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

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

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

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

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

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

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

# Make sure ERTS configuration is set
_init_erts_config

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

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

# Make sure config paths are setup
_init_configs

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

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

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

# Extract the target cookie
_load_cookie

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

cd "$ROOTDIR"

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

# For Elixir runtime
export DISTILLERY_TASK="$1"

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

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

        _check_cookie
        run_hooks pre_configure
        run_hooks pre_start

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

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

        mkdir -p "$PIPE_DIR"

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

        run_hooks post_start
        ;;

    stop)
        _check_cookie
        run_hooks pre_stop
        # 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 post_stop
        ;;

    restart)
        _check_cookie
        run_hooks pre_configure
        run_hooks pre_start
        ## Restart the VM without exiting the process
        if ! nodetool "restart"; then
            exit 1
        fi
        ;;

    reboot)
        _check_cookie
        run_hooks pre_configure
        run_hooks pre_start
        ## Restart the VM completely (uses heart to restart it)
        if ! nodetool "reboot"; then
            exit 1
        fi
        ;;

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

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

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

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

    attach)
        _check_cookie

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

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

    remote_console)
        _check_cookie

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

        shift
        _rem_sh
        ;;

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

        _check_cookie

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

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

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

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

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

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

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

        # Run any post-upgrade hooks
        run_hooks post_upgrade

        ;;
    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 pre_configure
        run_hooks pre_start

        # 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 pre_configure
        run_hooks pre_start

        # 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 post_start
        wait $__bg_pid
        __exit_code=$?
        run_hooks post_stop
        exit $__exit_code
        ;;
    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

        run_hooks pre_configure

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

        # Save extra arguments
        ARGS=$*

        # Build arguments for erlexec
        __code_paths=$(_get_code_paths)
        [ "$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 "$@" -s init stop $ERL_OPTS -extra $ARGS
        exit "$?"
        ;;
    reload_config)
        # Reload the running system's configuration
        _check_cookie

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

        run_hooks pre_configure

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

exit 0

#!/bin/sh

set -e

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

## Run hooks for one of the configured startup phases
run_hooks() {
  case $1 in
    pre_configure)
      _run_hooks_from_dir "$PRE_CONFIGURE_HOOKS"
      ;;
    pre_start)
      _run_hooks_from_dir "$PRE_START_HOOKS"
      ;;
    pre_stop)
      _run_hooks_from_dir "$PRE_STOP_HOOKS"
      ;;
    post_start)
      _run_hooks_from_dir "$POST_START_HOOKS"
      ;;
    post_stop)
      _run_hooks_from_dir "$POST_STOP_HOOKS"
      ;;
    pre_upgrade)
      _run_hooks_from_dir "$PRE_UPGRADE_HOOKS"
      ;;
    post_upgrade)
      _run_hooks_from_dir "$POST_UPGRADE_HOOKS"
      ;;
  esac
}

# 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 '%s', with permissions set to 0400", "$DEFAULT_COOKIE_FILE"
        exit 1
    fi
}

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

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

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

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

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

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

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

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

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

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

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

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

# Make sure ERTS configuration is set
_init_erts_config

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

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

# Make sure config paths are setup
_init_configs

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

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

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

# Extract the target cookie
_load_cookie

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

cd "$ROOTDIR"

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

# For Elixir runtime
export DISTILLERY_TASK="$1"

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

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

        _check_cookie
        run_hooks pre_configure
        run_hooks pre_start

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

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

        mkdir -p "$PIPE_DIR"

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

        run_hooks post_start
        ;;

    stop)
        _check_cookie
        run_hooks pre_stop
        # 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 post_stop
        ;;

    restart)
        _check_cookie
        run_hooks pre_configure
        run_hooks pre_start
        ## Restart the VM without exiting the process
        if ! nodetool "restart"; then
            exit 1
        fi
        ;;

    reboot)
        _check_cookie
        run_hooks pre_configure
        run_hooks pre_start
        ## Restart the VM completely (uses heart to restart it)
        if ! nodetool "reboot"; then
            exit 1
        fi
        ;;

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

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

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

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

    attach)
        _check_cookie

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

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

    remote_console)
        _check_cookie

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

        shift
        _rem_sh
        ;;

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

        _check_cookie

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

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

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

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

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

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

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

        # Run any post-upgrade hooks
        run_hooks post_upgrade

        ;;
    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 pre_configure
        run_hooks pre_start

        # 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 pre_configure
        run_hooks pre_start

        # 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 post_start
        wait $__bg_pid
        __exit_code=$?
        run_hooks post_stop
        exit $__exit_code
        ;;
    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

        run_hooks pre_configure

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

        # Save extra arguments
        ARGS=$*

        # Build arguments for erlexec
        __code_paths=$(_get_code_paths)
        [ "$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 "$@" -s init stop $ERL_OPTS -extra $ARGS
        exit "$?"
        ;;
    reload_config)
        # Reload the running system's configuration
        _check_cookie

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

        run_hooks pre_configure

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

exit 0


Correct id name

Correct id name

      <%= developer_header(@posts_count, @developer) %>

  <%= render Tilex.SharedView, "_posts_list.html", conn: @conn, posts: @posts %>

<%= render Tilex.SharedView, "_pagination.html", conn: @conn, page: @page, posts: @posts %>


fix elixir 1.11 EEx newline removal issue

Package: <%= sanitized_name %>
Version: <%= version %>
Vendor: <%= vendor %>
Architecture: <%= arch %>
Maintainer: <%= maintainers %>
Installed-Size: <%= installed_size %><%= if external_dependencies != nil do %>
Depends: <%= external_dependencies %>
<% end %>Priority: optional
Section: utils
Homepage: <%= homepage %>
Description: <%= description %>

Package: <%= sanitized_name %>
Version: <%= version %>
Vendor: <%= vendor %>
Architecture: <%= arch %>
Maintainer: <%= maintainers %>
Installed-Size: <%= installed_size %>
<%= if external_dependencies != nil do %>
Depends: <%= external_dependencies %>
<% end %>
Priority: optional
Section: utils
Homepage: <%= homepage %>
Description: <%= description %>


Made the drawer fixed

Made the drawer fixed

<!DOCTYPE html>

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

    <title>Hello CoursePlanner!</title>
    <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Roboto:300,400,500,700" type="text/css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">

        Course Planner

          Link

    <%= CoursePlanner.SharedView.navbar "Course Planner" do %>
      <%= CoursePlanner.SharedView.navbar_item "Users", @conn, user_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Coordinators", @conn, coordinator_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Students", @conn, student_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Teachers", @conn, teacher_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Volunteers", @conn, volunteer_path(@conn, :index) %>

      <%= CoursePlanner.SharedView.navbar_item "Courses", @conn, course_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Terms", @conn, term_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Offered Courses By Term", @conn, offered_course_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Classes", @conn, class_path(@conn, :index) %>
      <%= CoursePlanner.SharedView.navbar_item "Tasks", @conn, task_path(@conn, :index) %>
    <% end %>

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

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

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


Added a max length to the name field

Added a max length to the name field

          Player
          Kills
          Deaths

      <input type="text" id="tanx-name-field" class="form-control" maxlength="16" placeholder="Name">

      <button class="btn btn-primary btn-sm" id="tanx-join-btn">Join Game</button>
      <button class="btn btn-default btn-sm" id="tanx-leave-btn">Leave Game</button>

Instructions

Click on one of the pulsing yellow entry points to start your tank.

Move your tank with the arrow keys: forward, right, and left. Alternately, you can use the I, J, and L keys.

Space bar fires a missile. Shoot down the other players' tanks!

The Z key aborts (self-destructs) your tank.

      <canvas tabindex="0" id="tanx-canvas"></canvas>

        Frame rate:

          Player
          Kills
          Deaths

      <input type="text" id="tanx-name-field" class="form-control" placeholder="Name">

      <button class="btn btn-primary btn-sm" id="tanx-join-btn">Join Game</button>
      <button class="btn btn-default btn-sm" id="tanx-leave-btn">Leave Game</button>

Instructions

Click on one of the pulsing yellow entry points to start your tank.

Move your tank with the arrow keys: forward, right, and left. Alternately, you can use the I, J, and L keys.

Space bar fires a missile. Shoot down the other players' tanks!

The Z key aborts (self-destructs) your tank.

      <canvas tabindex="0" id="tanx-canvas"></canvas>

        Frame rate:


UI changes

UI changes

<!DOCTYPE html>

	<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
	<meta content="width=device-width, initial-scale=1" name="viewport">
	<meta content="BeyondBOINC displays the recently created content from a curated list of Steemit authors on the topics of cryptocurrency, distributed computing and technology." name="description">
	<meta content="Gridcoin, Bitshares, Steemit, Cryptocurrency, Blog, Aggregator, Glasnost, BOINC, BeyondBitcoin, BeyondBOINC, Distributed Computing, Cloud computing, Science, Peerplays, Blockchain, Decentralization, money, science, technology, crypto" name="keywords">
	<meta content="Customminer aka @cm-steem" name="author">
	<meta content="index, follow" name="robots">
	<meta content="1 days" name="revisit-after">

	<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

	<link href="https://beyondboinc.net" rel="canonical">
	<title>BeyondBOINC: <%= naive_translate("head title", @conn.assigns[:lang])%></title>
 	<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
 	<link href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.9/semantic.min.css" rel="stylesheet">

          			<img class="logo" src="/images/<%=naive_image_chooser("logo", @conn.assigns[:lang])%>">
          			BeyondBOINC

        	<%=naive_translate("home", @conn.assigns[:lang])%>

        	<a href="/authors/<%=@conn.assigns[:about_blog_author]%>/<%=@conn.assigns[:about_blog_permlink]%>" class="item"><%=naive_translate("about", @conn.assigns[:lang])%>
        	<a href="<%=if @conn.assigns[:lang] == "ru", do: "https://golos.io", else: "https://steemit.com"%>" class="item"><%=naive_translate("about_steemlike_chain", @conn.assigns[:lang])%>

					Trade GRC

							Decentralized Exchanges

							BitSquare

							OpenLedger

							BTSABC

							BTSBOTS

							Bitshares-Light

							Centralized Exchanges

							HolyTransactions

							Poloniex

							C-Cex

							Bittrex

							Explorers

							GridcoinStats

							GridResearchCorp

							Explorer.Gridcoin.Asia

							HolyTransactions

							Exchange stats

							CoinMarketCap

							CoinGecko

							CoinCap

					Community links

							 Gridcoin

									Website

									Forums

									GitHub

									Twitter

									Steemit

									Telegram

									Reddit

									IRC

									Wiki

							 BOINC

									BOINC Website

									BOINC Forums

									FormulaBOINC

									User of the day

									Rechenkraft

									Desktop Grid Federation

									SETI Germany

									SETI USA

							 Bitshares

									Official website

									Forums

									Telegram

									Explorer

							 Peerplays

									Official website

									Telegram

									Peerplays.chat

									GitHub

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

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

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

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

<%end %>

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

Promoted Tags

	            Gridcoin
	            BOINC
	            BeyondBitcoin
	            Cryptocurrency

Promoted Authors

	            CM-Steem
	            OfficialFuzzy
	            Erkan
	            Chris4210

Affiliate links

	            Vultr
	            Namecheap
	            NordVPN
	            Purse.IO

About

BeyondBOINC is a Steemit backed blog, powered by the  Glasnost  library & is actively maintained by @CM-STEEM.

	      <img class="ui centered mini image" src="/images/<%=naive_image_chooser("logo", @conn.assigns[:lang])%>">

	        Home
	        Site Map
	        Gridcoin Chat

<!DOCTYPE html>

	<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
	<meta content="width=device-width, initial-scale=1" name="viewport">
	<meta content="BeyondBOINC displays the recently created content from a curated list of Steemit authors on the topics of cryptocurrency, distributed computing and technology." name="description">
	<meta content="Gridcoin, Bitshares, Steemit, Cryptocurrency, Blog, Aggregator, Glasnost, BOINC, BeyondBitcoin, BeyondBOINC, Distributed Computing, Cloud computing, Science, Peerplays, Blockchain, Decentralization, money, science, technology, crypto" name="keywords">
	<meta content="Customminer aka @cm-steem" name="author">
	<meta content="index, follow" name="robots">
	<meta content="1 days" name="revisit-after">

	<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

	<link href="https://beyondboinc.net" rel="canonical">
	<title>BeyondBOINC: <%= naive_translate("head title", @conn.assigns[:lang])%></title>
 	<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
 	<link href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.9/semantic.min.css" rel="stylesheet">

          			<img class="logo" src="/images/<%=naive_image_chooser("logo", @conn.assigns[:lang])%>">

        	<%=naive_translate("home", @conn.assigns[:lang])%>

        	<a href="/authors/<%=@conn.assigns[:about_blog_author]%>/<%=@conn.assigns[:about_blog_permlink]%>" class="item"><%=naive_translate("about", @conn.assigns[:lang])%>
        	<a href="<%=if @conn.assigns[:lang] == "ru", do: "https://golos.io", else: "https://steemit.com"%>" class="item"><%=naive_translate("about_steemlike_chain", @conn.assigns[:lang])%>

					Trade GRC

							Decentralized Exchanges

							BitSquare

							OpenLedger

							BTSABC

							BTSBOTS

							Bitshares-Light

							Centralized Exchanges

							HolyTransactions

							Poloniex

							C-Cex

							Bittrex

							Explorers

							GridcoinStats

							GridResearchCorp

							Explorer.Gridcoin.Asia

							HolyTransactions

							Exchange stats

							CoinMarketCap

							CoinGecko

							CoinCap

					Community links

							 Gridcoin

									Website

									Forums

									GitHub

									Twitter

									Steemit

									Telegram

									Reddit

									IRC

									Wiki

							 BOINC

									BOINC Website

									BOINC Forums

									FormulaBOINC

									User of the day

									Rechenkraft

									Desktop Grid Federation

									SETI Germany

									SETI USA

							 Bitshares

									Official website

									Forums

									Telegram

									Explorer

							 Peerplays

									Official website

									Telegram

									Peerplays.chat

									GitHub

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

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

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

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

<%end %>

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

				BeyondBOINC is a  Steemit  backed blog, powered by the  Glasnost  & is maintained by  @CM-STEEM.

				Home, SiteMap.


Capitalize 'Slack' on home page

Capitalize 'Slack' on home page

  <%= render Org.SharedView, "nav.html", assigns %>

      Thanks for your interest in joining!

      To help prevent spam, we request that you sign in with GitHub to continue

    <a class="btn-large" href="<%= auth_path(@conn, :index, "github") %>">
       Authorize

      Your public profile information and activity will be used to verify you're
      not a robot or a spammer.

  <%= render Org.SharedView, "nav.html", assigns %>

      Thanks for your interest in joining!

      To help prevent spam, we request that you sign in with GitHub to continue

    <a class="btn-large primary" href="<%= auth_path(@conn, :index, "github") %>">
       Authorize

      Your public profile information and activity will be used to verify you're
      not a robot or a spammer.


s/skill/user_skill/g (skill as a var name was misleading)

  <%= for user_skill <- @user_skills do %>

        <%= link Skill.resolve_name(user_skill.skill_id), to: user_user_skill_path(@conn, :show, @user, user_skill) %>

          <%= if Enum.count(user_skill.endorsements) == 1 do %>
          <%= Enum.count(user_skill.endorsements) %> <%= gettext "upvote" %>
          <% end %>
          <%= if Enum.count(user_skill.endorsements) > 1 do %>
          <%= Enum.count(user_skill.endorsements) %> <%= gettext "upvotes" %>
          <% end %>

      <%= if @current_user do %>
        <%= if Vutuv.Endorsement.skill_endorsed?(user_skill.id, @current_user_id) do %>
          <%= button to: user_endorsement_path(@conn, :delete, @user, user_skill), method: :delete , class: "button button--icon", form: [class: "button button--icon"] do %>

          <% end %>
        <%= else %>
          <%= button to: user_endorsement_path(@conn, :create, @user, id: user_skill), method: :post , class: "button button--icon", form: [class: "button button--icon"] do %>

          <% end %>
        <%= end %>
        <%= if same_user?(@user, @current_user) do %>
        <%= button to: user_user_skill_path(@conn, :delete, @user, user_skill), method: :delete, class: "button button--icon", form: [class: "button button--icon"] do %>

        <% end %>
        <% end %>
      <% end %>

      <hr style="width: <%= (Enum.count(user_skill.endorsements)+1)/(Enum.count(hd(@user_skills).endorsements)+1)*100 %>%" />

  <% end %>

  <%= for skill <- @user_skills do %>

        <%= link Skill.resolve_name(skill.skill_id), to: user_user_skill_path(@conn, :show, @user, skill) %>

          <%= if Enum.count(skill.endorsements) == 1 do %>
          <%= Enum.count(skill.endorsements) %> <%= gettext "upvote" %>
          <% end %>
          <%= if Enum.count(skill.endorsements) > 1 do %>
          <%= Enum.count(skill.endorsements) %> <%= gettext "upvotes" %>
          <% end %>

      <%= if @current_user do %>
        <%= if Vutuv.Endorsement.skill_endorsed?(skill.id, @current_user_id) do %>
          <%= button to: user_endorsement_path(@conn, :delete, @user, skill), method: :delete , class: "button button--icon", form: [class: "button button--icon"] do %>

          <% end %>
        <%= else %>
          <%= button to: user_endorsement_path(@conn, :create, @user, id: skill), method: :post , class: "button button--icon", form: [class: "button button--icon"] do %>

          <% end %>
        <%= end %>
        <%= if same_user?(@user, @current_user) do %>
        <%= button to: user_user_skill_path(@conn, :delete, @user, skill), method: :delete, class: "button button--icon", form: [class: "button button--icon"] do %>

        <% end %>
        <% end %>
      <% end %>

      <hr style="width: <%= (Enum.count(skill.endorsements)+1)/(Enum.count(hd(@user_skills).endorsements)+1)*100 %>%" />

  <% end %>


more stats links

more stats links

      <%= link [fa_icon("folder-o"), " ", "Panoptikum"],
               to: category_frontend_path(@conn, :stats) %>
      /
      <%= if @category.parent do %>
        <%= link [fa_icon("folder-o"), " ", @category.parent.title],
                 to: category_frontend_path(@conn, :show, @category.parent) %>
        /
      <% end %>
      <%= fa_icon("folder-open-o") %> <%= @category.title %>

    <%= if @category.children != [] do %>
      <%= for group <- Enum.chunk(@category.children, 6, 6, []) do %>

          <%= for subcategory <- group do %>

              <%= link [fa_icon("folder-o"), " ", subcategory.title],
                       to: category_frontend_path(@conn, :show_stats, subcategory),
                       class: "btn btn-xs btn-light-gray truncate" %>

          <% end %>

      <% end %>

    <% end %>

    Jump to:
    <%= for {language, podcasts} <- Enum.group_by(@podcasts, &Map.get(&1, :language_name)) do %>

        <%= Integer.to_string(Enum.count(podcasts)) %>
        <%= List.first(podcasts) && List.first(podcasts).language_emoji %>
        <%= link (language || "Language unknown"), to: "#" <> (language || "Language unknown"),
                                                    id: "lang-#{language}"%>
    <% end %>

    <%= for {language, podcasts} <- Enum.group_by(@podcasts, &Map.get(&1, :language_name)) do %>
      <h3 id="<%= language %>"><%= List.first(podcasts) && List.first(podcasts).language_emoji %>
        <%= if podcasts != [], do: Integer.to_string(Enum.count(podcasts)) %> <%= language || "Language unknown" %>

      <%= for group <- Enum.chunk(podcasts, 6, 6, []) do %>

          <%= for podcast <- group do %>

                <%= link [fa_icon("podcast"), " ", podcast.title],
                         to: podcast_frontend_path(@conn, :show, podcast.id),
                         class: "btn btn-default btn-xs truncate",
                         id: "podcast-#{podcast.id}" %>

          <% end %>

      <% end %>
    <% end %>

<%= if @current_user do %>
  <%= like_or_unlike(@current_user.id, @category.id) %>
  <%= follow_or_unfollow(@current_user.id, @category.id) %>
<% end %>

      <%= link [fa_icon("folder-o"), " ", "Panoptikum"],
               to: category_frontend_path(@conn, :stats) %>
      /
      <%= if @category.parent do %>
        <%= link [fa_icon("folder-o"), " ", @category.parent.title],
                 to: category_frontend_path(@conn, :show, @category.parent) %>
        /
      <% end %>
      <%= fa_icon("folder-open-o") %> <%= @category.title %>

    <%= if @category.children != [] do %>
      <%= for group <- Enum.chunk(@category.children, 6, 6, []) do %>

          <%= for subcategory <- group do %>

              <%= link [fa_icon("folder-o"), " ", subcategory.title],
                       to: category_frontend_path(@conn, :show, subcategory),
                       class: "btn btn-xs btn-light-gray truncate" %>

          <% end %>

      <% end %>

    <% end %>

    Jump to:
    <%= for {language, podcasts} <- Enum.group_by(@podcasts, &Map.get(&1, :language_name)) do %>

        <%= Integer.to_string(Enum.count(podcasts)) %>
        <%= List.first(podcasts) && List.first(podcasts).language_emoji %>
        <%= link (language || "Language unknown"), to: "#" <> (language || "Language unknown"),
                                                    id: "lang-#{language}"%>
    <% end %>

    <%= for {language, podcasts} <- Enum.group_by(@podcasts, &Map.get(&1, :language_name)) do %>
      <h3 id="<%= language %>"><%= List.first(podcasts) && List.first(podcasts).language_emoji %>
        <%= if podcasts != [], do: Integer.to_string(Enum.count(podcasts)) %> <%= language || "Language unknown" %>

      <%= for group <- Enum.chunk(podcasts, 6, 6, []) do %>

          <%= for podcast <- group do %>

                <%= link [fa_icon("podcast"), " ", podcast.title],
                         to: podcast_frontend_path(@conn, :show, podcast.id),
                         class: "btn btn-default btn-xs truncate",
                         id: "podcast-#{podcast.id}" %>

          <% end %>

      <% end %>
    <% end %>

<%= if @current_user do %>
  <%= like_or_unlike(@current_user.id, @category.id) %>
  <%= follow_or_unfollow(@current_user.id, @category.id) %>
<% end %>


script needs to be after

script needs to be after

<div style="padding: 40px;">
  <%= raw(@content) %>
</div>

<script>

  function showHiddenContent (ev) {
    var el = document.querySelector('#vol-event');
    if (el.style.display == 'hidden') {
      el.style.display = 'block';
    } else {
      el.style.display = 'none';
    }
  }

  var button = document.querySelector('#show-events');
  debugger
  if (button) {
    button.onlick = showHiddenContent();
  }

</script>

<script>

  function showHiddenContent (ev) {
    var el = document.querySelector('#vol-event');
    if (el.style.display == 'hidden') {
      el.style.display = 'block';
    } else {
      el.style.display = 'none';
    }
  }

  var button = document.querySelector('#show-events');
  debugger
  if (button) {
    button.onlick = showHiddenContent();
  }

</script>

<div style="padding: 40px;">
  <%= raw(@content) %>
</div>


Standardize credit naming

Standardize credit naming

  <%= gettext "Thank you for so much registering/logging in!" %>

          <button type="button" class="btn btn-default">
            <%= gettext "Back" %>
          </button>

          <button type="button" class="btn btn-default">
            <%= gettext "Log out" %>
          </button>

          <button type="button" class="btn btn-default">
            <%= gettext "Settings" %>
          </button>

        <%= for {stock_type, _stocks} <- @food_stock_by_type do %>
          <li class="<%= active(stock_type, @food_stock_by_type)%>">
            <a href="#<%= stock_type %>" data-toggle="tab"> <%= stock_type %>

        <% end %>

        <%= for {stock_type, stocks} <- @food_stock_by_type do %>
          <div class="tab-pane <%= active(stock_type, @food_stock_by_type)%>" id="<%= stock_type %>">

              <%= stock_type %> <%= gettext("remaining:") %> <%=  @credits[stock_type] %>

                <%# TBD?
                  <colgroup>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                  </colgroup>
                %>

                  <%= gettext("Food description") %>
                  <%= gettext("Food packaging") %>
                  <%= gettext("Manufacturer info (if available)") %>
                  <%= gettext("Weight") %>
                  <%= gettext("Quantity available") %>
                  <%= stock_type %> cost

                  <%= gettext("Quantity requested") %>

                  <%= for stock <- stocks do %>

                        <%= stock.food.longdesc %>

                        <%= stock.packaging %>

                        <%= stock.food.manufacturer_name %>

                        <%= stock.weight %>

                        <%= stock.quantity %>

                        <%= stock.credits_per_package %>

                        <button data-action="add">
                        +
                        </button>

                        <%= quantity(stock, @package) %>

                        <button data-action="remove">
                        -
                        </button>

                        <button data-action="remove-all">
                        X
                        </button>

                  <% end %>

        <% end %>

  <%= gettext "Thank you for so much registering/logging in!" %>

          <button type="button" class="btn btn-default">
            <%= gettext "Back" %>
          </button>

          <button type="button" class="btn btn-default">
            <%= gettext "Log out" %>
          </button>

          <button type="button" class="btn btn-default">
            <%= gettext "Settings" %>
          </button>

        <%= for {stock_type, _stocks} <- @food_stock_by_type do %>
          <li class="<%= active(stock_type, @food_stock_by_type)%>">
            <a href="#<%= stock_type %>" data-toggle="tab"> <%= stock_type %>

        <% end %>

        <%= for {stock_type, stocks} <- @food_stock_by_type do %>
          <div class="tab-pane <%= active(stock_type, @food_stock_by_type)%>" id="<%= stock_type %>">

              <%= stock_type %> <%= gettext("credits remaining:") %> <%=  @credits[stock_type] %>

                <%# TBD?
                  <colgroup>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                    <col>
                  </colgroup>
                %>

                  <%= gettext("Food description") %>
                  <%= gettext("Food packaging") %>
                  <%= gettext("Manufacturer info (if available)") %>
                  <%= gettext("Weight") %>
                  <%= gettext("Quantity available") %>
                  <%= gettext("Credits") %>

                  <%= gettext("Quantity requested") %>

                  <%= for stock <- stocks do %>

                        <%= stock.food.longdesc %>

                        <%= stock.packaging %>

                        <%= stock.food.manufacturer_name %>

                        <%= stock.weight %>

                        <%= stock.quantity %>

                        <%= stock.credits_per_package %>  <%= stock_type %>

                        <button data-action="add">
                        +
                        </button>

                        <%= quantity(stock, @package) %>

                        <button data-action="remove">
                        -
                        </button>

                        <button data-action="remove-all">
                        X
                        </button>

                  <% end %>

        <% end %>


Avoid html-escape of experiment javascript

<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
<script>
var ex = require("web/static/js/app");
<%= raw @javascript %>
_experiment = new ex.Experiment("<%= @topic %>", "<%= @token %>", onUpdate)
function send_data(data) {
  _experiment.send_data(data)
}
</script>
<div id="content">
</div>

<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
<script>
<%= @javascript %>
var ex = require("web/static/js/app");
_experiment = new ex.Experiment("<%= @topic %>", "<%= @token %>", onUpdate)
function send_data(data) {
  _experiment.send_data(data)
}
</script>
<div id="content">
</div>


fix: various meta data might be nil

fix: various meta data might be nil

<%
p_type = if assigns[:type], do: assigns[:type], else: :thumbnail
%><article class="picture<%= if assigns[:home] do %> home<% end %><%= if not @picture.show_in_index and logged_in?(@conn) do %> unpublished<% end %> h-entry">
  <%= unless assigns[:atom] do %>

<%= @picture.title %>

        <%= link to: page_path(@conn, :about), rel: "me" do %><img src="<%= static_path(@conn, "/images/" <> @picture.author.avatar) %>" class="avatar u-photo"> <%= @picture.author.name %><% end %>,
      <time class="dt-published" datetime="<%= @picture |> Wwwtech.Picture.inserted_at_timex |> DateFormat.format!("%FT%T%:z", :strftime) %>"><%= link Wwwtech.LayoutView.time_ago_in_words(@picture |> Wwwtech.Picture.inserted_at_timex), to: picture_path(@conn, :show, @picture), class: "u-url" %></time>

  <% end %>

  <%= if @picture.in_reply_to != "" and @picture.in_reply_to != nil do %>

      In reply to <%= link @picture.in_reply_to, to: @picture.in_reply_to, class: "u-in-reply-to", rel: "in-reply-to" %>

  <% end %>

  <div class="e-content <%= p_type %>">
    <%= link(to: (if p_type == :thumbnail, do: picture_path(@conn, :show, @picture), else: picture_path(@conn, :show, @picture) <> ".png")) do %><img src="<%= picture_path(@conn, :show, @picture) %>.png?type=<%= p_type %>" alt="" title="<%= @picture.title %>" class="image u-photo"><% end %>

    <%= if p_type != :thumbnail || assigns[:home] do %>
      <%= {:safe, Wwwtech.Picture.to_html(@picture)} %>
    <% end %>
    <%= if assigns[:home] do %><%= link Wwwtech.Picture.inserted_at_timex(@picture) |> DateFormat.format!("%H:%M", :strftime), to: picture_path(@conn, :show, @picture) %><% end %>

  <%= if assigns[:index] == nil and assigns[:atom] == nil do %>
    <%= if assigns[:exif] != nil and assigns[:exif] != %{} do %>

Meta

          <%= if @exif[:model] != nil do %>

Camera

<%= @exif[:model] %>

          <% end %>
          <%= if @exif[:date_time] do %>

Taken

<%= DateFormat.parse!(@exif[:date_time], "%Y:%m:%d %H:%M:%S", :strftime) |> DateFormat.format!("%A, %d. %B %Y %H:%M", :strftime) %>

          <% end %>
          <%= if @exif[:pixel_x_dimension] != nil and @exif[:pixel_y_dimension] != nil do %>

Resolution

<%= @exif[:pixel_x_dimension] %>×<%= @exif[:pixel_y_dimension] %>

          <% end %>
          <%= if @exif[:gps_latitude] != nil and @exif[:gps_longitude] != nil do %>

GPS position
<% [la_h,la_m,la_s] = @exif[:gps_latitude]
                                 [lo_h, lo_m, lo_s] = @exif[:gps_longitude]%>

              <a href="http://www.openstreetmap.org/?lat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&lon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&mlat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&mlon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&zoom=16">
                <%= la_h %>° <%= la_m %>′ <%= la_s %>″ <%= @exif[:gps_latitude_ref] %> /
                <%= lo_h %>° <%= lo_m %>′ <%= lo_s %>″ <%= @exif[:gps_longitude_ref] %>

          <% end %>

        <%= if @exif[:gps_latitude] != nil and @exif[:gps_longitude] != nil do %>
          <a class="osm" href="http://www.openstreetmap.org/?lat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&lon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&mlat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&mlon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&zoom=16"><img src="<%= cache_path(@conn, :show, url: "http://staticmap.openstreetmap.de/staticmap.php?center=#{to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref])},#{to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref])}&markers=#{to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref])},#{to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref])}&zoom=16&size=640x480") %>">
        <% end %>

    <% end %>

    <%= if @picture.posse do %>

        <%= link "Twitter POSSE", to: "https://brid.gy/publish/twitter" %>

    <% end %>

    <% replies = Wwwtech.LayoutView.filtered_mentions(@picture.mentions) %>
    <%= if Enum.count(replies) > 0 do %>

<%= Enum.count(replies) %> Replies

          <%= for reply <- replies do %>
            <%= render Wwwtech.LayoutView, "reply.html", reply: reply, conn: @conn  %>
          <% end %>

    <% end %>

    <% likes = Wwwtech.LayoutView.filtered_mentions(@picture.mentions, "like") %>
    <%= if Enum.count(likes) > 0 do %>

<%= Enum.count(likes) %> Likes

          <%= for like <- likes do %>
            <%= render Wwwtech.LayoutView, "like.html", like: like, conn: @conn %>
          <% end %>

    <% end %>
  <% end %>

<%
p_type = if assigns[:type], do: assigns[:type], else: :thumbnail
%><article class="picture<%= if assigns[:home] do %> home<% end %><%= if not @picture.show_in_index and logged_in?(@conn) do %> unpublished<% end %> h-entry">
  <%= unless assigns[:atom] do %>

<%= @picture.title %>

        <%= link to: page_path(@conn, :about), rel: "me" do %><img src="<%= static_path(@conn, "/images/" <> @picture.author.avatar) %>" class="avatar u-photo"> <%= @picture.author.name %><% end %>,
      <time class="dt-published" datetime="<%= @picture |> Wwwtech.Picture.inserted_at_timex |> DateFormat.format!("%FT%T%:z", :strftime) %>"><%= link Wwwtech.LayoutView.time_ago_in_words(@picture |> Wwwtech.Picture.inserted_at_timex), to: picture_path(@conn, :show, @picture), class: "u-url" %></time>

  <% end %>

  <%= if @picture.in_reply_to != "" and @picture.in_reply_to != nil do %>

      In reply to <%= link @picture.in_reply_to, to: @picture.in_reply_to, class: "u-in-reply-to", rel: "in-reply-to" %>

  <% end %>

  <div class="e-content <%= p_type %>">
    <%= link(to: (if p_type == :thumbnail, do: picture_path(@conn, :show, @picture), else: picture_path(@conn, :show, @picture) <> ".png")) do %><img src="<%= picture_path(@conn, :show, @picture) %>.png?type=<%= p_type %>" alt="" title="<%= @picture.title %>" class="image u-photo"><% end %>

    <%= if p_type != :thumbnail || assigns[:home] do %>
      <%= {:safe, Wwwtech.Picture.to_html(@picture)} %>
    <% end %>
    <%= if assigns[:home] do %><%= link Wwwtech.Picture.inserted_at_timex(@picture) |> DateFormat.format!("%H:%M", :strftime), to: picture_path(@conn, :show, @picture) %><% end %>

  <%= if assigns[:index] == nil and assigns[:atom] == nil do %>
    <%= if assigns[:exif] != nil and assigns[:exif] != %{} do %>

Meta

Camera

<%= @exif[:model] %>

          <%= if @exif[:date_time] do %>

Taken

<%= DateFormat.parse!(@exif[:date_time], "%Y:%m:%d %H:%M:%S", :strftime) |> DateFormat.format!("%A, %d. %B %Y %H:%M", :strftime) %>

          <% end %>

Resolution

<%= @exif[:pixel_x_dimension] %>×<%= @exif[:pixel_y_dimension] %>

          <%= if @exif[:gps_latitude] != nil and @exif[:gps_longitude] != nil do %>

GPS position
<% [la_h,la_m,la_s] = @exif[:gps_latitude]
                                 [lo_h, lo_m, lo_s] = @exif[:gps_longitude]%>

              <a href="http://www.openstreetmap.org/?lat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&lon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&mlat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&mlon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&zoom=16">
                <%= la_h %>° <%= la_m %>′ <%= la_s %>″ <%= @exif[:gps_latitude_ref] %> /
                <%= lo_h %>° <%= lo_m %>′ <%= lo_s %>″ <%= @exif[:gps_longitude_ref] %>

          <% end %>

        <%= if @exif[:gps_latitude] != nil and @exif[:gps_longitude] != nil do %>
          <a class="osm" href="http://www.openstreetmap.org/?lat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&lon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&mlat=<%= to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref]) %>&mlon=<%= to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref]) %>&zoom=16"><img src="<%= cache_path(@conn, :show, url: "http://staticmap.openstreetmap.de/staticmap.php?center=#{to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref])},#{to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref])}&markers=#{to_degrees(@exif[:gps_latitude], @exif[:gps_latitude_ref])},#{to_degrees(@exif[:gps_longitude], @exif[:gps_longitude_ref])}&zoom=16&size=640x480") %>">
        <% end %>

    <% end %>

    <%= if @picture.posse do %>

        <%= link "Twitter POSSE", to: "https://brid.gy/publish/twitter" %>

    <% end %>

    <% replies = Wwwtech.LayoutView.filtered_mentions(@picture.mentions) %>
    <%= if Enum.count(replies) > 0 do %>

<%= Enum.count(replies) %> Replies

          <%= for reply <- replies do %>
            <%= render Wwwtech.LayoutView, "reply.html", reply: reply, conn: @conn  %>
          <% end %>

    <% end %>

    <% likes = Wwwtech.LayoutView.filtered_mentions(@picture.mentions, "like") %>
    <%= if Enum.count(likes) > 0 do %>

<%= Enum.count(likes) %> Likes

          <%= for like <- likes do %>
            <%= render Wwwtech.LayoutView, "like.html", like: like, conn: @conn %>
          <% end %>

    <% end %>
  <% end %>


Updated title of example app

Updated title of example app

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

Get Started

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

Get Started

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

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

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


img didn't work

img didn't work

<a href="https://steemit.com/@<%= @post.author %>/<%= @post.permlink %>"><%= @post.title %>

Author: <a href="https://beyondboinc.net/authors/<%= @post.author %>/"><%= @post.author %>

        <%= raw(@post.body) %>

		  Home
		  /

Author: <a href="https://beyondboinc.net/authors/<%= @post.author %>/"><%= @post.author %>

		  /

<a href="https://steemit.com/@<%= @post.author %>/<%= @post.permlink %>"><%= @post.permlink %>


block episodes

block episodes

<%= if @episode.podcast.blocked == true do %>
  This episode may not be published here, sorry.
<%= else %>
  <%= render "_header.html", episode: @episode,
                             current_user: @current_user,
                             changeset: @changeset,
                             conn: @conn %>

  <%= render "_recommendations.html", episode: @episode,
                                      conn: @conn %>

Player

  <%= case @player do %>
    <%= "podlove" -> %>

      <audio data-podlove-web-player-source="/episodes/player/<%= @episode.id %>">
        <source src="audio.m4a" type="audio/m4a">
      </audio>

    <%= "podigee" -> %>

  <% end %>

  <%= render "_chapters.html", episode: @episode,
                               current_user: @current_user,
                               changeset: @changeset,
                               player: @player,
                               conn: @conn %>

Enclosures

        <%= for enclosure <- @episode.enclosures do %>

Link

<%= link String.split(enclosure.url, "/")
                       |> List.last, to: enclosure.url %>

Length

<%= enclosure.length %>

Type

<%= enclosure.type %>

Guid

<%= enclosure.guid %>

- - - - -

        <% end %>

Contributors

        <%= for contributor <- @episode.contributors do %>

Name

<%= contributor.name %>

Link

<%= link contributor.uri, to: contributor.uri %>

- - - - -

        <% end %>

Shownotes

<%= raw(@episode.shownotes) %>

<% end %>