Initial sketch of Protocol module.

Initial sketch of Protocol module.

defmodule Sqlite.DbConnection.Protocol do
  @moduledoc false

  # alias Sqlite.DbConnection.Types
  # alias Sqlite.DbConnection.Query
  # import Sqlite.DbConnection.Messages
  # import Sqlite.DbConnection.BinaryUtils
  require Logger

  # @sock_opts [packet: :raw, mode: :binary, active: false]

  defstruct [db: nil, path: nil]

  @type state :: %__MODULE__{db: Sqlitex.Connection,
                             path: String.t}

  @reserved_prefix "Sqlite.DbConnection_"
  @reserved_queries ["BEGIN", "COMMIT", "ROLLBACK"]

  @spec connect(Keyword.t) ::
    {:ok, state} | {:error, Sqlite.DbConnection.Error.t}
  def connect(opts) do
    {db_path, _opts} = Keyword.pop(opts, :database)
    with {:ok, db} <- Sqlitex.open(db_path),
         :ok <- Sqlitex.exec(db, "PRAGMA foreign_keys = ON"),
         {:ok, [[foreign_keys: 1]]} = Sqlitex.query(db, "PRAGMA foreign_keys")
    do
      s = %__MODULE__{db: db, path: db_path}
      {:ok, s}
    else
      {:error, _reason} = error -> error
    end
  end

  # @spec disconnect(Exception.t, state) :: :ok
  # def disconnect(err, %{types: ref}) when is_reference(ref) do
  #   # Don't handle the case where connection failure occurs during bootstrap
  #   # (hard to test and "unlikely" given auth just succeeded)
  #   raise err
  # end
  # def disconnect(_, s) do
  #   sock_close(s)
  #   _ = recv_buffer(s)
  #   delete_parameters(s)
  #   :ok
  # end
  #
  # @spec ping(state) ::
  #   {:ok, state} | {:disconnect, Sqlite.DbConnection.Error.t, state}
  # def ping(%{buffer: buffer} = s) do
  #   status = %{notify: notify([]), sync: :sync}
  #   sync(%{s | buffer: nil}, status, buffer)
  # end
  #
  # @spec checkout(state) ::
  #   {:ok, state} | {:disconnect, Sqlite.DbConnection.Error.t, state}
  # def checkout(%{postgres: :transaction} = s) do
  #   sync_error(s, :transaction)
  # end
  # def checkout(%{buffer: :active_once} = s) do
  #   case setopts(s, [active: :false], :active_once) do
  #     :ok                       -> recv_buffer(s)
  #     {:disconnect, _, _} = dis -> dis
  #   end
  # end
  #
  # @spec checkin(state) ::
  # {:ok, state} | {:disconnect, Sqlite.DbConnection.Error.t, state}
  # def checkin(%{postgres: :transaction} = s) do
  #   sync_error(s, :transaction)
  # end
  # def checkin(%{buffer: buffer} = s) when is_binary(buffer) do
  #   activate(s, buffer)
  # end
  #
  # @spec handle_prepare(Sqlite.DbConnection.Query.t, Keyword.t, state) ::
  #   {:ok, Sqlite.DbConnection.Query.t, state} |
  #   {:error, ArgumentError.t, state} |
  #   {:error | :disconnect, Sqlite.DbConnection.Query.t, state}
  # def handle_prepare(%Query{name: @reserved_prefix <> _} = query, _, s) do
  #   reserved_error(query, s)
  # end
  # def handle_prepare(query, opts, s) do
  #   case query do
  #     %Query{param_formats: pfs, encoders: encoders} when is_list(pfs) and is_list(encoders) ->
  #       handle_prepare(query, :parse, opts, s)
  #     _ ->
  #       handle_prepare(query, :parse_describe, opts, s)
  #   end
  # end
  #
  # @spec handle_execute(Sqlite.DbConnection.Query.t, list, Keyword.t, state) ::
  #   {:ok, Sqlite.DbConnection.Result.t, state} |
  #   {:prepare, state} |
  #   {:error, ArgumentError.t, state} |
  #   {:error | :disconnect, Sqlite.DbConnection.Error.t, state}
  # def handle_execute(%Query{} = query, params, opts, s) do
  #   handle_execute(query, params, :sync, opts, s)
  # end
  # @spec handle_execute(Sqlite.DbConnection.Parameters.t, nil, Keyword.t, state) ::
  #   {:ok, %{binary => binary}, state} |
  #   {:error, Sqlite.DbConnection.Errpr.t, state}
  # def handle_execute(%Sqlite.DbConnection.Parameters{}, nil, _, s) do
  #   %{parameters: parameters} = s
  #   case Sqlite.DbConnection.Parameters.fetch(parameters) do
  #     {:ok, parameters} ->
  #       {:ok, parameters, s}
  #     :error ->
  #       {:error, %Sqlite.DbConnection.Error{message: "parameters not available"}, s}
  #   end
  # end
  #
  # @spec handle_execute_close(Sqlite.DbConnection.Query.t, list, Keyword.t, state) ::
  #   {:ok, Sqlite.DbConnection.Result.t, state} |
  #   {:prepare, state} |
  #   {:error, ArgumentError.t, state} |
  #   {:error | :disconnect, Sqlite.DbConnection.Error.t, state}
  # def handle_execute_close(%Query{name: @reserved_prefix <> _} = query, _, _, s) do
  #   reserved_error(query, s)
  # end
  # def handle_execute_close(query, params, opts, s) do
  #   handle_execute(query, params, :sync_close, opts, s)
  # end
  #
  # @spec handle_close(Sqlite.DbConnection.Query.t, Keyword.t, state) ::
  #   {:ok, state} |
  #   {:error, ArgumentError.t, state} |
  #   {:error | :disconnect, Sqlite.DbConnection.Error.t, state}
  # def handle_close(%Query{name: @reserved_prefix <> _} = query, _, s) do
  #   reserved_error(query, s)
  # end
  # def handle_close(query, opts, %{buffer: buffer} = s) do
  #   status = %{notify: notify(opts)}
  #   close(%{s | buffer: nil}, status, query, nil, buffer)
  # end
  #
  # def handle_begin(opts, s) do
  #   handle_transaction(@reserved_prefix <> "BEGIN", :transaction, opts, s)
  # end
  #
  # def handle_commit(opts, s) do
  #   handle_transaction(@reserved_prefix <> "COMMIT", :idle, opts, s)
  # end
  #
  # def handle_rollback(opts, s) do
  #   handle_transaction(@reserved_prefix <> "ROLLBACK", :idle, opts, s)
  # end
  #
  # @spec handle_simple(String.t, Keyword.t, state) ::
  #   {:ok, Sqlite.DbConnection.Result.t, state} |
  #   {:error | :disconnect, Sqlite.DbConnection.Error.t, state}
  # def handle_simple(statement, opts, %{buffer: buffer} = s) do
  #   status = %{notify: notify(opts), sync: :sync}
  #   simple_send(%{s | buffer: nil}, status, statement, buffer)
  # end
  #
  # @spec handle_info(any, Keyword.t, state) ::
  #   {:ok, state} | {:error | :disconnect, Sqlite.DbConnection.Error.t}
  # def handle_info(msg, opts \\ [], s)
  #
  # def handle_info({:tcp, sock, data}, opts, %{sock: {:gen_tcp, sock}} = s) do
  #   handle_data(s, opts, data)
  # end
  # def handle_info({:tcp_closed, sock}, _, %{sock: {:gen_tcp, sock}} = s) do
  #   err = Sqlite.DbConnection.Error.exception(tag: :tcp, action: "async recv", reason: :closed)
  #   {:disconnect, err, s}
  # end
  # def handle_info({:tcp_error, sock, reason}, _, %{sock: {:gen_tcp, sock}} = s) do
  #   err = Sqlite.DbConnection.Error.exception(tag: :tcp, action: "async recv", reason: reason)
  #   {:disconnect, err, s}
  # end
  # def handle_info({:ssl, sock, data}, opts, %{sock: {:ssl, sock}} = s) do
  #   handle_data(s, opts, data)
  # end
  # def handle_info({:ssl_closed, sock}, _, %{sock: {:ssl, sock}} = s) do
  #   err = Sqlite.DbConnection.Error.exception(tag: :ssl, action: "async recv", reason: :closed)
  #   {:disconnect, err, s}
  # end
  # def handle_info({:ssl_error, sock, reason}, _, %{sock: {:ssl, sock}} = s) do
  #   err = Sqlite.DbConnection.Error.exception(tag: :ssl, action: "async recv", reason: reason)
  #   {:disconnect, err, s}
  # end
  # def handle_info(msg, _, s) do
  #   Logger.info(fn() -> [inspect(__MODULE__), ?\s, inspect(self()),
  #     " received unexpected message: " | inspect(msg)]
  #   end)
  #   {:ok, s}
  # end
  #
  # ## connect
  #
  # defp connect(host, port, sock_opts, %{timeout: timeout} = s) do
  #   buffer? = Keyword.has_key?(sock_opts, :buffer)
  #   case :gen_tcp.connect(host, port, sock_opts ++ @sock_opts, timeout) do
  #     {:ok, sock} when buffer? ->
  #       {:ok, %{s | sock: {:gen_tcp, sock}}}
  #     {:ok, sock} ->
  #       # A suitable :buffer is only set if :recbuf is included in
  #       # :socket_options.
  #       {:ok, [sndbuf: sndbuf, recbuf: recbuf, buffer: buffer]} =
  #         :inet.getopts(sock, [:sndbuf, :recbuf, :buffer])
  #       buffer = buffer
  #         |> max(sndbuf)
  #         |> max(recbuf)
  #       :ok = :inet.setopts(sock, [buffer: buffer])
  #       {:ok, %{s | sock: {:gen_tcp, sock}}}
  #     {:error, reason} ->
  #       {:error, Sqlite.DbConnection.Error.exception(tag: :tcp, action: "connect", reason: reason)}
  #   end
  # end
  #
  # ## ssl
  #
  # defp ssl(s, status) do
  #   case msg_send(s, msg_ssl_request(), "") do
  #     :ok              -> ssl_recv(s, status)
  #     {:error, _} = err -> err
  #   end
  # end
  #
  # defp ssl_recv(%{sock: {:gen_tcp, sock}, timeout: timeout} = s, status) do
  #   case :gen_tcp.recv(sock, 1, timeout) do
  #     {:ok, <<?S>>} ->
  #       ssl_connect(s, status)
  #     {:ok, <<?N>>} ->
  #       disconnect(s, %Sqlite.DbConnection.Error{message: "ssl not available"}, "")
  #     {:error, reason} ->
  #       err = Sqlite.DbConnection.Error.exception(tag: :tcp, action: "recv", reason: reason)
  #       disconnect(s, err, "")
  #   end
  # end
  #
  # defp ssl_connect(%{sock: {:gen_tcp, sock}, timeout: timeout} = s, status) do
  #   case :ssl.connect(sock, status.opts[:ssl_opts] || [], timeout) do
  #     {:ok, ssl_sock} ->
  #       startup(%{s | sock: {:ssl, ssl_sock}}, status)
  #     {:error, reason} ->
  #       err = Sqlite.DbConnection.Error.exception(tag: :ssl, action: "connect", reason: reason)
  #       disconnect(s, err, "")
  #   end
  # end
  #
  # ## startup
  #
  # defp startup(s, %{opts: opts} = status) do
  #   params = opts[:parameters] || []
  #   user = Keyword.fetch!(opts, :username)
  #   database = Keyword.fetch!(opts, :database)
  #   msg = msg_startup(params: [user: user, database: database] ++ params)
  #   case msg_send(s, msg, "") do
  #     :ok                       -> auth_recv(s, status, <<>>)
  #     {:disconnect, _, _} = dis -> dis
  #   end
  # end
  #
  # ## auth
  #
  # defp auth_recv(%{timeout: timeout} = s, status, buffer) do
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_auth(type: :ok), buffer} ->
  #       init_recv(s, status, buffer)
  #     {:ok, msg_auth(type: :cleartext), buffer} ->
  #       auth_cleartext(s, status, buffer)
  #     {:ok, msg_auth(type: :md5, data: salt), buffer} ->
  #       auth_md5(s, status, salt, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       disconnect(s, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp auth_cleartext(s, %{opts: opts} = status, buffer) do
  #   pass = Keyword.fetch!(opts, :password)
  #   auth_send(s, msg_password(pass: pass), status, buffer)
  # end
  #
  # defp auth_md5(s, %{opts: opts} = status, salt, buffer) do
  #   user = Keyword.fetch!(opts, :username)
  #   pass = Keyword.fetch!(opts, :password)
  #
  #   digest = :crypto.hash(:md5, [pass, user])
  #   |> Base.encode16(case: :lower)
  #   digest = :crypto.hash(:md5, [digest, salt])
  #   |> Base.encode16(case: :lower)
  #   auth_send(s, msg_password(pass: ["md5", digest]), status, buffer)
  # end
  #
  # defp auth_send(s, msg, status, buffer) do
  #   case msg_send(s, msg, buffer) do
  #     :ok                       -> auth_recv(s, status, buffer)
  #     {:disconnect, _, _} = dis -> dis
  #   end
  # end
  #
  # ## init
  #
  # defp init_recv(%{timeout: timeout} = s, status, buffer) do
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_backend_key(pid: pid, key: key), buffer} ->
  #       init_recv(%{s | backend_key: {pid, key}}, status, buffer)
  #     {:ok, msg_ready(), buffer} ->
  #       bootstrap(s, status, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       disconnect(s, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, buffer} ->
  #       init_recv(handle_msg(s, status, msg), status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # ## bootstrap
  #
  # defp bootstrap(s, %{types_key: nil}, buffer) do
  #   activate(s, buffer)
  # end
  # defp bootstrap(s, %{types_key: types_key} = status, buffer) do
  #   case Sqlite.DbConnection.TypeServer.fetch(types_key) do
  #     {:ok, table} ->
  #       reserve_send(%{s | types: table}, status, buffer)
  #     {:lock, ref, table} ->
  #       status = %{status | types_ref: ref, types_table: table}
  #       bootstrap_send(%{s | types: ref}, status, buffer)
  #   end
  # end
  #
  # defp bootstrap_send(%{parameters: parameters} = s, status, buffer) do
  #   %{extensions: extensions} = status
  #
  #   extension_keys = Enum.map(extensions, &elem(&1, 0))
  #   extension_opts = Types.prepare_extensions(extensions, parameters)
  #   matchers = Types.extension_matchers(extension_keys, extension_opts)
  #   version = parameters["server_version"] |> Sqlite.DbConnection.Utils.parse_version
  #   statement = Types.bootstrap_query(matchers, version)
  #   msg = msg_query(statement: statement)
  #   case msg_send(s, msg, buffer) do
  #     :ok ->
  #       status = %{status | extension_info: {extension_keys, extension_opts}}
  #       bootstrap_recv(s, status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp bootstrap_recv(%{timeout: timeout} = s, status, buffer) do
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_row_desc(), buffer} ->
  #       bootstrap_recv(s, status, [], buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       disconnect(s, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, buffer} ->
  #       bootstrap_recv(handle_msg(s, status, msg), status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp bootstrap_recv(%{timeout: timeout} = s, status, rows, buffer) do
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_data_row(values: values), buffer} ->
  #       bootstrap_recv(s, status, [values | rows], buffer)
  #     {:ok, msg_command_complete(), buffer} ->
  #       bootstrap_types(s, status, rows, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       disconnect(s, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, buffer} ->
  #       bootstrap_recv(handle_msg(s, status, msg), status, rows, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp bootstrap_types(s, %{types_table: table} = status, rows, buffer) do
  #   %{types_ref: ref, extension_info: {extension_keys, extension_opts}} = status
  #   types = Types.build_types(rows)
  #   Types.associate_extensions_with_types(table, extension_keys, extension_opts, types)
  #   Sqlite.DbConnection.TypeServer.unlock(ref)
  #   bootstrap_sync_recv(%{s | types: table}, status, buffer)
  # end
  #
  # defp bootstrap_sync_recv(%{timeout: timeout} = s, status, buffer) do
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_ready(), buffer} ->
  #       reserve_send(s, status, buffer)
  #     {:ok, msg, buffer} ->
  #       bootstrap_sync_recv(handle_msg(s, status, msg), status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp reserve_send(s, status, buffer) do
  #   case msg_send(s, reserve_msgs() ++ [msg_sync()], buffer) do
  #     :ok ->
  #       reserve_recv(s, status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp reserve_msgs() do
  #   for statement <- @reserved_queries do
  #     name = @reserved_prefix <> statement
  #     msg_parse(name: name, statement: statement, type_oids: [])
  #   end
  # end
  #
  # defp reserve_recv(%{timeout: timeout} = s, status, buffer) do
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_parse_complete(), buffer} ->
  #       reserve_recv(s, status, buffer)
  #     {:ok, msg_ready(status: :idle), buffer} ->
  #       activate(s, buffer)
  #     {:ok, msg_ready(status: postgres), buffer} ->
  #       sync_error(s, postgres, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       disconnect(s, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, buffer} ->
  #       reserve_recv(handle_msg(s, status, msg), status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # ## simple
  #
  # defp simple_send(s, status, statement, buffer) do
  #   msg = msg_query(statement: statement)
  #   case msg_send(s, msg, buffer) do
  #     :ok                       -> simple_recv(s, status, buffer)
  #     {:disconnect, _, _} = dis -> dis
  #   end
  # end
  #
  # defp simple_recv(%{timeout: timeout} = s, status, buffer) do
  #   ## simple queries here are only done by Sqlite.DbConnection.Notifications processes
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_command_complete(tag: tag), buffer} ->
  #       complete(s, status, %Query{}, [], tag, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       sync_recv(s, status, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, buffer} ->
  #       simple_recv(handle_msg(s, status, msg), status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # ## prepare
  #
  # defp handle_prepare(query, prepare, opts, %{buffer: buffer} = s) do
  #   status = %{notify: notify(opts), prepare: prepare, sync: :sync}
  #   prepare_send(%{s | buffer: nil}, status, query, buffer)
  # end
  #
  # defp prepare_send(s, %{prepare: prepare} = status, query, buffer) do
  #   %Query{name: name, statement: statement} = query
  #   msgs =
  #    case prepare do
  #      :parse_describe ->
  #         [msg_describe(type: :statement, name: name), msg_flush()]
  #      :parse ->
  #         [msg_flush()]
  #     end
  #   msgs = [msg_parse(name: name, statement: statement, type_oids: []) | msgs]
  #   case msg_send(s, msgs, buffer) do
  #     :ok ->
  #       parse_recv(s, status, query, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp parse_recv(s, %{prepare: prepare} = status, query, buffer) do
  #   case msg_recv(s, :infinity, buffer) do
  #     {:ok, msg_parse_complete(), buffer} when prepare == :parse_describe ->
  #       describe_recv(s, status, %Query{query | types: s.types}, buffer)
  #     {:ok, msg_parse_complete(), buffer} when prepare == :parse ->
  #       ok(s, query, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       exception = Sqlite.DbConnection.Error.exception(postgres: fields)
  #       close_sync(s, status, query, exception, buffer)
  #     {:ok, msg, buffer} ->
  #       parse_recv(handle_msg(s, status, msg), status, query, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp describe_recv(s, status, query, buffer) do
  #   case msg_recv(s, :infinity, buffer) do
  #     {:ok, msg_no_data(), buffer} ->
  #       ok(s, query, buffer)
  #     {:ok, msg_parameter_desc(type_oids: param_oids), buffer} ->
  #       describe_recv(s, status, %Query{query | encoders: param_oids}, buffer)
  #     {:ok, msg_row_desc(fields: fields), buffer} ->
  #       {col_oids, col_names} = columns(fields)
  #       query = %Query{query | columns: col_names, decoders: col_oids}
  #       ok(s, query, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       exception = Sqlite.DbConnection.Error.exception(postgres: fields)
  #       close_sync(s, status, query, exception, buffer)
  #     {:ok, msg, buffer} ->
  #       describe_recv(handle_msg(s, status, msg), status, query, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp close_sync(s, status, %Query{name: name}, result, buffer) do
  #   msgs = [
  #     msg_close(type: :statement, name: name),
  #     msg_sync() ]
  #   case msg_send(s, msgs, buffer) do
  #     :ok                       -> sync_recv(s, status, result, buffer)
  #     {:disconnect, _, _} = dis -> dis
  #   end
  # end
  #
  # ## execute
  #
  # defp handle_execute(query, params, sync, opts, s) do
  #   %{types: types, buffer: buffer} = s
  #   case query do
  #     %Query{types: nil} ->
  #       query_error(s, "query #{inspect query} has not been prepared")
  #     %Query{param_formats: nil, types: ^types} ->
  #       query_error(s, "query #{inspect query} has not been described")
  #     %Query{types: ^types} = query ->
  #      status = %{notify: notify(opts), sync: sync}
  #      execute_send(%{s | buffer: nil}, status, query, params, buffer)
  #     %Query{} = query ->
  #       query_error(s, "query #{inspect query} has invalid types for the connection")
  #   end
  # end
  #
  # defp query_error(s, msg) do
  #   {:error, ArgumentError.exception(msg), s}
  # end
  #
  # defp execute_send(s, %{sync: sync} = status, query, params, buffer) do
  #   %Query{param_formats: pfs, result_formats: rfs, name: name} = query
  #   msgs =
  #     case sync do
  #       :sync_close ->
  #         [msg_sync(), msg_close(type: :statement, name: name), msg_flush()]
  #       :sync ->
  #         [msg_sync()]
  #     end
  #   msgs = [
  #     msg_bind(name_port: "", name_stat: name, param_formats: pfs, params: params, result_formats: rfs),
  #     msg_execute(name_port: "", max_rows: 0) |
  #     msgs ]
  #   case msg_send(s, msgs, buffer) do
  #     :ok                       -> bind_recv(s, status, query, buffer)
  #     {:disconnect, _, _} = dis -> dis
  #   end
  # end
  #
  # defp bind_recv(s, status, query, buffer) do
  #   case msg_recv(s, :infinity, buffer) do
  #     {:ok, msg_bind_complete(), buffer} ->
  #       execute_recv(s, status, query, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       bind_error(s, status, fields, buffer)
  #     {:ok, msg, buffer} ->
  #       bind_recv(handle_msg(s, status, msg), status, query, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp bind_error(s, status, fields, buffer) do
  #   case Sqlite.DbConnection.Error.exception(postgres: fields) do
  #     %Sqlite.DbConnection.Error{postgres: %{code: :invalid_sql_statement_name}} ->
  #       sync_recv(s, status, :prepare, buffer)
  #     err ->
  #       sync_recv(s, status, err, buffer)
  #   end
  # end
  #
  # defp execute_recv(s, status, query, buffer) do
  #   case msg_recv(s, :infinity, buffer) do
  #     {:ok, msg_data_row(values: values), buffer} ->
  #       execute_recv(s, status, query, [values], buffer)
  #     {:ok, msg_command_complete(tag: tag), buffer} ->
  #       complete(s, status, query, [], tag, buffer)
  #     {:ok, msg_empty_query(), buffer} ->
  #       sync_recv(s, status, %Sqlite.DbConnection.Result{}, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       sync_recv(s, status, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, buffer} ->
  #       execute_recv(handle_msg(s, status, msg), status, query, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp execute_recv(s, status, query, rows, buffer) do
  #   case msg_recv(s, :infinity, buffer) do
  #     {:ok, msg_data_row(values: values), buffer} ->
  #       execute_recv(s, status, query, [values | rows], buffer)
  #     {:ok, msg_command_complete(tag: tag), buffer} ->
  #       complete(s, status, query, rows, tag, buffer)
  #     {:ok, msg, buffer} ->
  #       execute_recv(handle_msg(s, status, msg), status, query, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp complete(s, status, %Query{columns: nil}, [], tag, buffer) do
  #   {command, nrows} = decode_tag(tag)
  #   result =  %Sqlite.DbConnection.Result{command: command, num_rows: nrows || 0}
  #   sync_recv(s, status, result, buffer)
  # end
  # defp complete(s, status, query, rows, tag, buffer) do
  #   {command, nrows} = decode_tag(tag)
  #   %Query{columns: cols} = query
  #   # Fix for PostgreSQL 8.4 (doesn't include number of selected rows in tag)
  #   if is_nil(nrows) and command == :select do
  #     nrows = length(rows)
  #   end
  #   result = %Sqlite.DbConnection.Result{command: command, num_rows: nrows || 0,
  #                             rows: rows, columns: cols}
  #   sync_recv(s, status, result, buffer)
  # end
  #
  # ## close
  #
  # defp close(s, status, %Query{name: name}, result, buffer) do
  #   msgs = [
  #     msg_close(type: :statement, name: name),
  #     msg_flush() ]
  #   case msg_send(s, msgs, buffer) do
  #     :ok               -> close_recv(s, status, result, buffer)
  #     {:error, _} = err -> err
  #   end
  # end
  #
  # defp close_recv(s, status, result, buffer) do
  #   case msg_recv(s, :infinity, buffer) do
  #     {:ok, msg_close_complete(), buffer} ->
  #       ok(s, result, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       ok(s, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, buffer} ->
  #       close_recv(handle_msg(s, status, msg), status, result, buffer)
  #     {:error, _} = err ->
  #       err
  #   end
  # end
  #
  # ## sync
  #
  # defp sync(s, status, buffer) do
  #   case msg_send(s, msg_sync(), buffer) do
  #     :ok               -> sync_recv(s, status, nil, buffer)
  #     {:error, _} = err -> err
  #   end
  # end
  #
  # ## transaction
  #
  # defp handle_transaction(name, postgres, opts, %{postgres: :naive} = s)
  # when postgres != :naive do
  #   handle_transaction(name, :naive, opts, s)
  # end
  # defp handle_transaction(name, postgres, opts, %{buffer: buffer} = s) do
  #   status = %{notify: notify(opts), sync: :sync}
  #   transaction_send(%{s | buffer: nil}, status, name, postgres, buffer)
  # end
  #
  # defp transaction_send(s, status, name, postgres, buffer) do
  #   msgs = [
  #     msg_bind(name_port: "", name_stat: name, param_formats: [], params: [], result_formats: []),
  #     msg_execute(name_port: "" , max_rows: 0),
  #     msg_sync()]
  #   case msg_send(s, msgs, buffer) do
  #     :ok ->
  #       transaction_recv(s, status, postgres, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp transaction_recv(s, status, postgres, buffer) do
  #   case msg_recv(s, :infinity, buffer) do
  #     {:ok, msg_ready(), buffer} when postgres == :naive ->
  #       ok(s, nil, buffer)
  #     {:ok, msg_ready(status: ^postgres), buffer} ->
  #       ok(s, postgres, buffer)
  #     {:ok, msg_ready(status: postgres), buffer} ->
  #       sync_error(s, postgres, buffer)
  #     {:ok, msg_bind_complete(), buffer} ->
  #       transaction_recv(s, status, postgres, buffer)
  #     {:ok, msg_command_complete(), buffer} ->
  #       transaction_recv(s, status, postgres, buffer)
  #     {:ok, msg_error(fields: fields), buffer} when postgres == :naive ->
  #       err = Sqlite.DbConnection.Error.exception(postgres: fields)
  #       sync_recv(s, status, err, buffer)
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       err = Sqlite.DbConnection.Error.exception(postgres: fields)
  #       disconnect(s, err, buffer)
  #     {:ok, msg, buffer} ->
  #       transaction_recv(handle_msg(s, status, msg), status, postgres, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # ## data
  #
  # defp handle_data(s, opts, buffer) do
  #   data(s, %{notify: notify(opts)}, buffer)
  # end
  #
  # defp data(%{timeout: timeout} = s, status, buffer) do
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_error(fields: fields), buffer} ->
  #       disconnect(s, Sqlite.DbConnection.Error.exception(postgres: fields), buffer)
  #     {:ok, msg, <<>>} ->
  #       activate(handle_msg(s, status, msg), <<>>)
  #     {:ok, msg, buffer} ->
  #       data(handle_msg(s, status, msg), status, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # ## helpers
  #
  # defp notify(opts) do
  #   opts[:notify] || fn(_, _) -> :ok end
  # end
  #
  # defp columns(fields) do
  #   Enum.map(fields, fn row_field(type_oid: oid, name: name) ->
  #     {oid, name}
  #   end) |> :lists.unzip
  # end
  #
  # defp tag(:gen_tcp), do: :tcp
  # defp tag(:ssl), do: :ssl
  #
  # defp decode_tag(tag) do
  #   words = :binary.split(tag, " ", [:global])
  #   words = Enum.map(words, fn word ->
  #     case Integer.parse(word) do
  #       {num, ""} -> num
  #       :error -> word
  #     end
  #   end)
  #
  #   {command, nums} = Enum.split_while(words, &is_binary(&1))
  #   command = Enum.join(command, "_") |> String.downcase |> String.to_atom
  #   {command, List.last(nums)}
  # end
  #
  # # It is ok to use infinity timeout here if in client process as timer is
  # # running.
  # defp msg_recv(%{sock: {:gen_tcp, sock}} = s, timeout, :active_once) do
  #   receive do
  #     {:tcp, ^sock, buffer} ->
  #       msg_recv(s, timeout, buffer)
  #     {:tcp_closed, ^sock} ->
  #       disconnect(s, :tcp, "async_recv", :closed, :active_once)
  #     {:tcp_error, ^sock, reason} ->
  #       disconnect(s, :tcp, "async_recv", reason, :active_once)
  #   after
  #     timeout ->
  #       disconnect(s, :tcp, "async_recv", :timeout, :active_one)
  #   end
  # end
  # defp msg_recv(%{sock: {:ssl, sock}} = s, timeout, :active_once) do
  #   receive do
  #     {:ssl, ^sock, buffer} ->
  #       msg_recv(s, timeout, buffer)
  #     {:ssl_closed, ^sock} ->
  #       disconnect(s, :ssl, "async_recv", :closed, :active_once)
  #     {:ssl_error, ^sock, reason} ->
  #       disconnect(s, :ssl, "async_recv", reason, :active_once)
  #   after
  #     timeout ->
  #       disconnect(s, :ssl, "async_recv", :timeout, :active_once)
  #   end
  # end
  # defp msg_recv(s, timeout, buffer) do
  #   case msg_decode(buffer) do
  #     {:ok, _, _} = ok -> ok
  #     {:more, more}    -> msg_recv(s, timeout, buffer, more)
  #   end
  # end
  #
  # defp msg_recv(%{sock: {mod, sock}} = s, timeout, buffer, more) do
  #   case mod.recv(sock, more, timeout) do
  #     {:ok, data} ->
  #       msg_recv(s, timeout, buffer <> data)
  #     {:error, reason} ->
  #       disconnect(s, tag(mod), "recv", reason, buffer)
  #   end
  # end
  #
  # defp msg_decode(bin) when byte_size(bin) < 5 do
  #   {:more, 0}
  # end
  # defp msg_decode(<<type :: int8, size :: int32, rest :: binary>>) do
  #   size = size - 4
  #   case rest do
  #     <<body :: binary(size), rest :: binary>> ->
  #       {:ok, parse(body, type, size), rest}
  #     _ ->
  #       {:more, size - byte_size(rest)}
  #   end
  # end
  #
  # defp msg_send(s, msgs, buffer) when is_list(msgs) do
  #   binaries = Enum.reduce(msgs, [], &[&2 | encode_msg(&1)])
  #   do_send(s, binaries, buffer)
  # end
  #
  # defp msg_send(s, msg, buffer) do
  #   do_send(s, encode_msg(msg), buffer)
  # end
  #
  # defp do_send(%{sock: {mod, sock}} = s, data, buffer) do
  #   case mod.send(sock, data) do
  #     :ok ->
  #       :ok
  #     {:error, reason} ->
  #       disconnect(s, tag(mod), "send", reason, buffer)
  #   end
  # end
  #
  # defp handle_msg(s, _, msg_parameter(name: name, value: value)) do
  #   %{parameters: parameters} = s
  #   # Binaries likely part of much larger binary and only keeping name/value
  #   # over long term
  #   name = :binary.copy(name)
  #   value = :binary.copy(value)
  #   cond do
  #     is_reference(parameters) ->
  #       _ = Sqlite.DbConnection.Parameters.put(parameters, name, value)
  #       s
  #     is_map(parameters) ->
  #       %{s | parameters: Map.put(parameters, name, value)}
  #   end
  # end
  # defp handle_msg(s, status, msg_notify(channel: channel, payload: payload)) do
  #   %{notify: notify} = status
  #   notify.(channel, payload)
  #   s
  # end
  # defp handle_msg(s, _, msg_notice()) do
  #   # TODO: subscribers
  #   s
  # end
  #
  # defp ok(s, %Sqlite.DbConnection.Result{} = res, buffer) do
  #   {:ok, res, %{s | buffer: buffer}}
  # end
  # defp ok(s, %Sqlite.DbConnection.Query{} = query, buffer) do
  #   {:ok, query, %{s | buffer: buffer}}
  #  end
  # defp ok(s, nil, buffer) do
  #   {:ok, %{s | buffer: buffer}}
  # end
  # defp ok(s, %Sqlite.DbConnection.Error{} = err, buffer) do
  #   {:error, err, %{s | buffer: buffer}}
  # end
  # defp ok(s, :prepare, buffer) do
  #   {:prepare, %{s | buffer: buffer}}
  # end
  # defp ok(s, postgres, buffer) when postgres in [:idle, :transaction] do
  #   {:ok, %{s | postgres: postgres, buffer: buffer}}
  # end
  #
  # defp disconnect(s, tag, action, reason, buffer) do
  #   err = Sqlite.DbConnection.Error.exception(tag: tag, action: action, reason: reason)
  #   disconnect(s, err, buffer)
  # end
  #
  # defp disconnect(s, err, buffer) do
  #   {:disconnect, err, %{s | buffer: buffer}}
  # end
  #
  # defp reserved_error(query, s) do
  #   err = ArgumentError.exception("query #{inspect query} uses reserved name")
  #   {:error, err, s}
  # end
  #
  # # Query has completed so ok to use state timeout as message should either be
  # # buffer or in flight. sync_recv/4 used by simple queries so can't use
  # # :infinity.
  # defp sync_recv(s, %{sync: sync} = status, result, buffer) do
  #   %{postgres: postgres, timeout: timeout} = s
  #   case msg_recv(s, timeout, buffer) do
  #     {:ok, msg_ready(status: :idle), buffer} when postgres == :transaction ->
  #       sync_error(s, :idle, buffer)
  #     {:ok, msg_ready(status: :transaction), buffer} when postgres == :idle ->
  #       sync_error(s, :transaction, buffer)
  #     {:ok, msg_ready(status: :failed), buffer} when postgres == :idle ->
  #       sync_error(s, :failed, buffer)
  #     {:ok, msg_ready(), buffer} when sync == :sync ->
  #       ok(s, result, buffer)
  #     {:ok, msg_ready(), buffer} when sync == :sync_close ->
  #       close_recv(s, status, result, buffer)
  #     {:ok, msg, buffer} ->
  #       sync_recv(handle_msg(s, status, msg), status, result, buffer)
  #     {:disconnect, _, _} = dis ->
  #       dis
  #   end
  # end
  #
  # defp sync_error(s, postgres, buffer) do
  #   sync_error(%{s | buffer: buffer}, postgres)
  # end
  #
  # defp sync_error(s, postgres) do
  #   err = %Sqlite.DbConnection.Error{message: "unexpected postgres status: #{postgres}"}
  #   {:disconnect, err, s}
  # end
  #
  # defp recv_buffer(%{sock: {:gen_tcp, sock}} = s) do
  #   receive do
  #     {:tcp, ^sock, buffer} ->
  #       {:ok, %{s | buffer: buffer}}
  #     {:tcp_closed, ^sock} ->
  #       disconnect(s, :tcp, "async recv", :closed, "")
  #     {:tcp_error, ^sock, reason} ->
  #       disconnect(s, :tcp, "async_recv", reason, "")
  #   after
  #     0 ->
  #       {:ok, %{s | buffer: <<>>}}
  #   end
  # end
  # defp recv_buffer(%{sock: {:ssl, sock}} = s) do
  #   receive do
  #     {:ssl, ^sock, buffer} ->
  #       {:ok, %{s | buffer: buffer}}
  #     {:ssl_closed, ^sock} ->
  #       disconnect(s, :ssl, "async recv", :closed, "")
  #     {:ssl_error, ^sock, reason} ->
  #       disconnect(s, :ssl, "async recv", reason, "")
  #   after
  #     0 ->
  #       {:ok, %{s | buffer: <<>>}}
  #   end
  # end
  #
  # ## Fake [active: once] if buffer not empty
  # defp activate(s, <<>>) do
  #   case setopts(s, [active: :once], <<>>) do
  #     :ok  -> {:ok, %{s | buffer: :active_once}}
  #     other -> other
  #   end
  # end
  # defp activate(%{sock: {mod, sock}} = s, buffer) do
  #   _ = send(self(), {tag(mod), sock, buffer})
  #   {:ok, s}
  # end
  #
  # defp setopts(%{sock: {mod, sock}} = s, opts, buffer) do
  #   case setopts(mod, sock, opts) do
  #     :ok ->
  #       :ok
  #     {:error, reason} ->
  #       disconnect(s, tag(mod), "setopts", reason, buffer)
  #   end
  # end
  #
  # defp setopts(:gen_tcp, sock, opts), do: :inet.setopts(sock, opts)
  # defp setopts(:ssl, sock, opts), do: :ssl.setopts(sock, opts)
  #
  # defp sock_close(%{sock: {mod, sock}}), do: mod.close(sock)
  #
  # defp delete_parameters(%{parameters: ref}) when is_reference(ref) do
  #   Sqlite.DbConnection.Parameters.delete(ref)
  # end
  # defp delete_parameters(_), do: :ok
