Touchup

Touchup

defmodule <%= @web_namespace %>.Telemetry do
  use Supervisor
  import Telemetry.Metrics

  def start_link(arg) do
    Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
  end

  @impl true
  def init(_arg) do
    children = [
      # Telemetry poller will execute the given period measurements
      # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics
      {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}
      # Add reporters as children of your supervision tree.
      # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()}
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end

  def metrics do
    [
      # Phoenix Metrics
      summary("phoenix.endpoint.start.system_time",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.endpoint.stop.duration",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.router_dispatch.start.system_time",
        tags: [:route],
        unit: {:native, :millisecond}
      ),
      summary("phoenix.router_dispatch.exception.duration",
        tags: [:route],
        unit: {:native, :millisecond}
      ),
      summary("phoenix.router_dispatch.stop.duration",
        tags: [:route],
        unit: {:native, :millisecond}
      ),
      summary("phoenix.socket_connected.duration",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.channel_join.duration",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.channel_handled_in.duration",
        tags: [:event],
        unit: {:native, :millisecond}
      ),<%= if @ecto do %>

      # Database Metrics
      summary("<%= @app_name %>.repo.query.total_time",
        unit: {:native, :millisecond},
        description: "The sum of the other measurements"
      ),
      summary("<%= @app_name %>.repo.query.decode_time",
        unit: {:native, :millisecond},
        description: "The time spent decoding the data received from the database"
      ),
      summary("<%= @app_name %>.repo.query.query_time",
        unit: {:native, :millisecond},
        description: "The time spent executing the query"
      ),
      summary("<%= @app_name %>.repo.query.queue_time",
        unit: {:native, :millisecond},
        description: "The time spent waiting for a database connection"
      ),
      summary("<%= @app_name %>.repo.query.idle_time",
        unit: {:native, :millisecond},
        description:
          "The time the connection spent waiting before being checked out for the query"
      ),<% end %>

      # VM Metrics
      summary("vm.memory.total", unit: {:byte, :kilobyte}),
      summary("vm.total_run_queue_lengths.total"),
      summary("vm.total_run_queue_lengths.cpu"),
      summary("vm.total_run_queue_lengths.io")
    ]
  end

  defp periodic_measurements do
    [
      # A module, function and arguments to be invoked periodically.
      # This function must call :telemetry.execute/3 and a metric must be added above.
      # {<%= @web_namespace %>, :count_users, []}
    ]
  end
end

defmodule <%= @web_namespace %>.Telemetry do
  use Supervisor
  import Telemetry.Metrics

  def start_link(arg) do
    Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
  end

  @impl true
  def init(_arg) do
    children = [
      # Telemetry poller will execute the given period measurements
      # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics
      {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}
      # Add reporters as children of your supervision tree.
      # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()}
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end

  def metrics do
    [
      # Phoenix Metrics
      summary("phoenix.endpoint.start.system_time",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.endpoint.stop.duration",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.router_dispatch.start.system_time",
        tags: [:route],
        unit: {:native, :millisecond}
      ),
      summary("phoenix.router_dispatch.exception.duration",
        tags: [:route],
        unit: {:native, :millisecond}
      ),
      summary("phoenix.router_dispatch.stop.duration",
        tags: [:route],
        unit: {:native, :millisecond}
      ),
      summary("phoenix.error_rendered.duration",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.socket_connected.duration",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.channel_join.duration",
        unit: {:native, :millisecond}
      ),
      summary("phoenix.channel_handled_in.duration",
        tags: [:event],
        unit: {:native, :millisecond}
      ),<%= if @ecto do %>

      # Database Metrics
      summary("<%= @app_name %>.repo.query.total_time",
        unit: {:native, :millisecond},
        description: "The sum of the other measurements"
      ),
      summary("<%= @app_name %>.repo.query.decode_time",
        unit: {:native, :millisecond},
        description: "The time spent decoding the data received from the database"
      ),
      summary("<%= @app_name %>.repo.query.query_time",
        unit: {:native, :millisecond},
        description: "The time spent executing the query"
      ),
      summary("<%= @app_name %>.repo.query.queue_time",
        unit: {:native, :millisecond},
        description: "The time spent waiting for a database connection"
      ),
      summary("<%= @app_name %>.repo.query.idle_time",
        unit: {:native, :millisecond},
        description:
          "The time the connection spent waiting before being checked out for the query"
      ),<% end %>

      # VM Metrics
      summary("vm.memory.total", unit: {:byte, :kilobyte}),
      summary("vm.total_run_queue_lengths.total"),
      summary("vm.total_run_queue_lengths.cpu"),
      summary("vm.total_run_queue_lengths.io")
    ]
  end

  defp periodic_measurements do
    [
      # A module, function and arguments to be invoked periodically.
      # This function must call :telemetry.execute/3 and a metric must be added above.
      # {<%= @web_namespace %>, :count_users, []}
    ]
  end
end


Remove un-used vars

Remove un-used vars

defmodule Officetournament.AuthController do
  use Officetournament.Web, :controller
  require Logger

  @doc """
  This action is reached via `/auth/:provider` and redirects to the OAuth2 provider
  based on the chosen strategy.
  """
  def index(conn, %{"provider" => provider}) do
    redirect conn, external: authorize_url!(provider, %{ redirect_uri: auth_url(conn, :callback, provider) })
  end

  @doc """
  This action is reached via `/auth/:provider/callback` is the the callback URL that
  the OAuth2 provider will redirect the user back to with a `code` that will
  be used to request an access token. The access token will then be used to
  access protected resources on behalf of the user.
  """
  def callback(conn, %{"provider" => provider, "code" => code}) do
    # Exchange an auth code for an access token
    token = get_token!(provider, %{ redirect_uri: auth_url(conn, :callback, provider) }, code)

    # Request the user's data with the access token
    user_params = get_user!(provider, token)

    sign_in_via_auth conn, provider, user_params
  end

  defp sign_in_via_auth(conn, provider, user_auth_params) do
    current_user = find_or_create_user(provider, user_auth_params)

    conn
      |> put_session(:current_user_id, current_user.id)
      |> redirect(to: "/")
  end

  def find_or_create_user(provider, user_auth_params) do
    # try do
    #   ElixirStatus.Avatar.load! user_name, url
    # rescue
    #   e -> IO.inspect {"error", e}
    # end

    case Officetournament.UserSessionController.find_by_user_params(provider, user_auth_params) do
      nil -> Officetournament.UserSessionController.create_from_auth_params(provider, user_auth_params)
      user -> user
    end
  end

  defp authorize_url!("github", oauth_client_params), do: GitHub.authorize_url!(oauth_client_params)
  defp authorize_url!("google", oauth_client_params), do: Google.authorize_url!(oauth_client_params)
  defp authorize_url!(_, _), do: raise "No matching provider available"

  defp get_token!("github", oauth_client_params, code), do: GitHub.get_token!(oauth_client_params, code: code)
  defp get_token!("google", oauth_client_params, code), do: Google.get_token!(oauth_client_params, code: code)
  defp get_token!(_, _, _), do: raise "No matching provider available"

  defp get_user!("github", token), do: OAuth2.AccessToken.get!(token, "/user")
  defp get_user!("google", token) do
    OAuth2.AccessToken.get!(token, "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=#{token.access_token}")
  end
end

defmodule Officetournament.AuthController do
  use Officetournament.Web, :controller
  require Logger

  @doc """
  This action is reached via `/auth/:provider` and redirects to the OAuth2 provider
  based on the chosen strategy.
  """
  def index(conn, %{"provider" => provider}) do
    redirect conn, external: authorize_url!(conn, provider, %{ redirect_uri: auth_url(conn, :callback, provider) })
  end

  @doc """
  This action is reached via `/auth/:provider/callback` is the the callback URL that
  the OAuth2 provider will redirect the user back to with a `code` that will
  be used to request an access token. The access token will then be used to
  access protected resources on behalf of the user.
  """
  def callback(conn, %{"provider" => provider, "code" => code}) do
    # Exchange an auth code for an access token
    token = get_token!(provider, %{ redirect_uri: auth_url(conn, :callback, provider) }, code)

    # Request the user's data with the access token
    user_params = get_user!(provider, token)

    sign_in_via_auth conn, provider, user_params
  end

  defp sign_in_via_auth(conn, provider, user_auth_params) do
    current_user = find_or_create_user(provider, user_auth_params)

    conn
      |> put_session(:current_user_id, current_user.id)
      |> redirect(to: "/")
  end

  def find_or_create_user(provider, user_auth_params) do
    # try do
    #   ElixirStatus.Avatar.load! user_name, url
    # rescue
    #   e -> IO.inspect {"error", e}
    # end

    case Officetournament.UserSessionController.find_by_user_params(provider, user_auth_params) do
      nil -> Officetournament.UserSessionController.create_from_auth_params(provider, user_auth_params)
      user -> user
    end
  end

  defp authorize_url!(conn, "github", oauth_client_params), do: GitHub.authorize_url!(oauth_client_params)
  defp authorize_url!(conn, "google", oauth_client_params), do: Google.authorize_url!(oauth_client_params)
  defp authorize_url!(conn, _, _), do: raise "No matching provider available"

  defp get_token!("github", oauth_client_params, code), do: GitHub.get_token!(oauth_client_params, code: code)
  defp get_token!("google", oauth_client_params, code), do: Google.get_token!(oauth_client_params, code: code)
  defp get_token!(_, _, _), do: raise "No matching provider available"

  defp get_user!("github", token), do: OAuth2.AccessToken.get!(token, "/user")
  defp get_user!("google", token) do
    %{access_token: access_token, other_params: %{"id_token" => id_token} } = token
    OAuth2.AccessToken.get!(token, "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=#{access_token}")
  end
end


Add params to type

Add params to type

defmodule Farmbot.Firmware.Gcode.Param do
  @moduledoc "Firmware paramaters."

  @doc "Turn a number into a param, or a param into a number."
  @spec parse_param(integer | t) :: t | integer
  def parse_param(0), do: :param_version
  def parse_param(1), do: :param_test
  def parse_param(2), do: :param_config_ok
  def parse_param(3), do: :param_use_eeprom
  def parse_param(4), do: :param_e_stop_on_mov_err
  def parse_param(5), do: :param_mov_nr_retry
  def parse_param(11), do: :movement_timeout_x
  def parse_param(12), do: :movement_timeout_y
  def parse_param(13), do: :movement_timeout_z
  def parse_param(15), do: :movement_keep_active_x
  def parse_param(16), do: :movement_keep_active_y
  def parse_param(17), do: :movement_keep_active_z
  def parse_param(18), do: :movement_home_at_boot_x
  def parse_param(19), do: :movement_home_at_boot_y
  def parse_param(20), do: :movement_home_at_boot_z
  def parse_param(21), do: :movement_invert_endpoints_x
  def parse_param(22), do: :movement_invert_endpoints_y
  def parse_param(23), do: :movement_invert_endpoints_z
  def parse_param(25), do: :movement_enable_endpoints_x
  def parse_param(26), do: :movement_enable_endpoints_y
  def parse_param(27), do: :movement_enable_endpoints_z
  def parse_param(31), do: :movement_invert_motor_x
  def parse_param(32), do: :movement_invert_motor_y
  def parse_param(33), do: :movement_invert_motor_z
  def parse_param(36), do: :movement_secondary_motor_x
  def parse_param(37), do: :movement_secondary_motor_invert_x
  def parse_param(41), do: :movement_steps_acc_dec_x
  def parse_param(42), do: :movement_steps_acc_dec_y
  def parse_param(43), do: :movement_steps_acc_dec_z
  def parse_param(45), do: :movement_stop_at_home_x
  def parse_param(46), do: :movement_stop_at_home_y
  def parse_param(47), do: :movement_stop_at_home_z
  def parse_param(51), do: :movement_home_up_x
  def parse_param(52), do: :movement_home_up_y
  def parse_param(53), do: :movement_home_up_z
  def parse_param(55), do: :movement_step_per_mm_x
  def parse_param(56), do: :movement_step_per_mm_y
  def parse_param(57), do: :movement_step_per_mm_z
  def parse_param(61), do: :movement_min_spd_x
  def parse_param(62), do: :movement_min_spd_y
  def parse_param(63), do: :movement_min_spd_z
  def parse_param(65), do: :movement_home_spd_x
  def parse_param(66), do: :movement_home_spd_y
  def parse_param(67), do: :movement_home_spd_z
  def parse_param(71), do: :movement_max_spd_x
  def parse_param(72), do: :movement_max_spd_y
  def parse_param(73), do: :movement_max_spd_z
  def parse_param(75), do: :movement_invert_2_endpoints_x
  def parse_param(76), do: :movement_invert_2_endpoints_y
  def parse_param(77), do: :movement_invert_2_endpoints_z
  def parse_param(101), do: :encoder_enabled_x
  def parse_param(102), do: :encoder_enabled_y
  def parse_param(103), do: :encoder_enabled_z
  def parse_param(105), do: :encoder_type_x
  def parse_param(106), do: :encoder_type_y
  def parse_param(107), do: :encoder_type_z
  def parse_param(111), do: :encoder_missed_steps_max_x
  def parse_param(112), do: :encoder_missed_steps_max_y
  def parse_param(113), do: :encoder_missed_steps_max_z
  def parse_param(115), do: :encoder_scaling_x
  def parse_param(116), do: :encoder_scaling_y
  def parse_param(117), do: :encoder_scaling_z
  def parse_param(121), do: :encoder_missed_steps_decay_x
  def parse_param(122), do: :encoder_missed_steps_decay_y
  def parse_param(123), do: :encoder_missed_steps_decay_z
  def parse_param(125), do: :encoder_use_for_pos_x
  def parse_param(126), do: :encoder_use_for_pos_y
  def parse_param(127), do: :encoder_use_for_pos_z
  def parse_param(131), do: :encoder_invert_x
  def parse_param(132), do: :encoder_invert_y
  def parse_param(133), do: :encoder_invert_z
  def parse_param(141), do: :movement_axis_nr_steps_x
  def parse_param(142), do: :movement_axis_nr_steps_y
  def parse_param(143), do: :movement_axis_nr_steps_z
  def parse_param(145), do: :movement_stop_at_max_x
  def parse_param(146), do: :movement_stop_at_max_y
  def parse_param(147), do: :movement_stop_at_max_z
  def parse_param(201), do: :pin_guard_1_pin_nr
  def parse_param(202), do: :pin_guard_1_time_out
  def parse_param(203), do: :pin_guard_1_active_state
  def parse_param(205), do: :pin_guard_2_pin_nr
  def parse_param(206), do: :pin_guard_2_time_out
  def parse_param(207), do: :pin_guard_2_active_state
  def parse_param(211), do: :pin_guard_3_pin_nr
  def parse_param(212), do: :pin_guard_3_time_out
  def parse_param(213), do: :pin_guard_3_active_state
  def parse_param(215), do: :pin_guard_4_pin_nr
  def parse_param(216), do: :pin_guard_4_time_out
  def parse_param(217), do: :pin_guard_4_active_state
  def parse_param(221), do: :pin_guard_5_pin_nr
  def parse_param(222), do: :pin_guard_5_time_out
  def parse_param(223), do: :pin_guard_5_active_state

  def parse_param(:param_version), do: 0
  def parse_param(:param_test), do: 1
  def parse_param(:param_config_ok), do: 2
  def parse_param(:param_use_eeprom), do: 3
  def parse_param(:param_e_stop_on_mov_err), do: 4
  def parse_param(:param_mov_nr_retry), do: 5
  def parse_param(:movement_timeout_x), do: 11
  def parse_param(:movement_timeout_y), do: 12
  def parse_param(:movement_timeout_z), do: 13
  def parse_param(:movement_keep_active_x), do: 15
  def parse_param(:movement_keep_active_y), do: 16
  def parse_param(:movement_keep_active_z), do: 17
  def parse_param(:movement_home_at_boot_x), do: 18
  def parse_param(:movement_home_at_boot_y), do: 19
  def parse_param(:movement_home_at_boot_z), do: 20
  def parse_param(:movement_invert_endpoints_x), do: 21
  def parse_param(:movement_invert_endpoints_y), do: 22
  def parse_param(:movement_invert_endpoints_z), do: 23
  def parse_param(:movement_enable_endpoints_x), do: 25
  def parse_param(:movement_enable_endpoints_y), do: 26
  def parse_param(:movement_enable_endpoints_z), do: 27
  def parse_param(:movement_invert_motor_x), do: 31
  def parse_param(:movement_invert_motor_y), do: 32
  def parse_param(:movement_invert_motor_z), do: 33
  def parse_param(:movement_secondary_motor_x), do: 36
  def parse_param(:movement_secondary_motor_invert_x), do: 37
  def parse_param(:movement_steps_acc_dec_x), do: 41
  def parse_param(:movement_steps_acc_dec_y), do: 42
  def parse_param(:movement_steps_acc_dec_z), do: 43
  def parse_param(:movement_stop_at_home_x), do: 45
  def parse_param(:movement_stop_at_home_y), do: 46
  def parse_param(:movement_stop_at_home_z), do: 47
  def parse_param(:movement_home_up_x), do: 51
  def parse_param(:movement_home_up_y), do: 52
  def parse_param(:movement_home_up_z), do: 53
  def parse_param(:movement_step_per_mm_x), do: 55
  def parse_param(:movement_step_per_mm_y), do: 56
  def parse_param(:movement_step_per_mm_z), do: 57
  def parse_param(:movement_min_spd_x), do: 61
  def parse_param(:movement_min_spd_y), do: 62
  def parse_param(:movement_min_spd_z), do: 63
  def parse_param(:movement_home_spd_x), do: 65
  def parse_param(:movement_home_spd_y), do: 66
  def parse_param(:movement_home_spd_z), do: 67
  def parse_param(:movement_max_spd_x), do: 71
  def parse_param(:movement_max_spd_y), do: 72
  def parse_param(:movement_max_spd_z), do: 73
  def parse_param(:movement_invert_2_endpoints_x), do: 75
  def parse_param(:movement_invert_2_endpoints_y), do: 76
  def parse_param(:movement_invert_2_endpoints_z), do: 77
  def parse_param(:encoder_enabled_x), do: 101
  def parse_param(:encoder_enabled_y), do: 102
  def parse_param(:encoder_enabled_z), do: 103
  def parse_param(:encoder_type_x), do: 105
  def parse_param(:encoder_type_y), do: 106
  def parse_param(:encoder_type_z), do: 107
  def parse_param(:encoder_missed_steps_max_x), do: 111
  def parse_param(:encoder_missed_steps_max_y), do: 112
  def parse_param(:encoder_missed_steps_max_z), do: 113
  def parse_param(:encoder_scaling_x), do: 115
  def parse_param(:encoder_scaling_y), do: 116
  def parse_param(:encoder_scaling_z), do: 117
  def parse_param(:encoder_missed_steps_decay_x), do: 121
  def parse_param(:encoder_missed_steps_decay_y), do: 122
  def parse_param(:encoder_missed_steps_decay_z), do: 123
  def parse_param(:encoder_use_for_pos_x), do: 125
  def parse_param(:encoder_use_for_pos_y), do: 126
  def parse_param(:encoder_use_for_pos_z), do: 127
  def parse_param(:encoder_invert_x), do: 131
  def parse_param(:encoder_invert_y), do: 132
  def parse_param(:encoder_invert_z), do: 133
  def parse_param(:movement_axis_nr_steps_x), do: 141
  def parse_param(:movement_axis_nr_steps_y), do: 142
  def parse_param(:movement_axis_nr_steps_z), do: 143
  def parse_param(:movement_stop_at_max_x), do: 145
  def parse_param(:movement_stop_at_max_y), do: 146
  def parse_param(:movement_stop_at_max_z), do: 147
  def parse_param(:pin_guard_1_pin_nr), do: 201
  def parse_param(:pin_guard_1_time_out), do: 202
  def parse_param(:pin_guard_1_active_state), do: 203
  def parse_param(:pin_guard_2_pin_nr), do: 205
  def parse_param(:pin_guard_2_time_out), do: 206
  def parse_param(:pin_guard_2_active_state), do: 207
  def parse_param(:pin_guard_3_pin_nr), do: 211
  def parse_param(:pin_guard_3_time_out), do: 212
  def parse_param(:pin_guard_3_active_state), do: 213
  def parse_param(:pin_guard_4_pin_nr), do: 215
  def parse_param(:pin_guard_4_time_out), do: 216
  def parse_param(:pin_guard_4_active_state), do: 217
  def parse_param(:pin_guard_5_pin_nr), do: 221
  def parse_param(:pin_guard_5_time_out), do: 222
  def parse_param(:pin_guard_5_active_state), do: 223

  @typedoc "Human readable param name."
  @type t :: :param_config_ok |
  :param_use_eeprom |
  :param_e_stop_on_mov_err |
  :param_mov_nr_retry |
  :movement_timeout_x |
  :movement_timeout_y |
  :movement_timeout_z |
  :movement_keep_active_x |
  :movement_keep_active_y |
  :movement_keep_active_z |
  :movement_home_at_boot_x |
  :movement_home_at_boot_y |
  :movement_home_at_boot_z |
  :movement_invert_endpoints_x |
  :movement_invert_endpoints_y |
  :movement_invert_endpoints_z |
  :movement_enable_endpoints_x |
  :movement_enable_endpoints_y |
  :movement_enable_endpoints_z |
  :movement_invert_motor_x |
  :movement_invert_motor_y |
  :movement_invert_motor_z |
  :movement_secondary_motor_x |
  :movement_secondary_motor_invert_x |
  :movement_steps_acc_dec_x |
  :movement_steps_acc_dec_y |
  :movement_steps_acc_dec_z |
  :movement_stop_at_home_x |
  :movement_stop_at_home_y |
  :movement_stop_at_home_z |
  :movement_home_up_x |
  :movement_home_up_y |
  :movement_home_up_z |
  :movement_step_per_mm_x |
  :movement_step_per_mm_y |
  :movement_step_per_mm_z |
  :movement_min_spd_x |
  :movement_min_spd_y |
  :movement_min_spd_z |
  :movement_home_spd_x |
  :movement_home_spd_y |
  :movement_home_spd_z |
  :movement_max_spd_x |
  :movement_max_spd_y |
  :movement_max_spd_z |
  :movement_invert_2_endpoints_x |
  :movement_invert_2_endpoints_y |
  :movement_invert_2_endpoints_z |
  :encoder_enabled_x |
  :encoder_enabled_y |
  :encoder_enabled_z |
  :encoder_type_x |
  :encoder_type_y |
  :encoder_type_z |
  :encoder_missed_steps_max_x |
  :encoder_missed_steps_max_y |
  :encoder_missed_steps_max_z |
  :encoder_scaling_x |
  :encoder_scaling_y |
  :encoder_scaling_z |
  :encoder_missed_steps_decay_x |
  :encoder_missed_steps_decay_y |
  :encoder_missed_steps_decay_z |
  :encoder_use_for_pos_x |
  :encoder_use_for_pos_y |
  :encoder_use_for_pos_z |
  :encoder_invert_x |
  :encoder_invert_y |
  :encoder_invert_z |
  :movement_axis_nr_steps_x |
  :movement_axis_nr_steps_y |
  :movement_axis_nr_steps_z |
  :movement_stop_at_max_x |
  :movement_stop_at_max_y |
  :movement_stop_at_max_z |
  :pin_guard_1_pin_nr |
  :pin_guard_1_time_out |
  :pin_guard_1_active_state |
  :pin_guard_2_pin_nr |
  :pin_guard_2_time_out |
  :pin_guard_2_active_state |
  :pin_guard_3_pin_nr |
  :pin_guard_3_time_out |
  :pin_guard_3_active_state |
  :pin_guard_4_pin_nr |
  :pin_guard_4_time_out |
  :pin_guard_4_active_state |
  :pin_guard_5_pin_nr |
  :pin_guard_5_time_out |
  :pin_guard_5_active_state

end

defmodule Farmbot.Firmware.Gcode.Param do
  @moduledoc "Firmware paramaters."

  @doc "Turn a number into a param, or a param into a number."
  @spec parse_param(integer | t) :: t | integer
  def parse_param(0), do: :param_version
  def parse_param(1), do: :param_test
  def parse_param(2), do: :param_config_ok
  def parse_param(3), do: :param_use_eeprom
  def parse_param(4), do: :param_e_stop_on_mov_err
  def parse_param(5), do: :param_mov_nr_retry
  def parse_param(11), do: :movement_timeout_x
  def parse_param(12), do: :movement_timeout_y
  def parse_param(13), do: :movement_timeout_z
  def parse_param(15), do: :movement_keep_active_x
  def parse_param(16), do: :movement_keep_active_y
  def parse_param(17), do: :movement_keep_active_z
  def parse_param(18), do: :movement_home_at_boot_x
  def parse_param(19), do: :movement_home_at_boot_y
  def parse_param(20), do: :movement_home_at_boot_z
  def parse_param(21), do: :movement_invert_endpoints_x
  def parse_param(22), do: :movement_invert_endpoints_y
  def parse_param(23), do: :movement_invert_endpoints_z
  def parse_param(25), do: :movement_enable_endpoints_x
  def parse_param(26), do: :movement_enable_endpoints_y
  def parse_param(27), do: :movement_enable_endpoints_z
  def parse_param(31), do: :movement_invert_motor_x
  def parse_param(32), do: :movement_invert_motor_y
  def parse_param(33), do: :movement_invert_motor_z
  def parse_param(36), do: :movement_secondary_motor_x
  def parse_param(37), do: :movement_secondary_motor_invert_x
  def parse_param(41), do: :movement_steps_acc_dec_x
  def parse_param(42), do: :movement_steps_acc_dec_y
  def parse_param(43), do: :movement_steps_acc_dec_z
  def parse_param(45), do: :movement_stop_at_home_x
  def parse_param(46), do: :movement_stop_at_home_y
  def parse_param(47), do: :movement_stop_at_home_z
  def parse_param(51), do: :movement_home_up_x
  def parse_param(52), do: :movement_home_up_y
  def parse_param(53), do: :movement_home_up_z
  def parse_param(55), do: :movement_step_per_mm_x
  def parse_param(56), do: :movement_step_per_mm_y
  def parse_param(57), do: :movement_step_per_mm_z
  def parse_param(61), do: :movement_min_spd_x
  def parse_param(62), do: :movement_min_spd_y
  def parse_param(63), do: :movement_min_spd_z
  def parse_param(65), do: :movement_home_spd_x
  def parse_param(66), do: :movement_home_spd_y
  def parse_param(67), do: :movement_home_spd_z
  def parse_param(71), do: :movement_max_spd_x
  def parse_param(72), do: :movement_max_spd_y
  def parse_param(73), do: :movement_max_spd_z
  def parse_param(75), do: :movement_invert_2_endpoints_x
  def parse_param(76), do: :movement_invert_2_endpoints_y
  def parse_param(77), do: :movement_invert_2_endpoints_z
  def parse_param(101), do: :encoder_enabled_x
  def parse_param(102), do: :encoder_enabled_y
  def parse_param(103), do: :encoder_enabled_z
  def parse_param(105), do: :encoder_type_x
  def parse_param(106), do: :encoder_type_y
  def parse_param(107), do: :encoder_type_z
  def parse_param(111), do: :encoder_missed_steps_max_x
  def parse_param(112), do: :encoder_missed_steps_max_y
  def parse_param(113), do: :encoder_missed_steps_max_z
  def parse_param(115), do: :encoder_scaling_x
  def parse_param(116), do: :encoder_scaling_y
  def parse_param(117), do: :encoder_scaling_z
  def parse_param(121), do: :encoder_missed_steps_decay_x
  def parse_param(122), do: :encoder_missed_steps_decay_y
  def parse_param(123), do: :encoder_missed_steps_decay_z
  def parse_param(125), do: :encoder_use_for_pos_x
  def parse_param(126), do: :encoder_use_for_pos_y
  def parse_param(127), do: :encoder_use_for_pos_z
  def parse_param(131), do: :encoder_invert_x
  def parse_param(132), do: :encoder_invert_y
  def parse_param(133), do: :encoder_invert_z
  def parse_param(141), do: :movement_axis_nr_steps_x
  def parse_param(142), do: :movement_axis_nr_steps_y
  def parse_param(143), do: :movement_axis_nr_steps_z
  def parse_param(145), do: :movement_stop_at_max_x
  def parse_param(146), do: :movement_stop_at_max_y
  def parse_param(147), do: :movement_stop_at_max_z
  def parse_param(201), do: :pin_guard_1_pin_nr
  def parse_param(202), do: :pin_guard_1_time_out
  def parse_param(203), do: :pin_guard_1_active_state
  def parse_param(205), do: :pin_guard_2_pin_nr
  def parse_param(206), do: :pin_guard_2_time_out
  def parse_param(207), do: :pin_guard_2_active_state
  def parse_param(211), do: :pin_guard_3_pin_nr
  def parse_param(212), do: :pin_guard_3_time_out
  def parse_param(213), do: :pin_guard_3_active_state
  def parse_param(215), do: :pin_guard_4_pin_nr
  def parse_param(216), do: :pin_guard_4_time_out
  def parse_param(217), do: :pin_guard_4_active_state
  def parse_param(221), do: :pin_guard_5_pin_nr
  def parse_param(222), do: :pin_guard_5_time_out
  def parse_param(223), do: :pin_guard_5_active_state

  def parse_param(:param_version), do: 0
  def parse_param(:param_test), do: 1
  def parse_param(:param_config_ok), do: 2
  def parse_param(:param_use_eeprom), do: 3
  def parse_param(:param_e_stop_on_mov_err), do: 4
  def parse_param(:param_mov_nr_retry), do: 5
  def parse_param(:movement_timeout_x), do: 11
  def parse_param(:movement_timeout_y), do: 12
  def parse_param(:movement_timeout_z), do: 13
  def parse_param(:movement_keep_active_x), do: 15
  def parse_param(:movement_keep_active_y), do: 16
  def parse_param(:movement_keep_active_z), do: 17
  def parse_param(:movement_home_at_boot_x), do: 18
  def parse_param(:movement_home_at_boot_y), do: 19
  def parse_param(:movement_home_at_boot_z), do: 20
  def parse_param(:movement_invert_endpoints_x), do: 21
  def parse_param(:movement_invert_endpoints_y), do: 22
  def parse_param(:movement_invert_endpoints_z), do: 23
  def parse_param(:movement_enable_endpoints_x), do: 25
  def parse_param(:movement_enable_endpoints_y), do: 26
  def parse_param(:movement_enable_endpoints_z), do: 27
  def parse_param(:movement_invert_motor_x), do: 31
  def parse_param(:movement_invert_motor_y), do: 32
  def parse_param(:movement_invert_motor_z), do: 33
  def parse_param(:movement_secondary_motor_x), do: 36
  def parse_param(:movement_secondary_motor_invert_x), do: 37
  def parse_param(:movement_steps_acc_dec_x), do: 41
  def parse_param(:movement_steps_acc_dec_y), do: 42
  def parse_param(:movement_steps_acc_dec_z), do: 43
  def parse_param(:movement_stop_at_home_x), do: 45
  def parse_param(:movement_stop_at_home_y), do: 46
  def parse_param(:movement_stop_at_home_z), do: 47
  def parse_param(:movement_home_up_x), do: 51
  def parse_param(:movement_home_up_y), do: 52
  def parse_param(:movement_home_up_z), do: 53
  def parse_param(:movement_step_per_mm_x), do: 55
  def parse_param(:movement_step_per_mm_y), do: 56
  def parse_param(:movement_step_per_mm_z), do: 57
  def parse_param(:movement_min_spd_x), do: 61
  def parse_param(:movement_min_spd_y), do: 62
  def parse_param(:movement_min_spd_z), do: 63
  def parse_param(:movement_home_spd_x), do: 65
  def parse_param(:movement_home_spd_y), do: 66
  def parse_param(:movement_home_spd_z), do: 67
  def parse_param(:movement_max_spd_x), do: 71
  def parse_param(:movement_max_spd_y), do: 72
  def parse_param(:movement_max_spd_z), do: 73
  def parse_param(:movement_invert_2_endpoints_x), do: 75
  def parse_param(:movement_invert_2_endpoints_y), do: 76
  def parse_param(:movement_invert_2_endpoints_z), do: 77
  def parse_param(:encoder_enabled_x), do: 101
  def parse_param(:encoder_enabled_y), do: 102
  def parse_param(:encoder_enabled_z), do: 103
  def parse_param(:encoder_type_x), do: 105
  def parse_param(:encoder_type_y), do: 106
  def parse_param(:encoder_type_z), do: 107
  def parse_param(:encoder_missed_steps_max_x), do: 111
  def parse_param(:encoder_missed_steps_max_y), do: 112
  def parse_param(:encoder_missed_steps_max_z), do: 113
  def parse_param(:encoder_scaling_x), do: 115
  def parse_param(:encoder_scaling_y), do: 116
  def parse_param(:encoder_scaling_z), do: 117
  def parse_param(:encoder_missed_steps_decay_x), do: 121
  def parse_param(:encoder_missed_steps_decay_y), do: 122
  def parse_param(:encoder_missed_steps_decay_z), do: 123
  def parse_param(:encoder_use_for_pos_x), do: 125
  def parse_param(:encoder_use_for_pos_y), do: 126
  def parse_param(:encoder_use_for_pos_z), do: 127
  def parse_param(:encoder_invert_x), do: 131
  def parse_param(:encoder_invert_y), do: 132
  def parse_param(:encoder_invert_z), do: 133
  def parse_param(:movement_axis_nr_steps_x), do: 141
  def parse_param(:movement_axis_nr_steps_y), do: 142
  def parse_param(:movement_axis_nr_steps_z), do: 143
  def parse_param(:movement_stop_at_max_x), do: 145
  def parse_param(:movement_stop_at_max_y), do: 146
  def parse_param(:movement_stop_at_max_z), do: 147
  def parse_param(:pin_guard_1_pin_nr), do: 201
  def parse_param(:pin_guard_1_time_out), do: 202
  def parse_param(:pin_guard_1_active_state), do: 203
  def parse_param(:pin_guard_2_pin_nr), do: 205
  def parse_param(:pin_guard_2_time_out), do: 206
  def parse_param(:pin_guard_2_active_state), do: 207
  def parse_param(:pin_guard_3_pin_nr), do: 211
  def parse_param(:pin_guard_3_time_out), do: 212
  def parse_param(:pin_guard_3_active_state), do: 213
  def parse_param(:pin_guard_4_pin_nr), do: 215
  def parse_param(:pin_guard_4_time_out), do: 216
  def parse_param(:pin_guard_4_active_state), do: 217
  def parse_param(:pin_guard_5_pin_nr), do: 221
  def parse_param(:pin_guard_5_time_out), do: 222
  def parse_param(:pin_guard_5_active_state), do: 223

  @typedoc "Human readable param name."
  @type t :: :param_config_ok |
  :param_use_eeprom |
  :param_e_stop_on_mov_err |
  :param_mov_nr_retry |
  :movement_timeout_x |
  :movement_timeout_y |
  :movement_timeout_z |
  :movement_keep_active_x |
  :movement_keep_active_y |
  :movement_keep_active_z |
  :movement_home_at_boot_x |
  :movement_home_at_boot_y |
  :movement_home_at_boot_z |
  :movement_invert_endpoints_x |
  :movement_invert_endpoints_y |
  :movement_invert_endpoints_z |
  :movement_enable_endpoints_x |
  :movement_enable_endpoints_y |
  :movement_enable_endpoints_z |
  :movement_invert_motor_x |
  :movement_invert_motor_y |
  :movement_invert_motor_z |
  :movement_secondary_motor_x |
  :movement_secondary_motor_invert_x |
  :movement_steps_acc_dec_x |
  :movement_steps_acc_dec_y |
  :movement_steps_acc_dec_z |
  :movement_stop_at_home_x |
  :movement_stop_at_home_y |
  :movement_stop_at_home_z |
  :movement_home_up_x |
  :movement_home_up_y |
  :movement_home_up_z |
  :movement_step_per_mm_x |
  :movement_step_per_mm_y |
  :movement_step_per_mm_z |
  :movement_min_spd_x |
  :movement_min_spd_y |
  :movement_min_spd_z |
  :movement_home_spd_x |
  :movement_home_spd_y |
  :movement_home_spd_z |
  :movement_max_spd_x |
  :movement_max_spd_y |
  :movement_max_spd_z |
  :encoder_enabled_x |
  :encoder_enabled_y |
  :encoder_enabled_z |
  :encoder_type_x |
  :encoder_type_y |
  :encoder_type_z |
  :encoder_missed_steps_max_x |
  :encoder_missed_steps_max_y |
  :encoder_missed_steps_max_z |
  :encoder_scaling_x |
  :encoder_scaling_y |
  :encoder_scaling_z |
  :encoder_missed_steps_decay_x |
  :encoder_missed_steps_decay_y |
  :encoder_missed_steps_decay_z |
  :encoder_use_for_pos_x |
  :encoder_use_for_pos_y |
  :encoder_use_for_pos_z |
  :encoder_invert_x |
  :encoder_invert_y |
  :encoder_invert_z |
  :movement_axis_nr_steps_x |
  :movement_axis_nr_steps_y |
  :movement_axis_nr_steps_z |
  :movement_stop_at_max_x |
  :movement_stop_at_max_y |
  :movement_stop_at_max_z |
  :pin_guard_1_pin_nr |
  :pin_guard_1_time_out |
  :pin_guard_1_active_state |
  :pin_guard_2_pin_nr |
  :pin_guard_2_time_out |
  :pin_guard_2_active_state |
  :pin_guard_3_pin_nr |
  :pin_guard_3_time_out |
  :pin_guard_3_active_state |
  :pin_guard_4_pin_nr |
  :pin_guard_4_time_out |
  :pin_guard_4_active_state |
  :pin_guard_5_pin_nr |
  :pin_guard_5_time_out |
  :pin_guard_5_active_state

end


Cleaner cli prints

Cleaner cli prints

defmodule Cingi.CLI do
	def main(args) do
		Process.register self(), :local_cli
		args |> parse_args |> process
	end

	def process([]) do
		IO.puts "No arguments given"
	end

	def process(options) do
		Cingi.Branch.link_cli(:local_branch, self())
		mbn = options[:minbranches]
		connect_to = options[:connectto]
		connect_or_headquarters(connect_to, mbn, options)
	end

	def connect_or_headquarters(nil, min_branch_num, options) do
		min_branch_num = min_branch_num || 0
		Cingi.Headquarters.start_link(name: {:global, :hq})
		Cingi.Headquarters.link_branch({:global, :hq}, :local_branch)

		set_up_network(min_branch_num, options)
		wait_for_branches(min_branch_num - 1)
		start_missions(options[:file], options)
	end

	def connect_or_headquarters(host, nil, options) do
		set_up_network(true, options)
		host = String.to_atom host
		wait_for_hq(host)
		Cingi.Headquarters.link_branch({:global, :hq}, :local_branch)
		IO.puts "Connected local branch to global headquarters"
		Process.send({:local_cli, host}, {:branch_connect, self()}, [])

		Node.monitor host, true

		receive_loop = fn(loop) ->
			receive do
				{:branch_outpost_data, data} ->
					print_output(data, options[:printbranchoutput])
					loop.(loop)
				{:nodedown, _} -> :error
				:terminate -> :ok
				_ -> loop.(loop)
			end
		end
		receive_loop.(receive_loop)
	end

	def connect_or_headquarters(_, _, _) do
		raise "Cannot have both connect_to and min_branch_num options"
	end

	def start_missions(nil, _options) do
	end

	def start_missions(file, options) do
		yaml_opts = [file: file, cli_pid: self()]
		report_pid = Cingi.Branch.create_report :local_branch, yaml_opts
		receive_loop = fn(loop) ->
			receive do
				{:branch_report_data, data} ->
					print_output(data, true)
					loop.(loop)
				{:branch_outpost_data, data} ->
					print_output(data, options[:printbranchoutput])
					loop.(loop)
				{:report, ^report_pid} -> Cingi.Headquarters.terminate_branches({:global, :hq})
				_ -> loop.(loop)
			end
		end
		receive_loop.(receive_loop)
	end

	defp parse_args(args) do
		{options, _, _} = OptionParser.parse(args,
			switches: [
				minbranches: :integer,
				file: :string,
				connectto: :string,
				branchoutput: :boolean,
				printbranchoutput: :boolean,
			]
		)
		options
	end

	def wait_for_branches(countdown) do
		case countdown do
			n when n <= 0 -> :ok
			n ->
				IO.puts "Waiting for #{n} branches to connect"
				receive do
					{:branch_connect, _} ->
						IO.puts "branch connected"
						wait_for_branches(n - 1)
				end
		end
	end

	def set_up_network(0, _) do end

	def set_up_network(_, options) do
		case {options[:name], options[:cookie]} do
			{nil, nil} -> raise "Requires name and cookie for networking"
			{nil, _} -> raise "Requires name for networking"
			{_, nil} -> raise "Requires cookie for networking"
			{name, cookie} ->
				Node.start(String.to_atom(name), :shortnames)
				Node.set_cookie(String.to_atom(cookie))
		end
	end

	def wait_for_hq(host, countdown \\ 100) do
		Node.connect(host)
		case GenServer.whereis({:global, :hq}) do
			nil ->
				Process.sleep 100
				case countdown do
					n when n <= 0 -> raise "Took too long connecting to headquarters"
					n -> wait_for_hq(host, n - 1)
				end
			_ -> Cingi.Headquarters.get({:global, :hq})
		end
	end

	def print_output(data, print) do
		print = print || false
		case print do
			false -> :ok
			true ->
				field_agent = Cingi.FieldAgent.get(data[:field_agent_pid])

				data[:data]
					|> String.split("\n")
					|> Enum.map(fn(line) ->
						keys = case field_agent.node do
							:nonode@nohost -> []
							x -> [" #{x} "]
						end

						keys = keys ++ case data[:pid] do
							[] -> []
							[_|_] -> data[:pid]
								|> Enum.map(fn(pid) ->
									key = Cingi.Mission.get(pid).key
									shortened = String.slice(key, 0, 7)
									case shortened == key do
										true -> key
										false -> shortened <> "..."
									end
								end)
						end

						keys = Enum.join(keys, "|")

						"[#{keys}]    #{line}"
					end)
					|> Enum.map(&IO.puts/1)
		end
	end
end

defmodule Cingi.CLI do
	def main(args) do
		Process.register self(), :local_cli
		args |> parse_args |> process
	end

	def process([]) do
		IO.puts "No arguments given"
	end

	def process(options) do
		Cingi.Branch.link_cli(:local_branch, self())
		mbn = options[:minbranches]
		connect_to = options[:connectto]
		connect_or_headquarters(connect_to, mbn, options)
	end

	def connect_or_headquarters(nil, min_branch_num, options) do
		min_branch_num = min_branch_num || 0
		Cingi.Headquarters.start_link(name: {:global, :hq})
		Cingi.Headquarters.link_branch({:global, :hq}, :local_branch)

		set_up_network(min_branch_num, options)
		wait_for_branches(min_branch_num - 1)
		start_missions(options[:file], options)
	end

	def connect_or_headquarters(host, nil, options) do
		set_up_network(true, options)
		host = String.to_atom host
		wait_for_hq(host)
		Cingi.Headquarters.link_branch({:global, :hq}, :local_branch)
		IO.puts "Connected local branch to global headquarters"
		Process.send({:local_cli, host}, {:branch_connect, self()}, [])

		Node.monitor host, true

		receive_loop = fn(loop) ->
			receive do
				{:branch_outpost_data, data} ->
					print_output(data, options[:printbranchoutput])
					loop.(loop)
				{:nodedown, _} -> :error
				:terminate -> :ok
				_ -> loop.(loop)
			end
		end
		receive_loop.(receive_loop)
	end

	def connect_or_headquarters(_, _, _) do
		raise "Cannot have both connect_to and min_branch_num options"
	end

	def start_missions(nil, _options) do
	end

	def start_missions(file, options) do
		yaml_opts = [file: file, cli_pid: self()]
		report_pid = Cingi.Branch.create_report :local_branch, yaml_opts
		receive_loop = fn(loop) ->
			receive do
				{:branch_outpost_data, data} ->
					print_output(data, options[:printbranchoutput])
					loop.(loop)
				{:report, ^report_pid} -> Cingi.Headquarters.terminate_branches({:global, :hq})
				_ -> loop.(loop)
			end
		end
		receive_loop.(receive_loop)
	end

	defp parse_args(args) do
		{options, _, _} = OptionParser.parse(args,
			switches: [
				minbranches: :integer,
				file: :string,
				connectto: :string,
				branchoutput: :boolean,
				printbranchoutput: :boolean,
			]
		)
		options
	end

	def wait_for_branches(countdown) do
		case countdown do
			n when n <= 0 -> :ok
			n ->
				IO.puts "Waiting for #{n} branches to connect"
				receive do
					{:branch_connect, _} ->
						IO.puts "branch connected"
						wait_for_branches(n - 1)
				end
		end
	end

	def set_up_network(0, _) do end

	def set_up_network(_, options) do
		case {options[:name], options[:cookie]} do
			{nil, nil} -> raise "Requires name and cookie for networking"
			{nil, _} -> raise "Requires name for networking"
			{_, nil} -> raise "Requires cookie for networking"
			{name, cookie} ->
				Node.start(String.to_atom(name), :shortnames)
				Node.set_cookie(String.to_atom(cookie))
		end
	end

	def wait_for_hq(host, countdown \\ 100) do
		Node.connect(host)
		case GenServer.whereis({:global, :hq}) do
			nil ->
				Process.sleep 100
				case countdown do
					n when n <= 0 -> raise "Took too long connecting to headquarters"
					n -> wait_for_hq(host, n - 1)
				end
			_ -> Cingi.Headquarters.get({:global, :hq})
		end
	end

	def print_output(data, nil) do
		print_output(data, true)
	end

	def print_output(data, print) do
		case print do
			false -> :ok
			true ->
				field_agent = Cingi.FieldAgent.get(data[:field_agent_pid])

				data[:data]
					|> String.split("\n")
					|> Enum.map(fn(line) ->
						keys = case field_agent.node do
							:nonode@nohost -> []
							x -> [x]
						end

						keys = keys ++ case data[:pid] do
							[] -> []
							[_|_] -> data[:pid] |> Enum.map(&(Cingi.Mission.get(&1).key))
						end

						keys = Enum.join(keys, "|")

						"[#{keys}]    #{line}"
					end)
					|> Enum.map(&IO.puts/1)
		end
	end
end


Add regression test for exceptions in GenServers

defmodule Appsignal.Error.BackendTest do
  use ExUnit.Case, async: true
  import AppsignalTest.Utils
  import ExUnit.CaptureIO
  alias Appsignal.{Error.Backend, Span, Test, Tracer, WrappedNif}

  setup do
    WrappedNif.start_link()
    Test.Tracer.start_link()
    Test.Span.start_link()

    :ok
  end

  test "is added as a Logger backend" do
    assert {:error, :already_present} = Logger.add_backend(Backend)
  end

  describe "handle_event/3, when no span exists" do
    setup do
      [pid: spawn(fn -> raise "Exception" end)]
    end

    test "creates a span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{"", nil, ^pid}]} = Test.Tracer.get(:create_span)
      end)
    end

    test "adds an error to the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}, %RuntimeError{message: "Exception"}, stack}]} =
                 Test.Span.get(:add_error)

        assert is_list(stack)
      end)
    end

    test "closes the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}}]} = Test.Tracer.get(:close_span)
      end)
    end
  end

  describe "handle_event/3, with an open span" do
    setup do
      parent = self()

      pid =
        spawn(fn ->
          span = Tracer.create_span("")
          send(parent, span)
          raise "Exception"
        end)

      span =
        receive do
          span -> span
        end

      [pid: pid, span: span]
    end

    test "adds an error to the existing span", %{span: span} do
      until(fn ->
        assert {:ok, [{^span, %RuntimeError{message: "Exception"}, _stack}]} =
                 Test.Span.get(:add_error)
      end)
    end

    test "closes the existing span", %{span: span, pid: pid} do
      until(fn ->
        assert {:ok, [{^span}]} = Test.Tracer.get(:close_span)
      end)
    end
  end

  describe "handle_event/3, with a :badarg" do
    setup do
      pid =
        spawn(fn ->
          :erlang.error(:badarg)
        end)

      [pid: pid]
    end

    test "creates a span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{"", nil, ^pid}]} = Test.Tracer.get(:create_span)
      end)
    end

    test "adds an error to the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}, %ArgumentError{message: "argument error"}, stack}]} =
                 Test.Span.get(:add_error)

        assert is_list(stack)
      end)
    end

    test "closes the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}}]} = Test.Tracer.get(:close_span)
      end)
    end
  end

  describe "handle_event/3, with a Task" do
    setup do
      parent = self()

      spawn(fn ->
        %Task{pid: pid} =
          Task.async(fn ->
            raise "Exception"
          end)

        send(parent, pid)
      end)

      pid =
        receive do
          pid -> pid
        end

      [pid: pid]
    end

    test "creates a span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{"", nil, ^pid}]} = Test.Tracer.get(:create_span)
      end)
    end

    test "adds an error to the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}, %RuntimeError{message: "Exception"}, stack}]} =
                 Test.Span.get(:add_error)

        assert is_list(stack)
      end)
    end

    test "closes the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}}]} = Test.Tracer.get(:close_span)
      end)
    end
  end

  describe "handle_event/3, with a crashing GenServer" do
    setup do
      defmodule CrashingGenServer do
        use GenServer

        def start_link(_opts) do
          GenServer.start(__MODULE__, [meta: :data], name: Elixir.MyGenServer)
        end

        def init(opts), do: {:ok, opts}

        def handle_cast(:raise_error, state) do
          Map.fetch!(%{}, :bad_key)

          {:noreply, state}
        end
      end

      {:ok, pid} = start_supervised(CrashingGenServer)

      GenServer.cast(pid, :raise_error)

      [pid: pid]
    end

    test "creates a span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{"", nil, ^pid}]} = Test.Tracer.get(:create_span)
      end)
    end

    test "adds an error to the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}, %KeyError{}, stack}]} = Test.Span.get(:add_error)

        assert is_list(stack)
      end)
    end

    test "closes the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}}]} = Test.Tracer.get(:close_span)
      end)
    end
  end
end

defmodule Appsignal.Error.BackendTest do
  use ExUnit.Case, async: true
  import AppsignalTest.Utils
  import ExUnit.CaptureIO
  alias Appsignal.{Error.Backend, Span, Test, Tracer, WrappedNif}

  setup do
    WrappedNif.start_link()
    Test.Tracer.start_link()
    Test.Span.start_link()

    :ok
  end

  test "is added as a Logger backend" do
    assert {:error, :already_present} = Logger.add_backend(Backend)
  end

  describe "handle_event/3, when no span exists" do
    setup do
      [pid: spawn(fn -> raise "Exception" end)]
    end

    test "creates a span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{"", nil, ^pid}]} = Test.Tracer.get(:create_span)
      end)
    end

    test "adds an error to the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}, %RuntimeError{message: "Exception"}, stack}]} =
                 Test.Span.get(:add_error)

        assert is_list(stack)
      end)
    end

    test "closes the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}}]} = Test.Tracer.get(:close_span)
      end)
    end
  end

  describe "handle_event/3, with an open span" do
    setup do
      parent = self()

      pid =
        spawn(fn ->
          span = Tracer.create_span("")
          send(parent, span)
          raise "Exception"
        end)

      span =
        receive do
          span -> span
        end

      [pid: pid, span: span]
    end

    test "adds an error to the existing span", %{span: span} do
      until(fn ->
        assert {:ok, [{^span, %RuntimeError{message: "Exception"}, _stack}]} =
                 Test.Span.get(:add_error)
      end)
    end

    test "closes the existing span", %{span: span, pid: pid} do
      until(fn ->
        assert {:ok, [{^span}]} = Test.Tracer.get(:close_span)
      end)
    end
  end

  describe "handle_event/3, with a :badarg" do
    setup do
      pid =
        spawn(fn ->
          :erlang.error(:badarg)
        end)

      [pid: pid]
    end

    test "creates a span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{"", nil, ^pid}]} = Test.Tracer.get(:create_span)
      end)
    end

    test "adds an error to the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}, %ArgumentError{message: "argument error"}, stack}]} =
                 Test.Span.get(:add_error)

        assert is_list(stack)
      end)
    end

    test "closes the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}}]} = Test.Tracer.get(:close_span)
      end)
    end
  end

  describe "handle_event/3, with a Task" do
    setup do
      parent = self()

      spawn(fn ->
        %Task{pid: pid} =
          Task.async(fn ->
            raise "Exception"
          end)

        send(parent, pid)
      end)

      pid =
        receive do
          pid -> pid
        end

      [pid: pid]
    end

    test "creates a span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{"", nil, ^pid}]} = Test.Tracer.get(:create_span)
      end)
    end

    test "adds an error to the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}, %RuntimeError{message: "Exception"}, stack}]} =
                 Test.Span.get(:add_error)

        assert is_list(stack)
      end)
    end

    test "closes the created span", %{pid: pid} do
      until(fn ->
        assert {:ok, [{%Span{}}]} = Test.Tracer.get(:close_span)
      end)
    end
  end