end

error: pathspec 'lib/sqlite_db_connection/protocol.ex' did not match any file(s) known to git


Disable audio on rtmp/hls streams

Disable audio on rtmp/hls streams

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-media.git/'


set proper names of constraints

set proper names of constraints


[patch] Add context to employee_request details (#1801)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/edenlabllc/ehealth.api.git/'


Content for layout helper test

Content for layout helper test

defmodule WeberHelperContentForTest do
  use ExUnit.Case

  setup_all do
    root = __DIR__ <> "/../weber_fake"
    app_name = Mix.Project.get.project[:app]
    Weber.run_weber(app_name, Example.Route.get_route, :binary.bin_to_list(root), Config.config)
    :ok
  end

  require Weber.Helper.ContentFor

  test "content for layout" do
    file_content = File.read!(app_views("test.html"))
    Weber.Helper.ContentFor.content_for(:layout)

    assert file_content =~ %r/Hello/
  end

  defp app_views(file) do
    __DIR__ <> "/../weber_fake/lib/views/" <> file
  end
end

error: pathspec 'test/helper/weber_helper_content_for_test.exs' did not match any file(s) known to git


fix pagination (#1238)

fix pagination (#1238)


Add tests for HerokuMetadata

Add tests for HerokuMetadata

defmodule AtomStyleTweaks.HerokuMetadata.Test do
  use ExUnit.Case, async: true

  alias AtomStyleTweaks.HerokuMetadata

  setup do
    heroku_metadata = Application.get_env(:atom_style_tweaks, HerokuMetadata)
    keys = Keyword.keys(heroku_metadata)
    test_data = Enum.map(keys, fn(key) -> {key, Atom.to_string(key) <> " test"} end)
    Application.put_env(:atom_style_tweaks, HerokuMetadata, test_data)

    on_exit fn ->
      # Ensure that after every test the configuration is restored (because if you delete a key,
      # the above code won't fix it)
      Application.put_env(:atom_style_tweaks, HerokuMetadata, test_data)
    end

    :ok
  end

  test "on_heroku? returns true if dyno id is set" do
    assert HerokuMetadata.on_heroku?
  end

  test "on_heroku? returns false if dyno id is unset" do
    test_data = Application.get_env(:atom_style_tweaks, HerokuMetadata)
                |> Keyword.delete(:dyno_id)

    Application.put_env(:atom_style_tweaks, HerokuMetadata, test_data)

    refute HerokuMetadata.on_heroku?
  end

  test "app_id returns the expected value" do
    assert HerokuMetadata.app_id == "app_id test"
  end

  test "app_name returns the expected value" do
    assert HerokuMetadata.app_name == "app_name test"
  end

  test "dyno_id returns the expected value" do
    assert HerokuMetadata.dyno_id == "dyno_id test"
  end

  test "release_created_at returns the expected value" do
    assert HerokuMetadata.release_created_at == "release_created_at test"
  end

  test "release_version returns the expected value" do
    assert HerokuMetadata.release_version == "release_version test"
  end

  test "slug_commit returns the expected value" do
    assert HerokuMetadata.slug_commit == "slug_commit test"
  end

  test "slug_description returns the expected value" do
    assert HerokuMetadata.slug_description == "slug_description test"
  end
end

error: pathspec 'test/lib/heroku_metadata_test.exs' did not match any file(s) known to git


add event status on contracts autoterminate (#2913)

fatal: unable to access 'https://github.com/edenlabllc/ehealth.api.git/': The requested URL returned error: 403


Set default name for log actions to "Anonymous"


Add :connection to applications

Add :connection to applications


Increment version [ci skip]

Increment version [ci skip]


cleans up mix application listing

cleans up mix application listing

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/lookuppm/package_finder.git/'


update elixir version

update elixir version

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/mononym/exmud.git/'


Make ttl timings clearer

Make ttl timings clearer


Add get-current-domain and get-domain-by-id queries

defmodule Exsoda.Domain do
  alias Exsoda.Http

  defmodule Current do
    defstruct opts: []
  end

  defmodule ById do
    defstruct id: 0, opts: []
  end

  def current(opts \\ []), do: %Current{opts: Http.options(opts)}

  def by_id(id, opts \\ []) when is_integer(id), do: %ById{id: id, opts: Http.options(opts)}

  def run(%Current{} = q), do: Http.get("/domains", q)
  def run(%ById{id: id} = q), do: Http.get("/domains/#{id}", q)
end

error: pathspec 'lib/exsoda/domain.ex' did not match any file(s) known to git


Refactor VendorModel.get_model/2

Refactor VendorModel.get_model/2


first pass at basic handler for connecting to OTP nodes

defmodule Discovery.Handler.NodeConnect do
  use Discovery.Handler.Behaviour
  @passing "passing"
  @critical "critical"
  @warning "warning"

  def update_services([]), do: :ok
  def update_services([%Discovery.Service{status: @passing} = service|rest]) do
    case node_name(service) do
      Node.self ->
        update_services(rest)
      name ->
        connect(name)
        update_services(rest)
    end
  end
  def update_services([%Discovery.Service{status: _}|rest]), do: update_services(rest)

  #
  # Private API
  #

  defp connect(name) do
    case Node.connect(name) do
      true ->
        IO.puts "CONNECTED TO: #{name}"
      false ->
        IO.puts "FAILED TO CONNECT TO: #{name}"
      :ignored ->
        IO.puts "IGNORED CONNECT TO: #{name}"
    end
  end

  defp node_name(%Discovery.Service{name: service, node: %Discovery.Node{name: node}}) do
    binary_to_atom("#{service}@#{node}")
  end
end

error: pathspec 'lib/discovery/handler/node_connect.ex' did not match any file(s) known to git


Use File.mkdir_p/1 instead of :filelib.ensure_dir/1

fatal: unable to access 'https://github.com/evercam/evercam-media.git/': The requested URL returned error: 403


Wrap Storage operations in a timeout

Wrap Storage operations in a timeout


removing docs for obvious and pure functions

fatal: unable to access 'https://github.com/mononym/exmud.git/': The requested URL returned error: 403


Changed route evercam_models

Changed route evercam_models


refactor the live and test snapshot code


attribute

attribute

defmodule Example do
  @attr "one"
  def first, do: @attr

  @attr "two"
  def second, do: @attr
end

IO.puts "#{Example.first}  #{Example.second}"

error: pathspec 'elixir/99.exs' did not match any file(s) known to git


Added Elixir implementation of 100 doors puzzle

defmodule Doors do
	def run do
		(1..100)
		|> Enum.map(&({&1, :closed}))
		|> open_doors(Enum.to_list(1..100))
		|> output
	end

	def output(list) do
		list
		|> Enum.map(fn({a, b}) -> "Door #{a} is #{b}" end)
		|> Enum.join("\r\n")
		|> IO.inspect
	end

	def open_doors(doors, []), do: doors
	def open_doors(doors, [h | t]) do
		open_doors(doors |> Enum.map(fn({door, state}) -> update_if_divisible(door, state, h) end), t)
	end

	def update_if_divisible(door, state, h) when rem(door, h) == 0 do
		case state do
			:closed ->
				{door, :open}
			:open ->
				{door, :closed}
		end
	end

	def update_if_divisible(door, state, _h), do: {door, state}
end

Doors.run()

error: pathspec 'puzzles/100_Doors/elixir/100_doors.exs' did not match any file(s) known to git


Case example.

Case example.

case File.open("case.ex") do
  {:ok, file} ->
    IO.puts "First line: #{IO.read(file, :line)}"
  {:error, reason} ->
    IO.puts "Failed to open file: #{reason}"
end

error: pathspec 'programming_elixir/chapter12/case.ex' did not match any file(s) known to git


Changed ffmpeg command to extract clip from nvr


fix mistyped parenthesis on Phoenix.Router.Route.build/10

defmodule Phoenix.Router.Route do
  # This module defines the Route struct that is used
  # throughout Phoenix's router. This struct is private
  # as it contains internal routing information.
  @moduledoc false

  alias Phoenix.Router.Route

  @doc """
  The `Phoenix.Router.Route` struct. It stores:

    * :verb - the HTTP verb as an upcased string
    * :kind - the kind of route, one of `:match`, `:forward`
    * :path - the normalized path as string
    * :host - the request host or host prefix
    * :plug - the plug module
    * :opts - the plug options
    * :helper - the name of the helper as a string (may be nil)
    * :private - the private route info
    * :assigns - the route info
    * :pipe_through - the pipeline names as a list of atoms

  """

  defstruct [:verb, :kind, :path, :host, :plug, :opts,
             :helper, :private, :pipe_through, :assigns]

  @type t :: %Route{}

  @doc """
  Receives the verb, path, plug, options and helper
  and returns a `Phoenix.Router.Route` struct.
  """
  @spec build(:match | :forward, String.t, String.t, String.t | nil, atom, atom, atom | nil, atom, %{}, %{}) :: t
  def build(kind, verb, path, host, plug, opts, helper, pipe_through, private, assigns)
      when is_atom(verb) and (is_binary(host) or is_nil(host)) and
           is_atom(plug) and (is_binary(helper) or is_nil(helper)) and
           is_list(pipe_through) and is_map(private) and is_map(assigns)
           and kind in [:match, :forward] do

    %Route{kind: kind, verb: verb, path: path, host: host, private: private,
           plug: plug, opts: opts, helper: helper,
           pipe_through: pipe_through, assigns: assigns}
  end

  @doc """
  Builds the expressions used by the route.
  """
  def exprs(route) do
    {path, binding} = build_path_and_binding(route)

    %{path: path,
      host: build_host(route.host),
      verb_match: verb_match(route.verb),
      binding: binding,
      dispatch: build_dispatch(route, binding)}
  end

  defp verb_match(:*), do: Macro.var(:_verb, nil)
  defp verb_match(verb), do: verb |> to_string() |> String.upcase()

  defp build_path_and_binding(%Route{path: path} = route) do
    {params, segments} = case route.kind do
      :forward -> Plug.Router.Utils.build_path_match(path <> "/*_forward_path_info")
      :match   -> Plug.Router.Utils.build_path_match(path)
    end

    binding = for var <- params, var != :_forward_path_info do
      {Atom.to_string(var), Macro.var(var, nil)}
    end

    {segments, binding}
  end

  defp build_host(host) do
    cond do
      is_nil(host)             -> quote do: _
      String.last(host) == "." -> quote do: unquote(host) <> _
      true                     -> host
    end
  end

  defp build_dispatch(route, binding) do
    exprs =
      [maybe_binding(binding),
       maybe_merge(:private, route.private),
       maybe_merge(:assigns, route.assigns),
       build_pipes(route)]

    {:__block__, [], Enum.filter(exprs, & &1 != nil)}
  end

  defp maybe_merge(key, data) do
    if map_size(data) > 0 do
      quote do
        var!(conn) =
          update_in var!(conn).unquote(key), &Map.merge(&1, unquote(Macro.escape(data)))
      end
    end
  end

  defp maybe_binding([]), do: nil
  defp maybe_binding(binding) do
    quote do
      var!(conn) =
        update_in var!(conn).params, &Map.merge(&1, unquote({:%{}, [], binding}))
    end
  end

  defp build_pipes(%Route{kind: :forward} = route) do
    {_params, fwd_segments} = Plug.Router.Utils.build_path_match(route.path)
    opts = route.plug.init(route.opts)

    quote do
      var!(conn)
      |> Plug.Conn.put_private(:phoenix_pipelines, unquote(route.pipe_through))
      |> Plug.Conn.put_private(:phoenix_route, fn conn ->
        Phoenix.Router.Route.forward(conn, unquote(fwd_segments),
                                     unquote(route.plug), unquote(opts))
      end)
    end |> pipe_through(route)
  end

  defp build_pipes(route) do
    quote do
      var!(conn)
      |> Plug.Conn.put_private(:phoenix_pipelines, unquote(route.pipe_through))
      |> Plug.Conn.put_private(:phoenix_route, fn conn ->
        # We need to store this in a variable so the compiler
        # does not see a call and then suddenly start tracking
        # changes in the controller.
        plug = unquote(route.plug)
        opts = plug.init(unquote(route.opts))
        plug.call(conn, opts)
      end)
    end |> pipe_through(route)
  end

  defp pipe_through(initial, route) do
    plugs = route.pipe_through |> Enum.reverse |> Enum.map(&{&1, [], true})
    {conn, body} = Plug.Builder.compile(__ENV__, plugs, [])
    quote do
      unquote(conn) = unquote(initial)
      unquote(body)
    end
  end

  @doc """
  Forwards requests to another Plug at a new path.
  """
  def forward(%Plug.Conn{path_info: path, script_name: script} = conn, fwd_segments, target, opts) do
    new_path = path -- fwd_segments
    {base, ^new_path} = Enum.split(path, length(path) - length(new_path))
    conn = %{conn | path_info: new_path, script_name: script ++ base} |> target.call(opts)
    %{conn | path_info: path, script_name: script}
  end

  @doc """
  Validates and returns the list of forward path segments.

  Raises RuntimeError plug is already forwarded or path contains
  a dynamic segment.
  """
  def forward_path_segments(path, plug, phoenix_forwards) do
    case Plug.Router.Utils.build_path_match(path) do
      {[], path_segments} ->
        if phoenix_forwards[plug] do
          raise ArgumentError, "`#{inspect plug}` has already been forwarded to. A module can only be forwarded a single time."
        end
        path_segments
      _ ->
        raise ArgumentError, "Dynamic segment `\"#{path}\"` not allowed when forwarding. Use a static path instead."
    end
  end
end

defmodule Phoenix.Router.Route do
  # This module defines the Route struct that is used
  # throughout Phoenix's router. This struct is private
  # as it contains internal routing information.
  @moduledoc false

  alias Phoenix.Router.Route

  @doc """
  The `Phoenix.Router.Route` struct. It stores:

    * :verb - the HTTP verb as an upcased string
    * :kind - the kind of route, one of `:match`, `:forward`
    * :path - the normalized path as string
    * :host - the request host or host prefix
    * :plug - the plug module
    * :opts - the plug options
    * :helper - the name of the helper as a string (may be nil)
    * :private - the private route info
    * :assigns - the route info
    * :pipe_through - the pipeline names as a list of atoms

  """

  defstruct [:verb, :kind, :path, :host, :plug, :opts,
             :helper, :private, :pipe_through, :assigns]

  @type t :: %Route{}

  @doc """
  Receives the verb, path, plug, options and helper
  and returns a `Phoenix.Router.Route` struct.
  """
  @spec build(:match | :forward, String.t, String.t, String.t | nil, atom, atom, atom | nil, atom, %{}, %{}) :: t
  def build(kind, verb, path, host, plug, opts, helper, pipe_through, private, assigns)
      when is_atom(verb) and (is_binary(host) or is_nil(host)) and
           is_atom(plug) and (is_binary(helper) or is_nil(helper)) and
           is_list(pipe_through) and is_map(private and is_map(assigns))
           and kind in [:match, :forward] do

    %Route{kind: kind, verb: verb, path: path, host: host, private: private,
           plug: plug, opts: opts, helper: helper,
           pipe_through: pipe_through, assigns: assigns}
  end

  @doc """
  Builds the expressions used by the route.
  """
  def exprs(route) do
    {path, binding} = build_path_and_binding(route)

    %{path: path,
      host: build_host(route.host),
      verb_match: verb_match(route.verb),
      binding: binding,
      dispatch: build_dispatch(route, binding)}
  end

  defp verb_match(:*), do: Macro.var(:_verb, nil)
  defp verb_match(verb), do: verb |> to_string() |> String.upcase()

  defp build_path_and_binding(%Route{path: path} = route) do
    {params, segments} = case route.kind do
      :forward -> Plug.Router.Utils.build_path_match(path <> "/*_forward_path_info")
      :match   -> Plug.Router.Utils.build_path_match(path)
    end

    binding = for var <- params, var != :_forward_path_info do
      {Atom.to_string(var), Macro.var(var, nil)}
    end

    {segments, binding}
  end

  defp build_host(host) do
    cond do
      is_nil(host)             -> quote do: _
      String.last(host) == "." -> quote do: unquote(host) <> _
      true                     -> host
    end
  end

  defp build_dispatch(route, binding) do
    exprs =
      [maybe_binding(binding),
       maybe_merge(:private, route.private),
       maybe_merge(:assigns, route.assigns),
       build_pipes(route)]

    {:__block__, [], Enum.filter(exprs, & &1 != nil)}
  end

  defp maybe_merge(key, data) do
    if map_size(data) > 0 do
      quote do
        var!(conn) =
          update_in var!(conn).unquote(key), &Map.merge(&1, unquote(Macro.escape(data)))
      end
    end
  end

  defp maybe_binding([]), do: nil
  defp maybe_binding(binding) do
    quote do
      var!(conn) =
        update_in var!(conn).params, &Map.merge(&1, unquote({:%{}, [], binding}))
    end
  end

  defp build_pipes(%Route{kind: :forward} = route) do
    {_params, fwd_segments} = Plug.Router.Utils.build_path_match(route.path)
    opts = route.plug.init(route.opts)

    quote do
      var!(conn)
      |> Plug.Conn.put_private(:phoenix_pipelines, unquote(route.pipe_through))
      |> Plug.Conn.put_private(:phoenix_route, fn conn ->
        Phoenix.Router.Route.forward(conn, unquote(fwd_segments),
                                     unquote(route.plug), unquote(opts))
      end)
    end |> pipe_through(route)
  end

  defp build_pipes(route) do
    quote do
      var!(conn)
      |> Plug.Conn.put_private(:phoenix_pipelines, unquote(route.pipe_through))
      |> Plug.Conn.put_private(:phoenix_route, fn conn ->
        # We need to store this in a variable so the compiler
        # does not see a call and then suddenly start tracking
        # changes in the controller.
        plug = unquote(route.plug)
        opts = plug.init(unquote(route.opts))
        plug.call(conn, opts)
      end)
    end |> pipe_through(route)
  end

  defp pipe_through(initial, route) do
    plugs = route.pipe_through |> Enum.reverse |> Enum.map(&{&1, [], true})
    {conn, body} = Plug.Builder.compile(__ENV__, plugs, [])
    quote do
      unquote(conn) = unquote(initial)
      unquote(body)
    end
  end

  @doc """
  Forwards requests to another Plug at a new path.
  """
  def forward(%Plug.Conn{path_info: path, script_name: script} = conn, fwd_segments, target, opts) do
    new_path = path -- fwd_segments
    {base, ^new_path} = Enum.split(path, length(path) - length(new_path))
    conn = %{conn | path_info: new_path, script_name: script ++ base} |> target.call(opts)
    %{conn | path_info: path, script_name: script}
  end

  @doc """
  Validates and returns the list of forward path segments.

  Raises RuntimeError plug is already forwarded or path contains
  a dynamic segment.
  """
  def forward_path_segments(path, plug, phoenix_forwards) do
    case Plug.Router.Utils.build_path_match(path) do
      {[], path_segments} ->
        if phoenix_forwards[plug] do
          raise ArgumentError, "`#{inspect plug}` has already been forwarded to. A module can only be forwarded a single time."
        end
        path_segments
      _ ->
        raise ArgumentError, "Dynamic segment `\"#{path}\"` not allowed when forwarding. Use a static path instead."
    end
  end
end


Player socket tests

Player socket tests

defmodule Battleship.PlayerSocketTest do
  use Battleship.ChannelCase

  alias Battleship.Player

  @id "test-id"
  @name "John"

  setup do
    {:ok, socket} = connect(Battleship.PlayerSocket, %{"id" => @id, "name" => @name})

    {:ok, socket: socket}
  end

  test "assigns player", %{socket: socket} do
    assert socket.assigns.player == %Player{id: @id, name: @name}
  end

  test "assigns id", %{socket: socket} do
    assert socket.id == "players_socket:#{@id}"
  end
end

error: pathspec 'test/channels/player_socket_test.exs' did not match any file(s) known to git


Add a test (careful, it will actually call http for real)

defmodule GitHubTest do
  use ExUnit.Case

  test "fetches data" do
    import Issues.GitHub, only: [ fetch_issues: 2]

    fetch_issues("thbar", "kiba")
  end
end

error: pathspec 'samples/issues/test/github_test.exs' did not match any file(s) known to git


add it to the list

add it to the list

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/tchoutri/magnetissimo.git/'


Removed Pry.

Removed Pry.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-admin.git/'


Added intercom fields default value

Added intercom fields default value

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-media.git/'


Add difference highlighting examples

Add difference highlighting examples

fatal: unable to access 'https://github.com/kimshrier/elixir.git/': The requested URL returned error: 403


Fixed ubiquiti cameras not recognized correctly

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-server.git/'


check valid jpeg using util function

check valid jpeg using util function


Run snapshot deletion hourly

Run snapshot deletion hourly


Fix archive exid generation

Fix archive exid generation


Adds params to the call to paginate

Adds params to the call to paginate

defmodule ElixirStatus.PostingController do
  use ElixirStatus.Web, :controller
  use Timex

  alias ElixirStatus.Publisher
  alias ElixirStatus.Posting

  plug :authenticate, :logged_in when action in [:new, :create, :edit, :update, :delete]
  plug :load_posting when action in [:edit, :update, :delete, :show]
  plug :authenticate, :same_user_or_admin when action in [:edit, :update, :delete]
  plug :scrub_params, "posting" when action in [:create, :update]

  def index(conn, params) do
    conn
      |> ElixirStatus.Impressionist.record("frontpage")
      |> render("index.html", postings: get_all(params),
                              created_posting: load_created_posting(conn))
  end

  def new(conn, _params) do
    changeset = Posting.changeset(%Posting{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"posting" => posting_params}) do
    posting_params = posting_params
                      |> extract_valid_params
                      |> to_create_params(conn)
    changeset = Posting.changeset(%Posting{}, posting_params)

    if changeset.valid? do
      posting = Repo.insert!(changeset)
      posting |> Publisher.after_create

      conn
        |> put_session(:created_posting_uid, posting.uid)
        |> redirect(to: posting_path(conn, :index))
    else
      render(conn, "new.html", changeset: changeset)
    end
  end

  def show(conn, %{"permalink" => _}) do
    show(conn, %{"id" => current_posting(conn)})
  end

  def show(conn, %{"id" => _}) do
    posting = current_posting(conn)

    conn
      |> ElixirStatus.Impressionist.record("detail", "postings", posting.uid)
      |> render("show.html", posting: posting)
  end

  def edit(conn, %{"id" => id}) do
    posting = Repo.get!(Posting, id)
    changeset = Posting.changeset(posting)
    render(conn, "edit.html", posting: posting, changeset: changeset)
  end

  def update(conn, %{"id" => id, "posting" => posting_params}) do
    posting = Repo.get!(Posting, id)
    posting_params = posting_params |> extract_valid_params
    changeset = Posting.changeset(posting, posting_params)

    if changeset.valid? do
      Repo.update!(changeset)
        |> Publisher.after_update

      conn
        |> put_flash(:info, "Posting updated successfully.")
        |> redirect(to: posting_path(conn, :index))
    else
      render(conn, "edit.html", posting: posting, changeset: changeset)
    end
  end

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

    conn
      |> put_flash(:info, "Posting deleted successfully.")
      |> redirect(to: posting_path(conn, :index))
  end

  defp load_posting(conn, _) do
    posting = case conn do
      %{params: %{"id" => id}} -> get_by_id(id)
      %{params: %{"permalink" => permalink}} -> get_by_permalink(permalink)
      _ -> nil
    end
    if is_nil(posting) do
      conn
        |> put_status(:not_found)
        |> render(ElixirStatus.ErrorView, "404.html")
        |> halt
    else
      conn
        |> assign(:posting, posting)
    end
  end

  def load_created_posting(conn) do
    uid = get_session(conn, :created_posting_uid)
    case load_created_posting_by_uid(uid)  do
      nil ->
        conn
          |> put_session(:created_posting_uid, nil)
        nil
      posting -> posting
    end
  end

  def load_created_posting_by_uid(nil), do: nil

  def load_created_posting_by_uid(uid) do
    get_by_uid(uid)
    # TODO: return nil if posting is older than 3 minutes
  end

  defp authenticate(conn, :logged_in) do
    case Auth.current_user(conn) do
      nil -> redirect(conn, to: "/") |> halt
      _   -> conn
    end
  end

  defp authenticate(conn, :same_user_or_admin) do
    if Auth.admin?(conn) || Auth.belongs_to_current_user?(conn, current_posting(conn)) do
      conn
    else
      redirect(conn, to: "/") |> halt
    end
  end

  defp current_posting(conn) do
    conn.assigns[:posting]
  end

  defp extract_valid_params(%{"title" => title, "text" => text}) do
    %{"title" => String.strip(title || ""), "text" => String.strip(text || "")}
  end

  defp extract_valid_params(%{"title" => title, "text" => text, "scheduled_at" => scheduled_at}) do
    %{"title" => String.strip(title), "text" => String.strip(text), "scheduled_at" => scheduled_at}
  end

  defp extract_valid_params(_) do
    %{}
  end

  defp to_create_params(params, conn) do
    uid = ElixirStatus.UID.generate(Posting)
    %{
      user_id: Auth.current_user(conn).id,
      uid: uid,
      permalink: Publisher.permalink(uid, params["title"]),
      text: params["text"],
      title: params["title"],
      scheduled_at: params["scheduled_at"],
      published_at: Ecto.DateTime.utc,
      public: true
    }
  end

  defp get_all(params) do
    query = from(p in Posting, where: p.public == ^true)
    query |> Ecto.Query.preload(:user) |> Repo.paginate(params)
  end

  defp get_by_id(id) do
    query = from(p in Posting, where: p.id == ^id)
    query |> Ecto.Query.preload(:user) |> Repo.one
  end

  defp get_by_permalink(permalink) do
    String.split(permalink, "-") |> Enum.at(0) |> get_by_uid
  end

  defp get_by_uid(uid) do
    query = from(p in Posting, where: p.uid == ^uid)
    query |> Ecto.Query.preload(:user) |> Repo.one
  end
end

defmodule ElixirStatus.PostingController do
  use ElixirStatus.Web, :controller
  use Timex

  alias ElixirStatus.Publisher
  alias ElixirStatus.Posting

  plug :authenticate, :logged_in when action in [:new, :create, :edit, :update, :delete]
  plug :load_posting when action in [:edit, :update, :delete, :show]
  plug :authenticate, :same_user_or_admin when action in [:edit, :update, :delete]
  plug :scrub_params, "posting" when action in [:create, :update]

  def index(conn, params) do
    conn
      |> ElixirStatus.Impressionist.record("frontpage")
      |> render("index.html", postings: get_all(params),
                              created_posting: load_created_posting(conn))
  end

  def new(conn, _params) do
    changeset = Posting.changeset(%Posting{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"posting" => posting_params}) do
    posting_params = posting_params
                      |> extract_valid_params
                      |> to_create_params(conn)
    changeset = Posting.changeset(%Posting{}, posting_params)

    if changeset.valid? do
      posting = Repo.insert!(changeset)
      posting |> Publisher.after_create

      conn
        |> put_session(:created_posting_uid, posting.uid)
        |> redirect(to: posting_path(conn, :index))
    else
      render(conn, "new.html", changeset: changeset)
    end
  end

  def show(conn, %{"permalink" => _}) do
    show(conn, %{"id" => current_posting(conn)})
  end

  def show(conn, %{"id" => _}) do
    posting = current_posting(conn)

    conn
      |> ElixirStatus.Impressionist.record("detail", "postings", posting.uid)
      |> render("show.html", posting: posting)
  end

  def edit(conn, %{"id" => id}) do
    posting = Repo.get!(Posting, id)
    changeset = Posting.changeset(posting)
    render(conn, "edit.html", posting: posting, changeset: changeset)
  end

  def update(conn, %{"id" => id, "posting" => posting_params}) do
    posting = Repo.get!(Posting, id)
    posting_params = posting_params |> extract_valid_params
    changeset = Posting.changeset(posting, posting_params)

    if changeset.valid? do
      Repo.update!(changeset)
        |> Publisher.after_update

      conn
        |> put_flash(:info, "Posting updated successfully.")
        |> redirect(to: posting_path(conn, :index))
    else
      render(conn, "edit.html", posting: posting, changeset: changeset)
    end
  end

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

    conn
      |> put_flash(:info, "Posting deleted successfully.")
      |> redirect(to: posting_path(conn, :index))
  end

  defp load_posting(conn, _) do
    posting = case conn do
      %{params: %{"id" => id}} -> get_by_id(id)
      %{params: %{"permalink" => permalink}} -> get_by_permalink(permalink)
      _ -> nil
    end
    if is_nil(posting) do
      conn
        |> put_status(:not_found)
        |> render(ElixirStatus.ErrorView, "404.html")
        |> halt
    else
      conn
        |> assign(:posting, posting)
    end
  end

  def load_created_posting(conn) do
    uid = get_session(conn, :created_posting_uid)
    case load_created_posting_by_uid(uid)  do
      nil ->
        conn
          |> put_session(:created_posting_uid, nil)
        nil
      posting -> posting
    end
  end

  def load_created_posting_by_uid(nil), do: nil

  def load_created_posting_by_uid(uid) do
    get_by_uid(uid)
    # TODO: return nil if posting is older than 3 minutes
  end

  defp authenticate(conn, :logged_in) do
    case Auth.current_user(conn) do
      nil -> redirect(conn, to: "/") |> halt
      _   -> conn
    end
  end

  defp authenticate(conn, :same_user_or_admin) do
    if Auth.admin?(conn) || Auth.belongs_to_current_user?(conn, current_posting(conn)) do
      conn
    else
      redirect(conn, to: "/") |> halt
    end
  end

  defp current_posting(conn) do
    conn.assigns[:posting]
  end

  defp extract_valid_params(%{"title" => title, "text" => text}) do
    %{"title" => String.strip(title || ""), "text" => String.strip(text || "")}
  end

  defp extract_valid_params(%{"title" => title, "text" => text, "scheduled_at" => scheduled_at}) do
    %{"title" => String.strip(title), "text" => String.strip(text), "scheduled_at" => scheduled_at}
  end

  defp extract_valid_params(_) do
    %{}
  end

  defp to_create_params(params, conn) do
    uid = ElixirStatus.UID.generate(Posting)
    %{
      user_id: Auth.current_user(conn).id,
      uid: uid,
      permalink: Publisher.permalink(uid, params["title"]),
      text: params["text"],
      title: params["title"],
      scheduled_at: params["scheduled_at"],
      published_at: Ecto.DateTime.utc,
      public: true
    }
  end

  defp get_all(params) do
    query = from(p in Posting, where: p.public == ^true)
    query |> Ecto.Query.preload(:user) |> Repo.paginate
  end

  defp get_by_id(id) do
    query = from(p in Posting, where: p.id == ^id)
    query |> Ecto.Query.preload(:user) |> Repo.one
  end

  defp get_by_permalink(permalink) do
    String.split(permalink, "-") |> Enum.at(0) |> get_by_uid
  end

  defp get_by_uid(uid) do
    query = from(p in Posting, where: p.uid == ^uid)
    query |> Ecto.Query.preload(:user) |> Repo.one
  end
end


spike from meetup

spike from meetup

defmodule Raxx.BasicAuth do
  @moduledoc """
  Add protection to a Raxx application using Basic Authentication.

  Basic Authentication is specified in RFC 7617 (which obsoletes RFC 2617).

  ## Examples
  # Authenticate is Authenticated

  ## NOTE

  The Basic authentication scheme is not a secure method of user authentication
  https://tools.ietf.org/html/rfc7617#section-4

  """

  defmacro __using__(_opts) do
    quote do
      def authenticate(request) do
        case get_credential(request) do
          {user_id, password} ->
            verify_credentials(user_id, password)
          {:error, reason} ->
            {:error, reason}
        end
      end
# TODO define your own verify_credentials -> user
    end
  end

  @authentication_header "authorization"
  @default_realm "Site"
  @default_charset "UTF-8"

  def set_authentication(request, user_id, password) do
    request
    |> set_header(@authentication_header, authentication_header(user_id, password))
  end

  # TODO expose credentials function
  def authenticate(request) do
    # Raxx does not need to include OK
    # ~>> fetch_authentication_header
    case Raxx.get_header(request, @authentication_header) do
      nil ->
        {:error, :not_authorization_header}
      authorization ->
        case String.split(authorization, " ", parts: 2) do
          ["Basic", encoded] ->
            case Base.decode64(encoded) do
              {:ok, user_pass} ->
                case String.split(authorization, " ", parts: 2) do
                  [user_id, password] ->
                    :ok
                  _ ->
                    {:error, :invalid_user_pass}
                end
              :error ->
                {:error, :unable_to_decode_user_pass}
            end
          [unknown, _] ->
            {:error, :unknown_authentication_method}
          _ ->
            {:error, :invalid_authentication_header}
        end
    end
  end

  @doc """
  Generate a response to a request that failed to authenticate.

  ## Options

  - **realm:**
  """
  def unauthorized(options) do
    realm = Keyword.get(options, :realm, @default_realm)
    charset = Keyword.get(options, :charset, @default_charset)

    response(:unauthorized)
    |> set_header("www-authenticate", challenge_header(realm, charset))
    |> set_body("401 Unauthorized")
  end

  @doc """

  ## Examples

      iex> authentication_header("Aladdin", "open sesame")
      Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
  """
  def authentication_header(user_id, password) do
    "Basic " <> Base.encode64(user_pass(user_id, password))
  end

  @doc """
  Generate the challenge header sent by a server.

  This challenge is sent to a client in the `www-authenticate` header.
  Use this challenge to prompt a client into providing basic authentication credentials.

  ### Notes

  - The only valid charset is `UTF-8`; https://tools.ietf.org/html/rfc7617#section-2.1.
    A `nil` can be provided to this function to omit the parameter.

  - Validation should be added for the parameter values to ensure they only accept valid values.

  """
  def challenge_header(realm, nil) do
    "Basic realm=\"#{realm}\""
  end
  def challenge_header(realm, charset) do
    "Basic realm=\"#{realm}\", charset=\"#{charset}\""
  end

  # The user-id and password MUST NOT contain any control characters (see
  # "CTL" in Appendix B.1 of [RFC5234]).
  defp user_pass(user_id, password) do
    :ok = case :binary.match(user_id, [":"]) do
      {_, _} ->
        raise "a user-id containing a colon character is invalid"

      :nomatch ->
        :ok
    end

    user_id <> ":" <> password
  end
end

error: pathspec 'lib/raxx/basic_auth.ex' did not match any file(s) known to git


elixir solution - todo

elixir solution - todo

# TODO

defmodule Sudoku do
    defp to_int(v) do
        v - 48
    end

    def line_column(idx) do
        {div(idx, 9), rem(idx, 9)}
    end

    def read_input(str) do
         Stream.with_index(str) |>
         Stream.map(fn({v, idx}) -> {to_int(v), line_column(idx)} end)
    end

    def next_empty(sudoku) do
        Stream.filter(sudoku, fn({v, idx}) -> v == 0 end)
        Stream.take(1) |>
        Stream.map(fn({v, idx}) -> idx end)
        Enum.to_list |>
        List.first
    end

    def line(sudoku, n) do
        Stream.filter(sudoku, fn({v, {i, j}}) -> i == n end)
    end

    def column(sudoku, n) do
        Stream.filter(sudoku, fn({v, {i, j}}) -> j == n end)
    end

    def square(sudoku, i, j) do
    end
end

error: pathspec 'sudoku.exs' did not match any file(s) known to git


Add auth controller with hard-coded redirect url

defmodule MyApp_7191136.AuthController do
  use MyApp_7191136.Web, :controller

  def index(conn, _params) do
    redirect conn, external: "https://www.fitbit.com/oauth2/authorize"
  end
end

error: pathspec 'web/controllers/auth_controller.ex' did not match any file(s) known to git


can now create user

can now create user

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/jacklin10/rumbl.git/'


added routing logic for HTML-based pages

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/acoburn/acdc-phoenix.git/'


fix: create le v2 response (#5083)

fix: create le v2 response (#5083)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/edenlabllc/ehealth.api.git/'


Add Die module for easy random "rolls"

Add Die module for easy random "rolls"

fatal: unable to access 'https://github.com/joshforisha/merchant-quest.git/': The requested URL returned error: 403


chore: pipe

chore: pipe

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/rockdragon/julia-programming.git/'


MR:show proper legal_entity_id

MR:show proper legal_entity_id

fatal: unable to access 'https://github.com/edenlabllc/ehealth.api.git/': The requested URL returned error: 403


Don't reuse cached camera when streaming


Add RevisionSerializer

Add RevisionSerializer

defmodule PhoenixFrontendDeploys.RevisionSerializer do
  use JaSerializer

  attributes [:revision, :mtime, :size]
end

error: pathspec 'lib/serializers/revision_serializer.ex' did not match any file(s) known to git


bump version

bump version

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/bit-engine/dustbin.git/'


Increase thumbnail timeout

Increase thumbnail timeout

fatal: unable to access 'https://github.com/evercam/evercam-media.git/': The requested URL returned error: 403


Fixed timestamp format in the controller request

defmodule EvercamMedia.SnapshotController do
  use Phoenix.Controller
  use Timex
  import EvercamMedia.Snapshot
  require Logger
  plug :action

  def show(conn, params) do
    [code, image] = snapshot(params["id"], params["token"])
    response(conn, code, image, params["id"])
  end

  defp response(conn, 200, image, _camera_id) do
    conn
    |> put_status(200)
    |> put_resp_header("content-type", "image/jpg")
    |> put_resp_header("access-control-allow-origin", "*")
    |> text image
  end

  defp response(conn, code, _, _) do
    conn
    |> put_status(code)
    |> put_resp_header("access-control-allow-origin", "*")
    |> text "We failed to retrieve a snapshot from the camera"
  end

  defp snapshot(camera_id, token) do
    try do
      [url, auth, credentials, time, _] = decode_request_token(token)
      # check_token_expiry(time)
      response = fetch(url, auth)
      check_jpg(response)
      store(camera_id, response)

      [200, response]
    rescue
      error in [FunctionClauseError] ->
        error_handler(error)
        [401, fallback]
      _error in [SnapshotError] ->
        [504, fallback]
      _error in [HTTPotion.HTTPError] ->
        timestamp = Ecto.DateTime.utc
        update_camera_status(camera_id, timestamp, false)
        [504, fallback]
      _error ->
        error_handler(_error)
        [500, fallback]
    end
  end

  defp decode_request_token(token) do
    {_, encrypted_message} = Base.url_decode64(token)
    message = :crypto.block_decrypt(
      :aes_cbc256,
      System.get_env["SNAP_KEY"],
      System.get_env["SNAP_IV"],
      encrypted_message
    )
    String.split(message, "|")
  end

  defp check_token_expiry(time) do
    token_time = DateFormat.parse! time, "{ISOz}"
    token_time = Date.shift token_time, mins: 5

    if Date.now > token_time do
      raise FunctionClauseError
    end
  end
end

defmodule EvercamMedia.SnapshotController do
  use Phoenix.Controller
  use Timex
  import EvercamMedia.Snapshot
  require Logger
  plug :action

  def show(conn, params) do
    [code, image] = snapshot(params["id"], params["token"])
    response(conn, code, image, params["id"])
  end

  defp response(conn, 200, image, _camera_id) do
    conn
    |> put_status(200)
    |> put_resp_header("content-type", "image/jpg")
    |> put_resp_header("access-control-allow-origin", "*")
    |> text image
  end

  defp response(conn, code, _, _) do
    conn
    |> put_status(code)
    |> put_resp_header("access-control-allow-origin", "*")
    |> text "We failed to retrieve a snapshot from the camera"
  end

  defp snapshot(camera_id, token) do
    try do
      [url, auth, credentials, time, _] = decode_request_token(token)
      # check_token_expiry(time)
      response = fetch(url, auth)
      check_jpg(response)
      store(camera_id, response)

      [200, response]
    rescue
      error in [FunctionClauseError] ->
        error_handler(error)
        [401, fallback]
      error in [HTTPotion.HTTPError] ->
        timestamp = Timex.Date.convert(Timex.Date.now, :secs)
        update_camera_status(camera_id, timestamp, false)
        error_handler(error)
        [504, fallback]
      _error ->
        error_handler(_error)
        [500, fallback]
    end
  end

  defp decode_request_token(token) do
    {_, encrypted_message} = Base.url_decode64(token)
    message = :crypto.block_decrypt(
      :aes_cbc256,
      System.get_env["SNAP_KEY"],
      System.get_env["SNAP_IV"],
      encrypted_message
    )
    String.split(message, "|")
  end

  defp check_token_expiry(time) do
    token_time = DateFormat.parse! time, "{ISOz}"
    token_time = Date.shift token_time, mins: 5

    if Date.now > token_time do
      raise FunctionClauseError
    end
  end
end


fatorial 0 = 1
fatorial n = n * fatorial (n - 1)

function fatorial(0) {
    return 1;
}
function fatorial(n) {
    return n * fatorial(n - 1);
}

#https://pt.stackoverflow.com/q/445451/101

error: pathspec 'Functional/PatternMatching.exs' did not match any file(s) known to git


expressions for key in maps

expressions for key in maps

name = "Jose Valim"

%{ String.downcase(name) => name }
|> IO.inspect

error: pathspec 'elixir/21.exs' did not match any file(s) known to git


function|> multiple body

function|> multiple body

handle_open = fn
  {:ok, file} -> "Read data: #{IO.read(file, :line)}"
  {_, error} -> "Error: #{:file.format_error(error)}"
end

handle_open.(File.open("./passwd"))
|> IO.puts

handle_open.(File.open("nonexistent"))
|> IO.puts

error: pathspec 'elixir/33.exs' did not match any file(s) known to git


Added stacktrace to error logging

Added stacktrace to error logging

fatal: unable to access 'https://github.com/shankardevy/evercam-media.git/': The requested URL returned error: 403


Add dummy docs cfg

Add dummy docs cfg

error: pathspec 'config/docs.exs' did not match any file(s) known to git


Add prod settings for heroku

Add prod settings for heroku

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/oinopion/elixir-inn.git/'


names of modules is atoms

names of modules is atoms

error: pathspec 'elixir/143.exs' did not match any file(s) known to git


[minor] improve PR (#2577)

[minor] improve PR (#2577)


Use sharer_api_key intsead of sharee_api_key for logging in to Sharer account.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-admin.git/'


slurp

slurp

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/atweiden/scripts.git/'


Add SeedLongerRetro task

Add SeedLongerRetro task

  - provides devs a simple means of persisting a retrospective with numerous long ideas so that they can develop UI for handling said cases
    - example, you may want to test how overflowing lists look/behave, or make sure the grouping interface is big enough to handle, say, an 75 idea max

defmodule Mix.Tasks.SeedLongerRetro do
  use Mix.Task

  alias RemoteRetro.{Repo, Retro, Idea}

  @shortdoc "Provides a simple means of seeding longer retros with varying idea counts/lengths"
  def run(_) do
    Mix.Task.run("app.start")

    IO.puts("\n#{IO.ANSI.green()}Persisting records for a long retro...#{IO.ANSI.reset()}\n")

    retro = Repo.insert!(%Retro{facilitator_id: 1, format: "Happy/Sad/Confused", stage: "idea-generation"})

    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "As*gm i**Is*gm is*gm is*gm igm i*Is*gm i**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "Ath**Is*gm i*gm i*gm igm i*gm igm i**thp**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "Agm i*gm i*gm is*gm i*gm igm th**Is*gm is*gm i/ igm is*gm igm igm igm is*gm is*gm i*"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*Is*gm iIs*gm i***!"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A* ith**Is*gm i*gm igm i*Is*gm igm i**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*Is*gm i**Is*gm i*Is*gm in**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A**Is*gm igm i*gm i*Is*gm i*gm i*gm in**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*gm iIs*gm i*gm i*gm i*Is*gm iIs*gm i**th."})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*Is*gm is*gm i**th**cats?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A* i*Is*gm iIs*gm is*gm i**Is*gm (s*gm i*Is*gm & igm i**th**skipsN)"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*th**Is*gm igm i**Is*gm i**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*Is*gm i*gm i**Is*gm i*gm i**+p**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*: i*gm i*gm is*gm is*gm i*gm igm i**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A* is*gm igm iIs*gm th**Is*gm i*gm i*th**Is*gm i*Is*gm i**th**/m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*Is*gm i*Is*gm iIs*gm igm i*gm igm i*gm i*gm igm i*"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A**Is*gm ith**Is*gm i*gm is*gm i***, i*gm i*Is*gm i*gm i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "Ath**Is*gm i*gm i*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "Agm i*gm i**Is*gm igm i*gm i**. igm is*gm igm igm i*gm i**Is*gm igm iIs*gm ith**Is*gm igm i**."})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A* i**Is*gm is*gm ip**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*gm igm i*Is*gm i*gm igm i*gm i**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A* i*gm igm i*Is*gm i*gm is*gm ith**Is*gm i*gm ith**Is*gm i*gm is*gm i*gm (Packers/Bears) gm i**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*Is*gm igm i*Is*gm i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*t*c*o**th**Is*gm : i**th/ i*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A* gm i*gm igm iIs*gm igm igm i*gm i*gm iIs*gm igm i**Is*gm igm i*th**Is*gm i*Is*gm i**th?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "Agm i*gm i**th**Is*gm i*gm iIs*gm (**********, is*gm i**th*, i**)"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*gm i**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "As*gm th**Is*gm i*gm i**Is*gm i*gm i*gm iIs*gm i**th*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*gm i*gm i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "As*gm i*gm igm i*Is*gm i*gm i*gm is*gm i*gm - i*gm i**th! i*gm igm i*gm igm igm iIs*gm is*gm i*gm (gm i**Is*gm -> i**th***)."})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "Agm i*Is*gm ith**Is*gm i**th***?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*gm 2 igm ith**Is*gm i**th**?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*Is*gm i*Is*gm i*Is*gm i**th**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A00**00"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A* igm @ 1gm i*gm i**Is*gm is*gm i*/**Is*gm (*Is*gm is*gm i***), igm is*gm i*gm 80% gm igm iIs*gm i*gm i**th***.  i*Is*gm i***'* i*gm is*gm i***, igm i**?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*gm is*gm i*gm igm im*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "Agm is*gm i*gm i*th**Is*gm igm i*th**Is*gm i*gm i*gm i*?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "Agm iIs*gm i*gm iIs*gm th**Is*gm in**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*gm im*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "Agm i**th: i*th**Is*gm i**th**Is*gm igm i**th***. is*gm i**Is*gm iIs*gm igm igm i**Is*gm igm i**th***."})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A**'* iIs*gm igm i**th*! is*gm igm i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "th**Is*gm i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "Agm igm i*Is*gm iIs*gm is*gm i**th**/th**Is*gm i*gm i*"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*gm th**Is*gm igm i**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "As*gm i*gm iIs*gm igm igm i**th**ICA**FBI*!"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A* i*gm is*gm igm i**th******. i*gm i*gm igm i**th*."})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "AIs*gm ith**Is*gm + i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "Ath**Is*gm is*gm igm i*gm i*Is*gm iIs*gm igm i**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A**Is*gm i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "Agm i**th*!"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A is*gm i*Is*gm is*gm (*'* i*Is*gm th**Is*gm is*gm i**)"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "As*gm ith**Is*gm i*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*->th**Is*gm i**Is*gm iIs*gm is*gm igm igm i*gm th**Is*gm ith**Is*gm i*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A**Is*gm igm i*gm i1 i*gm i*gm igm i*gm i*gm ip**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*Is*gm i*gm i*gm in**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A***p**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*gm i*Is*gm i**thm*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A/* i**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*Is*gm igm i**th**?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "AIs*gm i*"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*gm i*gm i***?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A* gm i*gm i*gm i**th****?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*gm igm is*gm igm igm 5gm i**th***? gm i*gm i**Is*gm i***? i*gm i*gm i**Is*gm is*gm is*gm i*?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "As*gm igm i*gm igm igm i**?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*th**Is*gm igm i**th!"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "Agm igm i*Is*gm & ith**Is*gm is*gm i*gm i**th**m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*gm iIs*gm iIs*gm i*gm i*gm i*gm i*gm im*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "A*Is*gm iIs*gm is*gm im*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "A*gm is*gm is*gm igm ith**Is*gm i**th**Is*gm & ith**Is*gm i*Is*gm iIs*gm i**th, is*gm i***!"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "happy", body:    "Agm i*Is*gm iIs*gm i*gm is*gm iIs*gm i*gm i**Is*gm in**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A igm i*Is*gm / i*gm igm is*gm i*gm igm igm i/* i*Is*gm i*m*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "A* is*gm i*gm i**Is*gm th**Is*gm igm i**th/CatsInHat?"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "confused", body: "Agm i*gm i*gm i**th****/*gm i**Is*gm iIs*gm i***/th**Is*gm i**th!"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "Ath**Is*gm igm iIs*gm i**Is*gm i**th**'* i*th**Is*gm i*gm igm im*n**"})
    Repo.insert!(%Idea{retro_id: retro.id, user_id: 1, category: "sad", body:      "AIs*gm igm i*gm i*gm is*gm igm i**m*n**"})

    :timer.sleep(500)
    IO.puts("\n#{IO.ANSI.green()}A long retro has been created!\n  - visit http://localhost:4000/retros/#{retro.id}#{IO.ANSI.reset()}\n")
  end
end

error: pathspec 'lib/tasks/seed_longer_retro.ex' did not match any file(s) known to git


Support domains in port check endpoint

Support domains in port check endpoint

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/evercam/evercam-media.git/'


Added task to import jpegs to cloud from an sd card. (#993)

* Added task to import jpegs to cloud from an sd card.

* Make days in seconds a global value.


Add elixir day 3 easy

Add elixir day 3 easy

# Add a timeout to the pitcher or catcher. What happens when you time out?

ball_glove  = fn -> receive do
  {:pitch, pitcher} ->
    send pitcher, {:catch, self()}
  after
    1_000 -> IO.puts "nothing after 1s in catcher"
  end
end

catcher = spawn ball_glove

:timer.sleep(2000)
send catcher, {:pitch, self()}
receive do
  {:catch, _pid} ->
    IO.puts "Caught it!"
  after
    1_000 -> IO.puts "nothing after 1s in pitcher"
end

error: pathspec 'elixir/day3/day3.exs' did not match any file(s) known to git


remove unnecessary comment

remove unnecessary comment

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/mononym/exmud.git/'


Increment version [ci skip]

Increment version [ci skip]

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/edenlabllc/ehealth.api.git/'


Increment version [ci skip]

Increment version [ci skip]


Minor refactoring

Minor refactoring

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/gtcode/phoenix-trello.git/'


add elixir config

add elixir config

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/longthanhtran/dotfiles.git/'


Use cache to fetch the camera in archive endpoints


Updated mix.exs

Updated mix.exs

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/riverrun/openmaize-phoenix.git/'


fix dispense quantity multiplicity

fix dispense quantity multiplicity


100% Coverage on Core.Tag and Core.TagController

defmodule Core.TagControllerTest do
  @moduledoc """
  Test for Core.TagController
  """
  use Core.ConnCase

  setup do
    user = insert_user(%{}, true)
    {:ok, jwt, _} = Guardian.encode_and_sign(user)

    conn = build_conn()
    |> put_req_header("accept", "application/json")
    |> put_req_header("authorization", "Bearer #{jwt}")

    {:ok, %{conn: conn}}
  end

  test "List of Tags", %{conn: conn}  do
    conn = conn
    |> get(tag_path(conn, :index))

    assert json_response(conn, :ok)
  end

  test "Create a tag", %{conn: conn} do
    conn1 = conn
    |> post(tag_path(conn, :create), %{"title" => "x"})

    conn2 = conn
    |> post(tag_path(conn, :create), %{"title" => ""})

    assert json_response(conn1, :created)
    assert json_response(conn2, :unprocessable_entity)
  end

  test "Show a tag", %{conn: conn} do
    tag = insert_tag()

    conn = conn
    |> get(tag_path(conn, :show, tag.id))

    assert json_response(conn, :ok)
  end

  test "Update a tag", %{conn: conn} do
    tag = insert_tag()

    conn1 = conn
    |> put(tag_path(conn, :update, tag.id), %{"title" => "b"})

    conn2 = conn
    |> put(tag_path(conn, :update, tag.id), %{"title" => ""})

    assert json_response(conn1, :ok)
    assert json_response(conn2, :unprocessable_entity)
  end

  test "Delete a tag", %{conn: conn} do
    tag = insert_tag()

    conn = conn
    |> delete(tag_path(conn, :delete, tag.id))

    assert response(conn, :no_content)
  end

  test "Resource not found", %{conn: conn} do
    conn1 = get(conn, tag_path(conn, :show, 0))
    conn2 = get(conn, tag_path(conn, :update, 0, %{}))
    conn3 = get(conn, tag_path(conn, :delete, 0))

    assert json_response(conn1, :not_found)
    assert json_response(conn2, :not_found)
    assert json_response(conn3, :not_found)
  end
end

error: pathspec 'test/controllers/tag_controller_test.exs' did not match any file(s) known to git