end


ecto, all fields are required

ecto, all fields are required

defmodule FunWithFlags.Store.Persistent.Ecto.Record do
  @moduledoc false
  use Ecto.Schema
  import Ecto.Changeset

  schema "fun_with_flags_toggles" do
    field :flag_name, :string
    field :gate_type, :string
    field :target, :string
    field :enabled, :boolean
  end

  @fields [:flag_name, :gate_type, :target, :enabled]

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @fields)
    |> validate_required(@fields)
    |> unique_constraint(
        :gate_type,
        name: "fwf_flag_name_gate_target_idx",
        message: "Can't store a duplicated gate."
      )
  end

  def build(flag_name, gate) do
    data = %{
      flag_name: to_string(flag_name),
      gate_type: to_string(gate.type),
      target: serialize_target(gate.for),
      enabled: gate.enabled
    }
    changeset(%__MODULE__{}, data)
  end

  # Do not just store NULL for `target: nil`, because the unique
  # index in the table does not see NULL values as equal.
  #
  def serialize_target(nil), do: "_fwf_none"
  def serialize_target(str) when is_binary(str), do: str
  def serialize_target(atm) when is_atom(atm), do: to_string(atm)

end

defmodule FunWithFlags.Store.Persistent.Ecto.Record do
  @moduledoc false
  use Ecto.Schema
  import Ecto.Changeset

  schema "fun_with_flags_toggles" do
    field :flag_name, :string
    field :gate_type, :string
    field :target, :string
    field :enabled, :boolean
  end

  @fields [:flag_name, :gate_type, :target, :enabled]
  @required_fields [:flag_name, :gate_type, :enabled]

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @fields)
    |> validate_required(@required_fields)
    |> unique_constraint(
        :gate_type,
        name: "fwf_flag_name_gate_target_idx",
        message: "Can't store a duplicated gate."
      )
  end

  def build(flag_name, gate) do
    data = %{
      flag_name: to_string(flag_name),
      gate_type: to_string(gate.type),
      target: serialize_target(gate.for),
      enabled: gate.enabled
    }
    changeset(%__MODULE__{}, data)
  end

  # Do not just store NULL for `target: nil`, because the unique
  # index in the table does not see NULL values as equal.
  #
  def serialize_target(nil), do: "_fwf_none"
  def serialize_target(str) when is_binary(str), do: str
  def serialize_target(atm) when is_atom(atm), do: to_string(atm)

end


One more time URL

One more time URL

use Mix.Config

version =
  Path.join(__DIR__, "VERSION")
  |> File.read!
  |> String.strip

config :nerves_system_nanopi_neo, :nerves_env,
  type: :system,
  version: version,
  compiler: :nerves_package,
  artifact_url: ["https://github.com/dhanson358/nerves_system_nanopi_neo/releases/download/v0.0.14a/nerves_system_nanopi_neo_014.tar.gz"],
  platform: Nerves.System.BR,
  platform_config: [
   defconfig: "nerves_defconfig",
  ],
  checksum: [
      "busybox_defconfig",
      "rootfs-additions",
      "fwup.conf",
      "post-createfs.sh",
      "uboot",
      "uboot-script.cmd",
      "linux",
      "VERSION"
  ]

use Mix.Config

version =
  Path.join(__DIR__, "VERSION")
  |> File.read!
  |> String.strip

config :nerves_system_nanopi_neo, :nerves_env,
  type: :system,
  version: version,
  compiler: :nerves_package,
  artifact_url: ["https://github.com/dhanson358/nerves_system_nanopi_neo/releases/download/v0.0.14b/nerves_system_nanopi_neo_014.tar.gz"],
  platform: Nerves.System.BR,
  platform_config: [
   defconfig: "nerves_defconfig",
  ],
  checksum: [
      "busybox_defconfig",
      "rootfs-additions",
      "fwup.conf",
      "post-createfs.sh",
      "uboot",
      "uboot-script.cmd",
      "linux",
      "VERSION"
  ]


Remove duplicate alias

Remove duplicate alias

defmodule Worker do
  require Logger
  alias Services.IdaiFieldDb
  alias Enricher.Enricher

  def process do

    Indexer.update_mapping_template()

    for db <- Core.Config.get(:couchdb_databases) do
      pid = spawn_link fn -> process_db(db) end
      Logger.info "Spawned indexer #{inspect pid} for #{db}"
    end
  end

  def process_db(db) do
    IdaiFieldDb.fetch_changes(db)
    |> Enum.map(Mapper.process)
    |> log_finished("mapping", db)
    |> Enum.map(Enricher.process(db, IdaiFieldDb.get_doc(db)))
    |> log_finished("enriching", db)
    |> Enum.map(Indexer.process(db))
    |> log_finished("indexing", db)
  end

  def log_finished(change, step, db) do
    Logger.info "Finished #{step} #{db}"
    change
  end
end

defmodule Worker do
  require Logger
  alias Services.IdaiFieldDb
  alias Enricher.Enricher
  alias Services.IdaiFieldDb

  def process do

    Indexer.update_mapping_template()

    for db <- Core.Config.get(:couchdb_databases) do
      pid = spawn_link fn -> process_db(db) end
      Logger.info "Spawned indexer #{inspect pid} for #{db}"
    end
  end

  def process_db(db) do
    IdaiFieldDb.fetch_changes(db)
    |> Enum.map(Mapper.process)
    |> log_finished("mapping", db)
    |> Enum.map(Enricher.process(db, IdaiFieldDb.get_doc(db)))
    |> log_finished("enriching", db)
    |> Enum.map(Indexer.process(db))
    |> log_finished("indexing", db)
  end

  def log_finished(change, step, db) do
    Logger.info "Finished #{step} #{db}"
    change
  end
end


Version bump translate 0.0.3 (#46)

Version bump translate 0.0.3 (#46)

defmodule GoogleApi.Translate.V2.Mixfile do
  use Mix.Project

  @version "0.0.3"

  def project() do
    [
      app: :google_api_translate,
      version: @version,
      elixir: "~> 1.4",
      build_embedded: Mix.env == :prod,
      start_permanent: Mix.env == :prod,
      description: description(),
      package: package(),
      deps: deps(),
      source_url: "https://github.com/GoogleCloudPlatform/elixir-google-api/tree/master/clients/translate"
    ]
  end

  def application() do
    [extra_applications: [:logger]]
  end

  defp deps() do
    [
      {:tesla, "~> 0.5"},
      {:poison, ">= 1.0.0"},
      {:ex_doc, "~> 0.16", only: :dev},
      {:goth, "~> 0.4.0", only: [:dev, :test]}
    ]
  end

  defp description() do
    """
    The Google Cloud Translation API lets websites and programs integrate with
    Google Translate programmatically.
    """
  end

  defp package() do
    [
      files: ["lib", "mix.exs", "README*", "LICENSE"],
      maintainers: ["Jeff Ching"],
      licenses: ["Apache 2.0"],
      links: %{
        "GitHub" => "https://github.com/GoogleCloudPlatform/elixir-google-api/tree/master/clients/translate",
        "Homepage" => "https://cloud.google.com/translate/"
      }
    ]
  end
end

defmodule GoogleApi.Translate.V2.Mixfile do
  use Mix.Project

  @version "0.0.2"

  def project() do
    [
      app: :google_api_translate,
      version: @version,
      elixir: "~> 1.4",
      build_embedded: Mix.env == :prod,
      start_permanent: Mix.env == :prod,
      description: description(),
      package: package(),
      deps: deps(),
      source_url: "https://github.com/GoogleCloudPlatform/elixir-google-api/tree/master/clients/translate"
    ]
  end

  def application() do
    [extra_applications: [:logger]]
  end

  defp deps() do
    [
      {:tesla, "~> 0.5"},
      {:poison, ">= 1.0.0"},
      {:ex_doc, "~> 0.16", only: :dev},
      {:goth, "~> 0.4.0", only: [:dev, :test]}
    ]
  end

  defp description() do
    """
    The Google Cloud Translation API lets websites and programs integrate with
    Google Translate programmatically.
    """
  end

  defp package() do
    [
      files: ["lib", "mix.exs", "README*", "LICENSE"],
      maintainers: ["Jeff Ching"],
      licenses: ["Apache 2.0"],
      links: %{
        "GitHub" => "https://github.com/GoogleCloudPlatform/elixir-google-api/tree/master/clients/translate",
        "Homepage" => "https://cloud.google.com/translate/"
      }
    ]
  end
end


redirect to /events

redirect to /events

defmodule Admin.AuthController do
  use Admin, :controller
  plug Ueberauth

  alias Guardian.Plug
  alias Admin.{Repo}

  def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
    case authenticate(auth) do
      {:ok, user} ->
        conn = Plug.sign_in(conn, user)

        conn
        |> redirect(to: "/events")
      {:error, email} when is_binary(email) ->
        json conn, %{error: "Use your JD email #{email}!"}
    end
  end

  def index(conn, _params) do
    redirect conn, to: "/auth/google"
  end

  def delete(conn, _params) do
    conn
    |> Plug.sign_out
    |> put_flash(:info, "Signed out")
    |> redirect(to: "/")
  end

  defp authenticate(%{info: info, uid: uid}) do
    email = Map.get(info, :email)

    case String.match?(email, ~r/@justicedemocrats.com$/) do
      true ->
        {:ok, %{email: email, google_id: uid}}
      _ ->
        {:error, email}
    end
  end
end

defmodule Admin.AuthController do
  use Admin, :controller
  plug Ueberauth

  alias Guardian.Plug
  alias Admin.{Repo}

  def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
    case authenticate(auth) do
      {:ok, user} ->
        conn = Plug.sign_in(conn, user)

        conn
        |> redirect(to: "/esm")
      {:error, email} when is_binary(email) ->
        json conn, %{error: "Use your JD email #{email}!"}
    end
  end

  def index(conn, _params) do
    redirect conn, to: "/auth/google"
  end

  def delete(conn, _params) do
    conn
    |> Plug.sign_out
    |> put_flash(:info, "Signed out")
    |> redirect(to: "/")
  end

  defp authenticate(%{info: info, uid: uid}) do
    email = Map.get(info, :email)

    case String.match?(email, ~r/@justicedemocrats.com$/) do
      true ->
        {:ok, %{email: email, google_id: uid}}
      _ ->
        {:error, email}
    end
  end
end


Fix Power and Temp mappings

Fix Power and Temp mappings

defmodule Thermio.AirconController do
  use Thermio.Web, :controller

  alias Thermio.Aircon

  def index(conn, _params) do
    aircon =
      Thermio.Aircon
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one

    render(conn, "show.json", aircon: aircon)
  end

  def set_aircon(params) do
    aircon =
      Thermio.Aircon
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one
      |> Kernel.||(%{
        power: 0,
        mode: 3,
        fan: 0,
        temp: 24,
        v_dir: 0,
        h_dir: 0
      })

    intitial_state = %{
      "power" => aircon.power,
      "mode" => aircon.mode,
      "fan" => aircon.fan,
      "temp" => aircon.temp,
      "v_dir" => aircon.v_dir,
      "h_dir" => aircon.h_dir
    }

    changeset_params =
      intitial_state
      |> Map.merge(params)

    changeset = Aircon.changeset(%Aircon{}, changeset_params)

    mqtt_payload =
      changeset_params
      |> Map.merge(%{"type" => "set"})
      |> ProperCase.to_camel_case
      |> Poison.encode!

    Thermio.MqttClient.publish_message("heatpump", mqtt_payload)

    Repo.insert(changeset)
  end

  def handle_dialogflow(conn, %{"result" => %{"action" => "input.welcome"}}) do
    %{heat_index: heat_index} =
      Thermio.Climate
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one

    aircon =
      Thermio.Aircon
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one

    conn
    |> put_status(:ok)
    |> render(Thermio.DialogflowView, "summary.json", %{aircon: aircon, heat_index: heat_index})
  end

  def handle_dialogflow(conn, %{"result" => %{"action" => "ac.setting", "parameters" => %{
    "mode" => mode,
    "temp" => temp,
    "power" => power
  }}}) do
    modes = %{
      "auto" => 1,
      "heat" => 2,
      "cool" => 3,
      "dry" => 4,
      "fan" => 5
    }

    power = if (power == "off"), do: 0, else: 1
    temp = if (temp == "" || !temp), do: 24, else: temp

    params = %{
      "mode" => modes[mode] || 3,
      "power" => power,
      "temp" => temp
    }

    case set_aircon(params) do
      {:ok, aircon} ->
        conn
        |> put_status(:created)
        |> put_resp_header("location", aircon_path(conn, :show, aircon))
        |> render(Thermio.DialogflowView, "update.json", aircon: aircon)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(Thermio.ChangesetView, "error.json", changeset: changeset)
    end
  end

  def create(conn, params) do
    case set_aircon(params) do
      {:ok, aircon} ->
        conn
        |> put_status(:created)
        |> put_resp_header("location", aircon_path(conn, :show, aircon))
        |> render("show.json", aircon: aircon)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(Thermio.ChangesetView, "error.json", changeset: changeset)
    end
  end

  def show(conn, %{"id" => id}) do
    aircon = Repo.get!(Aircon, id)
    render(conn, "show.json", aircon: aircon)
  end

  def update(conn, %{"id" => id, "aircon" => aircon_params}) do
    aircon = Repo.get!(Aircon, id)
    changeset = Aircon.changeset(aircon, aircon_params)

    case Repo.update(changeset) do
      {:ok, aircon} ->
        render(conn, "show.json", aircon: aircon)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(Thermio.ChangesetView, "error.json", changeset: changeset)
    end
  end

  def delete(conn, %{"id" => id}) do
    aircon = Repo.get!(Aircon, id)

    # Here we use delete! (with a bang) because we expect
    # it to always work (and if it does not, it will raise).
    Repo.delete!(aircon)

    send_resp(conn, :no_content, "")
  end
end

defmodule Thermio.AirconController do
  use Thermio.Web, :controller

  alias Thermio.Aircon

  def index(conn, _params) do
    aircon =
      Thermio.Aircon
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one

    render(conn, "show.json", aircon: aircon)
  end

  def set_aircon(params) do
    aircon =
      Thermio.Aircon
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one
      |> Kernel.||(%{
        power: 0,
        mode: 3,
        fan: 0,
        temp: 24,
        v_dir: 0,
        h_dir: 0
      })

    intitial_state = %{
      "power" => aircon.power,
      "mode" => aircon.mode,
      "fan" => aircon.fan,
      "temp" => aircon.temp,
      "v_dir" => aircon.v_dir,
      "h_dir" => aircon.h_dir
    }

    changeset_params =
      intitial_state
      |> Map.merge(params)

    changeset = Aircon.changeset(%Aircon{}, changeset_params)

    mqtt_payload =
      changeset_params
      |> Map.merge(%{"type" => "set"})
      |> ProperCase.to_camel_case
      |> Poison.encode!

    Thermio.MqttClient.publish_message("heatpump", mqtt_payload)

    Repo.insert(changeset)
  end

  def handle_dialogflow(conn, %{"result" => %{"action" => "input.welcome"}}) do
    %{heat_index: heat_index} =
      Thermio.Climate
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one

    aircon =
      Thermio.Aircon
      |> order_by(desc: :inserted_at)
      |> limit(1)
      |> Thermio.Repo.one

    conn
    |> put_status(:ok)
    |> render(Thermio.DialogflowView, "summary.json", %{aircon: aircon, heat_index: heat_index})
  end

  def handle_dialogflow(conn, %{"result" => %{"action" => "ac.setting", "parameters" => %{
    "mode" => mode,
    "temp" => power,
    "power" => temp
  }}}) do
    modes = %{
      "auto" => 1,
      "heat" => 2,
      "cool" => 3,
      "dry" => 4,
      "fan" => 5
    }

    power = if (power == "on"), do: 1, else: 0
    temp = if (temp == "" || !temp), do: 24, else: temp

    params = %{
      "mode" => modes[mode] || 3,
      "power" => power,
      "temp" => temp
    }

    case set_aircon(params) do
      {:ok, aircon} ->
        conn
        |> put_status(:created)
        |> put_resp_header("location", aircon_path(conn, :show, aircon))
        |> render(Thermio.DialogflowView, "update.json", aircon: aircon)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(Thermio.ChangesetView, "error.json", changeset: changeset)
    end
  end

  def create(conn, params) do
    case set_aircon(params) do
      {:ok, aircon} ->
        conn
        |> put_status(:created)
        |> put_resp_header("location", aircon_path(conn, :show, aircon))
        |> render("show.json", aircon: aircon)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(Thermio.ChangesetView, "error.json", changeset: changeset)
    end
  end

  def show(conn, %{"id" => id}) do
    aircon = Repo.get!(Aircon, id)
    render(conn, "show.json", aircon: aircon)
  end

  def update(conn, %{"id" => id, "aircon" => aircon_params}) do
    aircon = Repo.get!(Aircon, id)
    changeset = Aircon.changeset(aircon, aircon_params)

    case Repo.update(changeset) do
      {:ok, aircon} ->
        render(conn, "show.json", aircon: aircon)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(Thermio.ChangesetView, "error.json", changeset: changeset)
    end
  end

  def delete(conn, %{"id" => id}) do
    aircon = Repo.get!(Aircon, id)

    # Here we use delete! (with a bang) because we expect
    # it to always work (and if it does not, it will raise).
    Repo.delete!(aircon)

    send_resp(conn, :no_content, "")
  end
end


Fixes the order of parameter incase updates fails

defmodule CoursePlanner.SettingController do
  @moduledoc false
  use CoursePlanner.Web, :controller

  alias CoursePlanner.{Settings, SystemVariable}
  alias Ecto.Changeset

  import Canary.Plugs
  plug :authorize_controller

  def show(%{assigns: %{current_user: %{role: "Coordinator"}}} = conn, _param) do
    system_variables = Settings.get_visible_systemvariables()
    render(conn, "show.html", system_variables: system_variables)
  end

  def edit(%{assigns: %{current_user: %{role: "Coordinator"}}} = conn, _param) do
    changeset =
      Settings.get_editable_systemvariables()
      |> Enum.map(&SystemVariable.changeset/1)
      |> Settings.wrap()
    render(conn, "edit.html", changeset: changeset)
  end

  def update(
    %{assigns: %{current_user: %{role: "Coordinator"}}} = conn,
    %{"settings" => %{"system_variables" => variables}}) do
    changesets = Settings.get_changesets_for_update(variables)

    case Settings.update(changesets) do
      {:ok, _setting} ->
        conn
        |> put_flash(:info, "Setting updated successfully.")
        |> redirect(to: setting_path(conn, :show))
      {:error, :non_existing_resource, _failed_value, _changes_so_far} ->
        conn
        |> put_status(404)
        |> render(CoursePlanner.ErrorView, "404.html")
      {:error, :uneditable_resource, _failed_value, _changes_so_far} ->
        conn
        |> put_status(403)
        |> render(CoursePlanner.ErrorView, "403.html")
      {:error, _failed_operation, _failed_value, _changes_so_far} ->
        changeset =
          changesets
          |> Enum.sort_by(&(Changeset.get_field(&1, :key)), &<=/2)
          |> Settings.wrap()
          |> Map.put(:action, :update)
        render(conn, "edit.html", changeset: changeset)
    end
  end
end

defmodule CoursePlanner.SettingController do
  @moduledoc false
  use CoursePlanner.Web, :controller

  alias CoursePlanner.{Settings, SystemVariable}

  import Canary.Plugs
  plug :authorize_controller

  def show(%{assigns: %{current_user: %{role: "Coordinator"}}} = conn, _param) do
    system_variables = Settings.get_visible_systemvariables()
    render(conn, "show.html", system_variables: system_variables)
  end

  def edit(%{assigns: %{current_user: %{role: "Coordinator"}}} = conn, _param) do
    changeset =
      Settings.get_editable_systemvariables()
      |> Enum.map(&SystemVariable.changeset/1)
      |> Settings.wrap()
    render(conn, "edit.html", changeset: changeset)
  end

  def update(
    %{assigns: %{current_user: %{role: "Coordinator"}}} = conn,
    %{"settings" => %{"system_variables" => variables}}) do
    changesets = Settings.get_changesets_for_update(variables)

    case Settings.update(changesets) do
      {:ok, _setting} ->
        conn
        |> put_flash(:info, "Setting updated successfully.")
        |> redirect(to: setting_path(conn, :show))
      {:error, :non_existing_resource, _failed_value, _changes_so_far} ->
        conn
        |> put_status(404)
        |> render(CoursePlanner.ErrorView, "404.html")
      {:error, :uneditable_resource, _failed_value, _changes_so_far} ->
        conn
        |> put_status(403)
        |> render(CoursePlanner.ErrorView, "403.html")
      {:error, _failed_operation, _failed_value, _changes_so_far} ->
        changeset =
          changesets
          |> Settings.wrap()
          |> Map.put(:action, :update)
        render(conn, "edit.html", changeset: changeset)
    end
  end
end


Increase size of pool

Increase size of pool


Added updated at to serialized fields

Added updated at to serialized fields

defmodule PhoenixToggl.TimeEntry do
  use PhoenixToggl.Web, :model
  use Ecto.Model.Callbacks

  alias PhoenixToggl.{Workspace, User}
  alias Timex.Ecto.DateTime
  alias Timex.Date

  @derive {Poison.Encoder, only: [:id, :description, :started_at, :stopped_at, :duration, :updated_at]}

  schema "time_entries" do
    field :description, :string
    field :started_at, DateTime
    field :stopped_at, DateTime
    field :duration, :integer

    field :restarted_at, DateTime, virtual: true

    belongs_to :workspace, Workspace
    belongs_to :user, User

    timestamps
  end

  @required_fields ~w(started_at user_id)
  @optional_fields ~w(description stopped_at duration workspace_id)
  @restart_required_fields ~w(restarted_at)

  @doc """
  Creates a changeset based on the `model` and `params`.

  If no params are provided, an invalid changeset is returned
  with no validation performed.
  """
  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
    |> foreign_key_constraint(:workspace_id)
    |> foreign_key_constraint(:user_id)
  end

  @doc """
  Creates a default changeset and sets the first time_range
  """
  def start_changeset(model, params \\ :empty) do
    model
    |> changeset(params)
    |> put_change(:duration, 0)
  end

  @doc """
  Creates a default changeset and sets the stop key value
  on the last time_range
  """
  def stop_changeset(model, params \\ :empty) do
    duration = Date.diff(model.started_at, params.stopped_at, :secs)

    model
    |> changeset(params)
    |> put_change(:duration, duration)
  end

  @doc """
  Creates a default changeset and sets the stop key value
  on the last time_range
  """
  def restart_changeset(model, params \\ :empty) do
    model
    |> changeset(params)
    |> cast(params, @restart_required_fields, @optional_fields)
    |> put_change(:stopped_at, nil)
  end

  @doc """
  Returns a start_changeset
  """
  def start(time_entry, params) do
    time_entry
    |> start_changeset(params)
  end

  @doc """
  Returns a stop_changeset
  """
  def stop(time_entry, date_time \\ Date.now) do
    time_entry
    |> stop_changeset(%{stopped_at: date_time})
  end

  @doc """
  Returns a restart_changeset
  """
  def restart(time_entry, date_time \\ Date.now) do
    time_entry
    |> restart_changeset(%{restarted_at: date_time})
  end

  def active_for_user(query, user_id) do
    from t in query,
      where: t.user_id == ^user_id and is_nil(t.stopped_at)
  end

  def not_active_for_user(query, user_id) do
    from t in query,
      where: t.user_id == ^user_id and not(is_nil(t.stopped_at))
  end

  def sorted(query) do
    from t in query,
      order_by: [desc: t.updated_at]
  end

  # Private functions
  ###################

end

defmodule PhoenixToggl.TimeEntry do
  use PhoenixToggl.Web, :model
  use Ecto.Model.Callbacks

  alias PhoenixToggl.{Workspace, User}
  alias Timex.Ecto.DateTime
  alias Timex.Date

  @derive {Poison.Encoder, only: [:id, :description, :started_at, :stopped_at, :duration]}

  schema "time_entries" do
    field :description, :string
    field :started_at, DateTime
    field :stopped_at, DateTime
    field :duration, :integer

    field :restarted_at, DateTime, virtual: true

    belongs_to :workspace, Workspace
    belongs_to :user, User

    timestamps
  end

  @required_fields ~w(started_at user_id)
  @optional_fields ~w(description stopped_at duration workspace_id)
  @restart_required_fields ~w(restarted_at)

  @doc """
  Creates a changeset based on the `model` and `params`.

  If no params are provided, an invalid changeset is returned
  with no validation performed.
  """
  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
    |> foreign_key_constraint(:workspace_id)
    |> foreign_key_constraint(:user_id)
  end

  @doc """
  Creates a default changeset and sets the first time_range
  """
  def start_changeset(model, params \\ :empty) do
    model
    |> changeset(params)
    |> put_change(:duration, 0)
  end

  @doc """
  Creates a default changeset and sets the stop key value
  on the last time_range
  """
  def stop_changeset(model, params \\ :empty) do
    duration = Date.diff(model.started_at, params.stopped_at, :secs)

    model
    |> changeset(params)
    |> put_change(:duration, duration)
  end

  @doc """
  Creates a default changeset and sets the stop key value
  on the last time_range
  """
  def restart_changeset(model, params \\ :empty) do
    model
    |> changeset(params)
    |> cast(params, @restart_required_fields, @optional_fields)
    |> put_change(:stopped_at, nil)
  end

  @doc """
  Returns a start_changeset
  """
  def start(time_entry, params) do
    time_entry
    |> start_changeset(params)
  end

  @doc """
  Returns a stop_changeset
  """
  def stop(time_entry, date_time \\ Date.now) do
    time_entry
    |> stop_changeset(%{stopped_at: date_time})
  end

  @doc """
  Returns a restart_changeset
  """
  def restart(time_entry, date_time \\ Date.now) do
    time_entry
    |> restart_changeset(%{restarted_at: date_time})
  end

  def active_for_user(query, user_id) do
    from t in query,
      where: t.user_id == ^user_id and is_nil(t.stopped_at)
  end

  def not_active_for_user(query, user_id) do
    from t in query,
      where: t.user_id == ^user_id and not(is_nil(t.stopped_at))
  end

  def sorted(query) do
    from t in query,
      order_by: [desc: t.updated_at]
  end

  # Private functions
  ###################

end


Fixed unsafe variable warnings in shared view

defmodule CoursePlanner.SharedView do
  use CoursePlanner.Web, :view

  # helpers

  def path_exact_match(conn, path) do
    conn.request_path == path
  end

  def path_match(conn, path) do
    String.starts_with? conn.request_path, path
  end

  # form components

  def form_text(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    wrapper_class = if form.errors[field] do "is-invalid" else "" end

    required = opts[:required] || nil

    value = Map.get form.data, field
    wrapper_class =
      if required && String.length to_string value > 0 do
        Enum.join [wrapper_class, "form-init"], " "
      else
        wrapper_class
      end

    render "form_text.html", form: form,
                             field: field,
                             label: label,
                             wrapper_class: wrapper_class,
                             class: class,
                             required: required
  end

  def form_textarea(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    wrapper_class = if form.errors[field] do "is-invalid" else "" end

    required = opts[:required] || nil

    value = Map.get form.data, field
    wrapper_class =
      if required && String.length to_string value > 0 do
        Enum.join [wrapper_class, "form-init"], " "
      else
        wrapper_class
      end

    rows = opts[:rows] || 3

    render "form_textarea.html", form: form,
                                 field: field,
                                 label: label,
                                 wrapper_class: wrapper_class,
                                 class: class,
                                 required: required,
                                 rows: rows
  end

  def form_password(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    required = opts[:required] || nil

    value = Map.get form.data, field
    wrapper_class =
      if required && String.length to_string value > 0 do
        "form-init"
      else
        ""
      end

    render "form_password.html", form: form,
                                 field: field,
                                 label: label,
                                 wrapper_class: wrapper_class,
                                 class: class,
                                 required: required
  end

  def form_date(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    render "form_date.html", form: form,
                             field: field,
                             label: label,
                             class: class
  end

  def form_time(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    render "form_time.html", form: form,
                             field: field,
                             label: label,
                             class: class
  end

  def form_datetime(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    render "form_datetime.html", form: form,
                                 field: field,
                                 label: label,
                                 class: class
  end

  def form_select(form, field, options, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    selected = opts[:selected] || nil

    render "form_select.html", form: form,
                               field: field,
                               label: label,
                               selected: selected,
                               options: options,
                               class: class
  end

  def form_multiselect(form, field, options, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    selected = opts[:selected] || nil
    tooltip_text = opts[:tooltip_text] || "Add new item"

    multiselect_id = (Atom.to_string field) <> "__multiselect"
    button_id = (Atom.to_string field) <> "__add-button"

    render "form_multiselect.html", form: form,
                                    field: field,
                                    label: label,
                                    selected: selected,
                                    options: options,
                                    tooltip_text: tooltip_text,
                                    class: class,
                                    button_id: button_id,
                                    multiselect_id: multiselect_id
  end

  def form_button(label, to, opts \\ []) do
    class = opts[:class] || ""
    render "form_button.html", label: label, to: to, class: class
  end

  def form_submit(form, label, opts \\ []) do
    class = opts[:class] || ""
    render "form_submit.html", form: form, label: label, class: class
  end

  # card

  def card(title, [do: children]) do
    render "card.html", title: title, children: children
  end

  def card_content([do: children]) do
    render "card_content.html", children: children
  end

  def card_actions([do: children]) do
    render "card_actions.html", children: children
  end

  # navbar

  def navbar(title, [do: children]) do
    render "navbar.html", title: title, children: children
  end

  def navbar_separator do
    render "navbar_separator.html"
  end

  def navbar_item(label, conn, path) do
    classes = if path_match(conn, path) do
      "mdl-navigation__link mdl-navigation__link--current"
    else
      "mdl-navigation__link"
    end

    render "navbar_item.html", label: label, path: path, classes: classes
  end

end

defmodule CoursePlanner.SharedView do
  use CoursePlanner.Web, :view

  # helpers

  def path_exact_match(conn, path) do
    conn.request_path == path
  end

  def path_match(conn, path) do
    String.starts_with? conn.request_path, path
  end

  # form components

  def form_text(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    wrapper_class = ""

    if form.errors[field] do
      wrapper_class = "is-invalid"
    end

    required = opts[:required] || nil

    value = Map.get form.data, field
    if required && String.length to_string value > 0 do
      wrapper_class = Enum.join [wrapper_class, "form-init"], " "
    end

    render "form_text.html", form: form,
                             field: field,
                             label: label,
                             wrapper_class: wrapper_class,
                             class: class,
                             required: required
  end

  def form_textarea(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    wrapper_class = ""

    if form.errors[field] do
      wrapper_class = "is-invalid"
    end

    required = opts[:required] || nil

    value = Map.get form.data, field
    if required && String.length to_string value > 0 do
      wrapper_class = Enum.join [wrapper_class, "form-init"], " "
    end

    rows = opts[:rows] || 3

    render "form_textarea.html", form: form,
                                 field: field,
                                 label: label,
                                 wrapper_class: wrapper_class,
                                 class: class,
                                 required: required,
                                 rows: rows
  end

  def form_password(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    required = opts[:required] || nil
    wrapper_class = ""

    value = Map.get form.data, field
    if required && String.length to_string value > 0 do
      wrapper_class = Enum.join [wrapper_class, "form-init"], " "
    end

    render "form_password.html", form: form,
                                 field: field,
                                 label: label,
                                 wrapper_class: wrapper_class,
                                 class: class,
                                 required: required
  end

  def form_date(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    render "form_date.html", form: form,
                             field: field,
                             label: label,
                             class: class
  end

  def form_time(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    render "form_time.html", form: form,
                             field: field,
                             label: label,
                             class: class
  end

  def form_datetime(form, field, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)

    render "form_datetime.html", form: form,
                                 field: field,
                                 label: label,
                                 class: class
  end

  def form_select(form, field, options, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    selected = opts[:selected] || nil

    render "form_select.html", form: form,
                               field: field,
                               label: label,
                               selected: selected,
                               options: options,
                               class: class
  end

  def form_multiselect(form, field, options, opts \\ []) do
    class = opts[:class] || ""
    label = opts[:label] || humanize(field)
    selected = opts[:selected] || nil
    tooltip_text = opts[:tooltip_text] || "Add new item"

    multiselect_id = (Atom.to_string field) <> "__multiselect"
    button_id = (Atom.to_string field) <> "__add-button"

    render "form_multiselect.html", form: form,
                                    field: field,
                                    label: label,
                                    selected: selected,
                                    options: options,
                                    tooltip_text: tooltip_text,
                                    class: class,
                                    button_id: button_id,
                                    multiselect_id: multiselect_id
  end

  def form_button(label, to, opts \\ []) do
    class = opts[:class] || ""
    render "form_button.html", label: label, to: to, class: class
  end

  def form_submit(form, label, opts \\ []) do
    class = opts[:class] || ""
    render "form_submit.html", form: form, label: label, class: class
  end

  # card

  def card(title, [do: children]) do
    render "card.html", title: title, children: children
  end

  def card_content([do: children]) do
    render "card_content.html", children: children
  end

  def card_actions([do: children]) do
    render "card_actions.html", children: children
  end

  # navbar

  def navbar(title, [do: children]) do
    render "navbar.html", title: title, children: children
  end

  def navbar_separator do
    render "navbar_separator.html"
  end

  def navbar_item(label, conn, path) do
    classes = if path_match(conn, path) do
      "mdl-navigation__link mdl-navigation__link--current"
    else
      "mdl-navigation__link"
    end

    render "navbar_item.html", label: label, path: path, classes: classes
  end

end


fix warning

fix warning

defmodule UnitFun.Components.Equality do
  alias UnitFun.Value
  import UnitFun.Conversion.ConversionHelper, only: [convert_to: 2]

  alias UnitFun.Errors.CannotCompareError
  alias UnitFun.Errors.MissingConversionError

  def equal(%Value{value: left, units: x}, %Value{value: right, units: x}) do
    left == right
  end

  def equal(%Value{units: left_units} = left_side, %Value{units: right_units} = right_side) do
    updated_right_side = try do
      right_side |> convert_to(left_units)
    rescue
      e in MissingConversionError
        -> raise CannotCompareError, message: "Can't compare #{left_units} to #{right_units}. " <> e.message
    end
    equal(left_side, updated_right_side)
  end

  def equal(left, right) do
    left == right
  end
end

defmodule UnitFun.Components.Equality do
  alias UnitFun.Value
  alias UnitFun.Units.CompositeUnit
  import UnitFun.Conversion.ConversionHelper, only: [convert_to: 2]

  alias UnitFun.Errors.CannotCompareError
  alias UnitFun.Errors.MissingConversionError

  def equal(%Value{value: left, units: x}, %Value{value: right, units: x}) do
    left == right
  end

  def equal(%Value{units: left_units} = left_side, %Value{units: right_units} = right_side) do
    updated_right_side = try do
      right_side |> convert_to(left_units)
    rescue
      e in MissingConversionError
        -> raise CannotCompareError, message: "Can't compare #{left_units} to #{right_units}. " <> e.message
    end
    equal(left_side, updated_right_side)
  end

  def equal(left, right) do
    left == right
  end
end