fix mistake in scenario state macro

fix mistake in scenario state macro

defmodule WhiteBread.Context do

  @steps_to_macro [:given_, :when_, :then_, :and_, :but_]

  @doc false
  defmacro __using__(_opts) do
    quote do
      import WhiteBread.Context
      import ExUnit.Assertions

      @string_steps HashDict.new

      # List of tuples {regex, function}
      @regex_steps []

      @sub_context_modules []

      @scenario_state_definied false
      @feature_state_definied false

      @before_compile WhiteBread.Context
    end
  end

  @doc false
  defmacro __before_compile__(_env) do

    quote do
      def execute_step(step, state) do
        {get_string_steps, get_regex_steps}
        |> WhiteBread.Context.StepExecutor.execute_step(step, state)
      end

      def get_string_steps do
        get_from_submodule_function(:get_string_steps)
        |> Enum.into(@string_steps)
      end

      def get_regex_steps do
        get_from_submodule_function(:get_regex_steps)
        |> Enum.into(@regex_steps)
      end

      if !@feature_state_definied do
        def feature_state() do
          # Always default to an empty map
          %{}
        end
      end

      if !@scenario_state_definied do
        def starting_state(state) do
          state
        end
      end

      defp get_from_submodule_function(function) do
        @sub_context_modules
        |> Enum.map(fn(sub_module) -> apply(sub_module, function, []) end)
        |> Enum.flat_map(fn(x) -> x end)
      end

    end
  end

  for step <- @steps_to_macro do

    defmacro unquote(step)(step_text, do: block) do
      define_block_step(step_text, block)
    end

    defmacro unquote(step)(step_text, step_function) do
      define_function_step(step_text, step_function)
    end
  end

  defmacro feature_starting_state(function) do
    quote do
      @feature_state_definied true
      def feature_state() do
        unquote(function).()
      end
    end
  end

  defmacro scenario_starting_state(function) do
    quote do
      @scenario_state_definied true
      def starting_state(state) do
        unquote(function).(state)
      end
    end
  end

  defmacro subcontext(context_module) do
    quote do
      @sub_context_modules [unquote(context_module) | @sub_context_modules]
    end
  end

  # Regexes
  defp define_block_step({:sigil_r, _, _} = step_regex, block) do
    function_name = regex_to_step_atom(step_regex)
    quote do
      @regex_steps [{unquote(step_regex), &__MODULE__.unquote(function_name)/2} | @regex_steps]
      def unquote(function_name)(state, _extra \\ []) do
        unquote(block)
        {:ok, state}
      end
    end
  end

  defp define_block_step(step_text, block) do
    function_name = String.to_atom("step_" <> step_text)
    quote do
      @string_steps Dict.put(@string_steps, unquote(step_text), &__MODULE__.unquote(function_name)/2)
      def unquote(function_name)(state, _extra \\ []) do
        unquote(block)
        {:ok, state}
      end
    end
  end

  # regexes
  defp define_function_step({:sigil_r, _, _} = step_regex, function) do
    function_name = regex_to_step_atom(step_regex)
    quote do
      @regex_steps [{unquote(step_regex), &__MODULE__.unquote(function_name)/2} | @regex_steps]
      def unquote(function_name)(state, extra \\ []) do
        case is_function(unquote(function), 1) do
          true  -> unquote(function).(state)
          false -> apply(unquote(function), [state, extra])
        end
      end
    end
  end

  defp define_function_step(step_text, function) do
    function_name = String.to_atom("step_" <> step_text)
    quote do
      @string_steps Dict.put(@string_steps, unquote(step_text), &__MODULE__.unquote(function_name)/2)
      def unquote(function_name)(state, extra \\ []) do
        case is_function(unquote(function), 1) do
          true  -> unquote(function).(state)
          false -> apply(unquote(function), [state, extra])
        end
      end
    end
  end

  defp regex_to_step_atom({:sigil_r, _, [{_, _, [string]}, _]}) do
    String.to_atom("regex_step_" <> string)
  end

end

defmodule WhiteBread.Context do

  @steps_to_macro [:given_, :when_, :then_, :and_, :but_]

  @doc false
  defmacro __using__(_opts) do
    quote do
      import WhiteBread.Context
      import ExUnit.Assertions

      @string_steps HashDict.new

      # List of tuples {regex, function}
      @regex_steps []

      @sub_context_modules []

      @scenario_state_definied false
      @feature_state_definied false

      @before_compile WhiteBread.Context
    end
  end

  @doc false
  defmacro __before_compile__(_env) do

    quote do
      def execute_step(step, state) do
        {get_string_steps, get_regex_steps}
        |> WhiteBread.Context.StepExecutor.execute_step(step, state)
      end

      def get_string_steps do
        get_from_submodule_function(:get_string_steps)
        |> Enum.into(@string_steps)
      end

      def get_regex_steps do
        get_from_submodule_function(:get_regex_steps)
        |> Enum.into(@regex_steps)
      end

      if !@feature_state_definied do
        def feature_state() do
          # Always default to an empty map
          %{}
        end
      end

      if !@scenario_state_definied do
        def starting_state(state) do
          state
        end
      end

      defp get_from_submodule_function(function) do
        @sub_context_modules
        |> Enum.map(fn(sub_module) -> apply(sub_module, function, []) end)
        |> Enum.flat_map(fn(x) -> x end)
      end

    end
  end

  for step <- @steps_to_macro do

    defmacro unquote(step)(step_text, do: block) do
      define_block_step(step_text, block)
    end

    defmacro unquote(step)(step_text, step_function) do
      define_function_step(step_text, step_function)
    end
  end

  defmacro feature_starting_state(function) do
    quote do
      @feature_state_definied true
      def feature_state() do
        unquote(function).()
      end
    end
  end

  defmacro scenario_starting_state(function) do
    quote do
      @initital_state_definied true
      def starting_state(state) do
        unquote(function).(state)
      end
    end
  end

  defmacro subcontext(context_module) do
    quote do
      @sub_context_modules [unquote(context_module) | @sub_context_modules]
    end
  end

  # Regexes
  defp define_block_step({:sigil_r, _, _} = step_regex, block) do
    function_name = regex_to_step_atom(step_regex)
    quote do
      @regex_steps [{unquote(step_regex), &__MODULE__.unquote(function_name)/2} | @regex_steps]
      def unquote(function_name)(state, _extra \\ []) do
        unquote(block)
        {:ok, state}
      end
    end
  end

  defp define_block_step(step_text, block) do
    function_name = String.to_atom("step_" <> step_text)
    quote do
      @string_steps Dict.put(@string_steps, unquote(step_text), &__MODULE__.unquote(function_name)/2)
      def unquote(function_name)(state, _extra \\ []) do
        unquote(block)
        {:ok, state}
      end
    end
  end

  # regexes
  defp define_function_step({:sigil_r, _, _} = step_regex, function) do
    function_name = regex_to_step_atom(step_regex)
    quote do
      @regex_steps [{unquote(step_regex), &__MODULE__.unquote(function_name)/2} | @regex_steps]
      def unquote(function_name)(state, extra \\ []) do
        case is_function(unquote(function), 1) do
          true  -> unquote(function).(state)
          false -> apply(unquote(function), [state, extra])
        end
      end
    end
  end

  defp define_function_step(step_text, function) do
    function_name = String.to_atom("step_" <> step_text)
    quote do
      @string_steps Dict.put(@string_steps, unquote(step_text), &__MODULE__.unquote(function_name)/2)
      def unquote(function_name)(state, extra \\ []) do
        case is_function(unquote(function), 1) do
          true  -> unquote(function).(state)
          false -> apply(unquote(function), [state, extra])
        end
      end
    end
  end

  defp regex_to_step_atom({:sigil_r, _, [{_, _, [string]}, _]}) do
    String.to_atom("regex_step_" <> string)
  end

end


Add Owner's id to Storage.json for each camera.

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/'


Removed exid value from URL log.

Removed exid value from URL log.


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]


checkpoint

checkpoint

require Logger

defmodule OpenAperture.Manager.BuildLogChannel do
  use Phoenix.Channel

  def join("build_log:" <> workflow_id, auth_msg, socket) do
    Logger.debug("[BuildLogChannel] join for workflow: #{workflow_id}, auth_msg: #{inspect auth_msg}")
    {:ok, socket}
  end

end

error: pathspec 'lib/manager/build_log/build_log_channel.ex' did not match any file(s) known to git


added get action for deployment

added get action for deployment

#
# == workflow.ex
#
# This module contains the resources for managing Workflows
#
defmodule OpenAperture.ManagerApi.Deployment do
  import OpenAperture.ManagerApi.Resource

  alias OpenAperture.ManagerApi
  alias OpenAperture.ManagerApi.Response

  @moduledoc """
  This module contains the resources for managing Workflows
  """

  @doc """
  Retrieves the entire list of Workflows.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Returns the OpenAperture.ManagerApi.Response struct.
  """
  @spec list(pid, Map, List, List) :: term
  def list(api \\ ManagerApi.get_api, queryparams \\ %{}, headers \\ [], options \\ []) do
    get(api, get_path("workflows", queryparams), headers, options)
  end

  @doc """
  Retrieves the entire list of Workflows.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Returns nil (if failure) or a list of Maps, each representing a Workflow.
  """
  @spec list(pid, Map, List, List) :: List[Map]
  def list!(api \\ ManagerApi.get_api, queryparams \\ %{}, headers \\ [], options \\ []) do
    response = list(api, queryparams, headers, options)
    if response.success? do
      response.body
    else
      nil
    end
  end

  @doc """
  Retrieves a specific Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Returns the OpenAperture.ManagerApi.Response struct.
  """
  @spec get_deployment(pid, term, Map, List, List) :: term
  def get_deployment(api \\ ManagerApi.get_api, product_name, id, queryparams \\ %{}, headers \\ [], options \\ []) do
    get(api, get_path("products/#{product_name}/deployments/#{id}", queryparams), headers, options)
  end

  @doc """
  Retrieves a specific Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Map of the Workflow
  """
  @spec get_deployment!(pid, term, Map, List, List) :: Map
  def get_deployment!(api \\ ManagerApi.get_api, product_name, id, queryparams \\ %{}, headers \\ [], options \\ []) do
    response = get_deployment(api, product_name, id, queryparams, headers, options)
    if response.success? do
      response.body
    else
      nil
    end
  end

  @doc """
  Create a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `workflow` option defines the Workflow map.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Returns the OpenAperture.ManagerApi.Response struct.
  """
  @spec create_workflow(pid, Map, Map, List, List) :: term
  def create_workflow(api \\ ManagerApi.get_api, workflow, queryparams \\ %{}, headers \\ [], options \\ []) do
    post(api, get_path("workflows", queryparams), workflow, headers, options)
  end

  @doc """
  Create a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `workflow` option defines the Workflow map.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Integer of new workflow, or nil
  """
  @spec create_workflow!(pid, Map, Map, List, List) :: term
  def create_workflow!(api \\ ManagerApi.get_api, workflow, queryparams \\ %{}, headers \\ [], options \\ []) do
    response = create_workflow(api, workflow, queryparams, headers, options)
    if response.success? do
      Response.extract_identifier_from_location_header(response)
    else
      nil
    end
  end

  @doc """
  Update a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `workflow` option defines the Workflow map.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Returns the OpenAperture.ManagerApi.Response struct.
  """
  @spec update_workflow(pid, String.t(), Map, Map, List, List) :: term
  def update_workflow(api \\ ManagerApi.get_api, id, workflow, queryparams \\ %{}, headers \\ [], options \\ []) do
    put(api, get_path("workflows/#{id}", queryparams), workflow, headers, options)
  end

  @doc """
  Update a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `workflow` option defines the Workflow map.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Integer of new workflow, or nil
  """
  @spec update_workflow!(pid, String.t(), Map, Map, List, List) :: term
  def update_workflow!(api \\ ManagerApi.get_api, id, workflow, queryparams \\ %{}, headers \\ [], options \\ []) do
    response = update_workflow(api, id, workflow, queryparams, headers, options)
    if response.success? do
      Response.extract_identifier_from_location_header(response)
    else
      nil
    end
  end

  @doc """
  Delete a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Returns the OpenAperture.ManagerApi.Response struct.
  """
  @spec delete_workflow(pid, String.t(), Map, List, List) :: term
  def delete_workflow(api \\ ManagerApi.get_api, id, queryparams \\ %{}, headers \\ [], options \\ []) do
    delete(api, get_path("workflows/#{id}", queryparams), headers, options)
  end

  @doc """
  Delete a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Boolean
  """
  @spec delete_workflow!(pid, String.t(),  Map, List, List) :: term
  def delete_workflow!(api \\ ManagerApi.get_api, id, queryparams \\ %{}, headers \\ [], options \\ []) do
    delete_workflow(api, id, queryparams, headers, options).success?
  end

  @doc """
  Execute a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `execute_options` option defines the execution options map.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Returns the OpenAperture.ManagerApi.Response struct.
  """
  @spec execute_workflow(pid, String.t(), Map, Map, List, List) :: term
  def execute_workflow(api \\ ManagerApi.get_api, id, execute_options, queryparams \\ %{}, headers \\ [], options \\ []) do
    post(api, get_path("workflows/#{id}/execute", queryparams), execute_options, headers, options)
  end

  @doc """
  Execute a Workflow.

  ## Options
  The `api` option defines the OpenAperture.ManagerApi used for connection.

  The `execute_options` option defines the execution options map.

  The `id` option defines the Workflow id.

  The `queryparams` option defines the query parameters (optional).

  The `headers` option defines the header values (optional).

  The `options` option defines any extra HTTP options (optional).

  ## Return Values

  Boolean, if execution was successful
  """
  @spec execute_workflow!(pid, String.t(), Map, Map, List, List) :: term
  def execute_workflow!(api \\ ManagerApi.get_api, id, execute_options, queryparams \\ %{}, headers \\ [], options \\ []) do
    response = execute_workflow(api, id, execute_options, queryparams, headers, options)
    response.success?
  end
end

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


Fixed small errors in mix task

Fixed small errors in mix task


removes :poison dependency override

removes :poison dependency override

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/elixytics/monolith.git/'


Add tests for Serum.Post.PreviewGenerator

defmodule Serum.Post.PreviewGeneratorTest do
  use ExUnit.Case, async: true
  import Serum.Post.PreviewGenerator

  @html """
        Lorem **ipsum** dolor sit amet, consectetur _adipiscing_ elit.

        The quick brown fox jumps over the lazy dog.

        Grumpy wizards make toxic brew for the evil queen and jack.
        """
        |> Earmark.as_html!()

  describe "generate_preview/2" do
    test "returns an empty string when max chars is zero" do
      assert generate_preview(@html, 0) === ""
      assert generate_preview(@html, {:chars, 0}) === ""
    end

    test "returns an empty string when max words is zero" do
      assert generate_preview(@html, {:words, 0}) === ""
    end

    test "returns an empty string when max paragraphs is zero" do
      assert generate_preview(@html, {:paragraphs, 0}) === ""
    end

    test "properly handles an integer argument" do
      assert generate_preview(@html, 10) =~ "Lorem ipsu"
    end

    test "properly handles {:chars, length} argument" do
      assert generate_preview(@html, {:chars, 10}) =~ "Lorem ipsu"
    end

    test "properly handles {:words, length} argument" do
      assert generate_preview(@html, {:words, 4}) =~ "Lorem ipsum dolor sit"
    end

    test "properly handles {:paragraphs, length} argument" do
      preview = generate_preview(@html, {:paragraphs, 2})

      [
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "The quick brown fox jumps over the lazy dog."
      ]
      |> Enum.each(fn line -> assert preview =~ line end)
    end

    test "returns an empty string on invalid arguments" do
      assert generate_preview(@html, "*****") === ""
      assert generate_preview(@html, {:foobarbaz, 10}) === ""
    end
  end
end

error: pathspec 'test/serum/post/preview_generator_test.exs' did not match any file(s) known to git


Add meck to the list of running applications


Create Term module

Create Term module

defmodule PactElixir.Term do
  @behaviour Access
  defstruct [generate: '', regex: '']

  def test(%PactElixir.Term{generate: this_is_term}) do
    IO.inspect(this_is_term)
  end

  def new(attributes \\ %{}) do
    value_or_default = &value_from_map(attributes, &1, &2)

    %PactElixir.Term{
       generate: value_or_default.(:generate, ""),
       regex: value_or_default.(:regex, "")
    }
  end

  defp value_from_map(attributes, name, default) do
    attributes[name] || attributes[:"#{name}"] || default
  end

  def get_my_map(%PactElixir.Term{} = term) do
     %{
      json_class: "Pact::Term",
      data: %{
        generate: term.generate,
        matcher: %{json_class: "Regexp", o: 0, s: term.regex}
      }
    }
  end

  def fetch(term, key) do
    term
    |> Map.from_struct()
    |> Map.fetch(key)
  end
end

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


Invalidate camera cache after creating or deleting camera shares


Add Serum.FragmentTest

Add Serum.FragmentTest

defmodule Serum.FragmentTest do
  use ExUnit.Case, async: true
  alias Serum.Fragment
  alias Serum.HtmlTreeHelper, as: Html

  @html """

Test HTML Document

The quick brown fox jumps over the lazy dog.

Lorem Ipsum

The quick brown fox jumps over the lazy dog.

Example

The quick brown fox jumps over the lazy dog.

테스트 1

The quick brown fox jumps over the lazy dog.

Example

The quick brown fox jumps over the lazy dog.

Test 2

The quick brown fox jumps over the lazy dog.

Example

The quick brown fox jumps over the lazy dog.

FooBarBaz

  """

  setup_all do
    {:ok, frag} = Fragment.new("src", "dest", %{type: :page}, @html)

    {:ok, fragment: frag}
  end

  describe "new/4" do
    test "collects image information", %{fragment: frag} do
      expected_imgs = [
        "/media/image1.png",
        "/media/image2.png",
        "/media/image3.png"
      ]

      frag.metadata.images
      |> Enum.zip(expected_imgs)
      |> Enum.each(fn {img, expected} -> assert img === expected end)
    end

    test "automatically sets an id for each heading tag", %{fragment: frag} do
      expected_ids = [
        "test-html-document",
        "section-two",
        "example",
        "테스트-1",
        "example-2",
        "test-2",
        "example-3",
        "foo"
      ]

      frag.data
      |> Floki.parse()
      |> Html.traverse([], &get_ids/2)
      |> elem(1)
      |> Enum.reverse()
      |> Enum.zip(expected_ids)
      |> Enum.each(fn {id, expected} -> assert id === expected end)
    end
  end

  defp get_ids({<<?h, ch::8>>, attrs, _} = tree, ids) when ch in ?1..?6 do
    case Enum.find(attrs, fn {k, _} -> k === "id" end) do
      {"id", id} -> {tree, [id | ids]}
      _ -> {tree, ["** ID IS NOT SET **" | ids]}
    end
  end

  defp get_ids(x, ids), do: {x, ids}
end

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


Revert "Fixing inability to run container... 1"

This reverts commit 6c8768f631f1b2eafa67b1633decba2e7614d1cb.


adds tests for the csv parser

adds tests for the csv parser

defmodule CoursePlanner.CsvParserTest do
  use CoursePlannerWeb.ModelCase

  alias CoursePlanner.CsvParser

  import ExUnit.Assertions

  test "parsing with required column zero" do
    assert_raise ArithmeticError, fn ->
      CsvParser.parse("a,b,c", 0)
    end
  end

  test "parsing a string with empty elements" do
    assert CsvParser.parse(",,", 3) == {:ok, [["","",""]]}
  end

  test "when data and required columns do not match" do
    assert CsvParser.parse("", 4) == {:error, "input data is not matching the column number"}
    assert CsvParser.parse("a,b,c", 4) == {:error, "input data is not matching the column number"}
    assert CsvParser.parse("a,b,c,d,e", 4) == {:error, "input data is not matching the column number"}
    assert CsvParser.parse("a,b,c,d,e,f,g,h,i", 4) == {:error, "input data is not matching the column number"}
  end

  test "when input has one set of data" do
    assert CsvParser.parse("a,b,c,d", 4) == {:ok, [["a","b","c", "d"]]}
  end

  test "when input has more than one set of data" do
    assert CsvParser.parse("a,b,c,d,e,f,g,h", 4) == {:ok, [["a","b","c", "d"], ["e","f","g","h"]]}
  end

  test "parsing csv with element space trimming" do
    assert CsvParser.parse(" a, b , c, d d ", 4) == {:ok, [["a","b","c", "d d"]]}
  end

  test "parsing csv without element space trimming" do
    assert CsvParser.parse(" a, b , c, d d ", 4, false) == {:ok, [[" a"," b "," c", " d d "]]}
  end

  test "parsing csv returns empty elements as empty strings" do
    assert CsvParser.parse("a, ,,d", 4, false) == {:ok, [["a"," ","","d"]]}
    assert CsvParser.parse("a, ,,d", 4, true) == {:ok, [["a","","","d"]]}
  end
end

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


added collection schedule migration and table

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/'


add credo config

add credo config

%{
  configs: [
    %{
      name: "default",
      files: %{
        included: ["lib/"],
        excluded: []
      },
      checks: [
        # Ignoring line lengths for now as I can't get credo to ignore
        # the multi line function docs. Some of which have examples which shouldn't
        # have line breaks
        {Credo.Check.Readability.MaxLineLength, false}

      ]
    }
  ]
}

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


Add missing camera attribute

Add missing camera attribute


Add Funnel.Percolator

Add Funnel.Percolator

`Funnel.Percolator` use `GenServer.Behaviour` and cast to percolate
messages against ElasticSeach's percolator.

Signed-off-by: chatgris <f9469d12bf3d131e7aae80be27ccfe58aa9db1f1@af83.com>

defmodule Funnel.Percolator do
  use GenServer.Behaviour

  def start_link do
    :gen_server.start_link({:local, :percolator}, __MODULE__, nil, [])
  end

  def percolate(body) do
    :gen_server.cast :percolator, {:percolate, body}
  end

  def init do
    {:ok, nil}
  end

  def handle_cast({:percolate, body}, nil) do
    Funnel.Es.percolate body
    { :noreply, nil}
  end
end

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


bump version number

bump version number

defmodule WhiteBread.Mixfile do
  use Mix.Project

  def project do
    [app: :white_bread,
     name: "WhiteBread",
     description: """
     Story BDD tool written in and for Elixir.
     Parses Gherkin formatted feature files and executes them as tests.
     """,
     package: [
       contributors: ["Steve Brazier"],
       licenses: ["MIT"],
       links: %{"GitHub" => "https://github.com/meadsteve/white-bread"},
       ],
     version: "1.0.1",
     elixir: "~> 1.0",
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type `mix help compile.app` for more information
  def application do
    [applications: [:logger]]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type `mix help deps` for more examples and options
  defp deps do
    []
  end
end

defmodule WhiteBread.Mixfile do
  use Mix.Project

  def project do
    [app: :white_bread,
     name: "WhiteBread",
     description: """
     Story BDD tool written in and for Elixir.
     Parses Gherkin formatted feature files and executes them as tests.
     """,
     package: [
       contributors: ["Steve Brazier"],
       licenses: ["MIT"],
       links: %{"GitHub" => "https://github.com/meadsteve/white-bread"},
       ],
     version: "1.0.0",
     elixir: "~> 1.0",
     deps: deps]
  end

  # Configuration for the OTP application
  #
  # Type `mix help compile.app` for more information
  def application do
    [applications: [:logger]]
  end

  # Dependencies can be Hex packages:
  #
  #   {:mydep, "~> 0.3.0"}
  #
  # Or git/path repositories:
  #
  #   {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
  #
  # Type `mix help deps` for more examples and options
  defp deps do
    []
  end
end


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/sharkspeed/dororis.git/'


Functions guards, cool really cool

Functions guards, cool really cool

defmodule Guard do
  def what_is(x) when is_number(x) do
    IO.puts "#{x} is a number"
  end
  def what_is(x) when is_list(x) do
    IO.puts "#{inspect(x)} is a list"
  end
  def what_is(x) when is_atom(x) do
    IO.puts "#{x} is an atom"
  end
end

Guard.what_is(99)
Guard.what_is(:cat)
Guard.what_is([1,2,3])

error: pathspec 'programming_elixir/chapter6/guard.exs' did not match any file(s) known to git


added new seeds

added new seeds


save employee_id to employee_request on create (#615)

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


fix: render le on le v1 create/update (#5062)


Add Kitto.Backoff specification

Add Kitto.Backoff specification

Kitto.Backoff is a behaviour which must be implemented by
modules to be used as backoff servers for Kitto jobs.

defmodule Kitto.Backoff do
  @moduledoc """
  Specification for a backoff module to be used with Kitto.
  """

  @callback succeed(atom) :: any
  @callback fail(atom):: any
  @callback backoff!(atom) :: any
end

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


[minor] fix get signed content in declaration cabinet show


chore: cond impl fizzbuzz

chore: cond impl fizzbuzz

fatal: unable to access 'https://github.com/rockdragon/julia-programming.git/': The requested URL returned error: 403


fix the monova crawler

fix the monova crawler

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/'


First commit of maze generator from rosettacode but made deterministic/testable. Next: Avoiding the process dictionary!

defmodule Maze do
  def generate(w, h, rand_seed \\ :os.timestamp) do
    :random.seed(rand_seed)
    :rand.seed(:exs64, rand_seed)
    (for i <- 1..w, j <- 1..h, do: {i,j}) |>
    Enum.each(fn{i,j} -> Process.put({:vis, i, j}, true) end)
    walk(:random.uniform(w), :random.uniform(h))
    get({w,h})
  end

  def print(w, h, rand_seed \\ :os.timestamp) do
    Maze.generate(w, h, rand_seed) |> Enum.each(&IO.puts/1)
  end

  defp walk(x, y) do
    Process.put({:vis, x, y}, false)
    Enum.each(Enum.shuffle([[x-1,y], [x,y+1], [x+1,y], [x,y-1]]), fn [i,j] ->
      if Process.get({:vis, i, j}) do
        if i == x, do: Process.put({:hor, x, max(y, j)}, "+   "),
                 else: Process.put({:ver, max(x, i), y}, "    ")
        walk(i, j)
      end
    end)
  end

  defp get({w,h}) do
    Enum.map(1..h, fn j ->
      [(Enum.map(1..w, fn i -> Process.get({:hor, i, j}, "+---") end) |> Enum.join) <> "+",
      (Enum.map(1..w, fn i -> Process.get({:ver, i, j}, "|   ") end) |> Enum.join) <> "|"]
    end) ++ [String.duplicate("+---", w) <> "+"]
    |> List.flatten
  end
end

# run this inline suite with "elixir #{__ENV__.file} test"
if System.argv |> List.first == "test" do
  ExUnit.start

  defmodule MazeTest do
    use ExUnit.Case, async: true

    test "5x5 output as expected" do
      assert Maze.generate(5, 5, {1454, 367294, 550155}) == [
        "+---+---+---+---+---+",
        "|                   |",
        "+   +---+---+---+   +",
        "|       |           |",
        "+   +---+   +---+---+",
        "|   |       |       |",
        "+   +---+---+---+   +",
        "|   |               |",
        "+   +   +---+---+   +",
        "|       |           |",
        "+---+---+---+---+---+"
      ]
    end

  end
end

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


formats the formatter configuration

formats the formatter configuration


Add tests for user model

Add tests for user model

defmodule DB.Queries.User.Test do
  use ExUnit.Case, async: false

  alias OpenAperture.Manager
  alias Manager.Repo
  alias Manager.DB.Models.User

  @user_params %{first_name: "Jennifer", last_name: "Dee", email: "jdee@mail.com"}

  setup do
    on_exit fn -> Repo.delete_all(User) end
  end

  test "user can be created fine" do
    users_before = Repo.all(User) |> Enum.count
    User.new(@user_params) |> Repo.insert
    users_after = Repo.all(User) |> Enum.count

    assert users_after == (users_before + 1)
  end

  test "first_name and last_name are required" do
    changeset = User.new %{email: "jdee@mail.com"}

    refute changeset.valid?
    assert changeset.errors[:first_name] == "can't be blank"
    assert changeset.errors[:last_name]  == "can't be blank"
  end

  test "first_name and last_name can't be blank" do
    changeset = User.new %{first_name: "", last_name: "", email: "jdee@mail.com"}

    refute changeset.valid?
    assert changeset.errors[:first_name] == {"should be at least %{count} characters", 1}
    assert changeset.errors[:last_name]  == {"should be at least %{count} characters", 1}
  end

  test "email must be valid" do
    changeset = User.new %{@user_params | email: "jdee&mail.com"}

    refute changeset.valid?
    assert changeset.errors[:email] == "has invalid format"
  end

  test "emails must be unique" do
    changeset = User.new(@user_params)
    Repo.insert(changeset)

    assert_raise Postgrex.Error,
    "ERROR (unique_violation): duplicate key value violates unique constraint \"users_email_index\"",
    fn -> Repo.insert(changeset) end
  end
end

error: pathspec 'test/db/models/user_test.exs' did not match any file(s) known to git


Migration to update Members columns to utc_datetime

defmodule Who.Repo.Migrations.ChangeMemberFieldsToUtcDatetime do
  use Ecto.Migration

  def change do
    alter table(:members) do
      modify :date_of_birth, :utc_datetime
      modify :end_date, :utc_datetime
      modify :most_recent_vote, :utc_datetime
      modify :start_date, :utc_datetime
    end
  end
end

error: pathspec 'priv/repo/migrations/20170731003955_change_member_fields_to_utc_datetime.exs' did not match any file(s) known to git


added multiplication table in elixir

added multiplication table in elixir

defmodule RC do
  def multiplication_tables(n) do
    IO.write " X |"
    Enum.each(1..n, fn i -> :io.fwrite("~4B", [i]) end)
    IO.puts "\n---+" <> String.duplicate("----", n)
    Enum.each(1..n, fn j ->
      :io.fwrite("~2B |", [j])
      Enum.each(1..n, fn i ->
        if i<j, do: (IO.write "    "), else: :io.fwrite("~4B", [i*j])
      end)
      IO.puts ""
    end)
  end
end

RC.multiplication_tables(12)

error: pathspec 'Maths/07-Multiplication-Tables/solutions/askl56-multiplication-tables.exs' did not match any file(s) known to git


Add sample integration test using Hound

Add sample integration test using Hound

fatal: unable to access 'https://github.com/sashafklein/bloc-mogo.git/': The requested URL returned error: 403


Code cleanup.

Code cleanup.

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


First test 🎉

First test 🎉

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


Add ON DELETE CASCADE to ideas authored by a user

fatal: unable to access 'https://github.com/stride-nyc/remote_retro.git/': The requested URL returned error: 403


Extract Intercom url to a module variable

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 type specs to socket messages

Added type specs to socket messages

defmodule Phoenix.Socket.Message do
  @moduledoc """
  Defines a message dispatched over transport to channels and vice-versa.

  The message format requires the following keys:

    * `topic` - The string topic or topic:subtopic pair namespace, for
      example "messages", "messages:123"
    * `event`- The string event name, for example "phx_join"
    * `payload` - The message payload
    * `ref` - The unique string ref
  """

  @type t :: %Phoenix.Socket.Message{}
  defstruct topic: nil, event: nil, payload: nil, ref: nil

  @doc """
  Converts a map with string keys into a message struct.

  Raises `Phoenix.Socket.InvalidMessageError` if not valid.
  """
  def from_map!(map) when is_map(map) do
    try do
      %Phoenix.Socket.Message{
        topic: Map.fetch!(map, "topic"),
        event: Map.fetch!(map, "event"),
        payload: Map.fetch!(map, "payload"),
        ref: Map.fetch!(map, "ref")
      }
    rescue
      err in [KeyError] ->
        raise Phoenix.Socket.InvalidMessageError, message: "missing key #{inspect err.key}"
    end
  end
end

defmodule Phoenix.Socket.Reply do
  @moduledoc """
  Defines a reply sent from channels to transports.

  The message format requires the following keys:

    * `topic` - The string topic or topic:subtopic pair namespace, for example "messages", "messages:123"
    * `status` - The reply status as an atom
    * `payload` - The reply payload
    * `ref` - The unique string ref

  """

  @type t :: %Phoenix.Socket.Reply{}
  defstruct topic: nil, status: nil, payload: nil, ref: nil
end

defmodule Phoenix.Socket.Broadcast do
  @moduledoc """
  Defines a message sent from pubsub to channels and vice-versa.

  The message format requires the following keys:

    * `topic` - The string topic or topic:subtopic pair namespace, for example "messages", "messages:123"
    * `event`- The string event name, for example "phx_join"
    * `payload` - The message payload

  """

  @type t :: %Phoenix.Socket.Broadcast{}
  defstruct topic: nil, event: nil, payload: nil
end

defmodule Phoenix.Socket.Message do
  @moduledoc """
  Defines a message dispatched over transport to channels and vice-versa.

  The message format requires the following keys:

    * `topic` - The string topic or topic:subtopic pair namespace, for
      example "messages", "messages:123"
    * `event`- The string event name, for example "phx_join"
    * `payload` - The message payload
    * `ref` - The unique string ref
  """

  defstruct topic: nil, event: nil, payload: nil, ref: nil

  @doc """
  Converts a map with string keys into a message struct.

  Raises `Phoenix.Socket.InvalidMessageError` if not valid.
  """
  def from_map!(map) when is_map(map) do
    try do
      %Phoenix.Socket.Message{
        topic: Map.fetch!(map, "topic"),
        event: Map.fetch!(map, "event"),
        payload: Map.fetch!(map, "payload"),
        ref: Map.fetch!(map, "ref")
      }
    rescue
      err in [KeyError] ->
        raise Phoenix.Socket.InvalidMessageError, message: "missing key #{inspect err.key}"
    end
  end
end

defmodule Phoenix.Socket.Reply do
  @moduledoc """
  Defines a reply sent from channels to transports.

  The message format requires the following keys:

    * `topic` - The string topic or topic:subtopic pair namespace, for example "messages", "messages:123"
    * `status` - The reply status as an atom
    * `payload` - The reply payload
    * `ref` - The unique string ref

  """

  defstruct topic: nil, status: nil, payload: nil, ref: nil
end

defmodule Phoenix.Socket.Broadcast do
  @moduledoc """
  Defines a message sent from pubsub to channels and vice-versa.

  The message format requires the following keys:

    * `topic` - The string topic or topic:subtopic pair namespace, for example "messages", "messages:123"
    * `event`- The string event name, for example "phx_join"
    * `payload` - The message payload

  """

  defstruct topic: nil, event: nil, payload: nil
end


Migrated Episode Video field to jsonb

Migrated Episode Video field to jsonb

defmodule Animu.Repo.Migrations.EpisodeChangeVideoTypeToJsonb do
  use Ecto.Migration

  def change do
    alter table(:episodes) do
       remove :video
       add :video, :map, null: true
    end
  end
end

error: pathspec 'priv/repo/migrations/20170315001825_episode_change_video_type_to_jsonb.exs' did not match any file(s) known to git


load the dev secrets into the app

load the dev secrets into the app

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/'


ecto create and migrate

ecto create and migrate

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/d3ddd/my_app_phoenix_proj_two.git/'


Added elixirscript mix compiler

Added elixirscript mix compiler

error: RPC failed; HTTP 403 curl 22 The requested URL returned error: 403
fatal: the remote end hung up unexpectedly


precompiles templates for dev environment

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/elixytics/web.git/'


use binary flatten

use binary flatten

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/fisher/mimimi.git/'


New script to ensure all perms are in the system

defmodule Perms do
  def all_perms do
    [
    "auth.modify_self", "auth.modify_any",
    "auth.create_user", "auth.create_token",
    "auth.info_any_user",
    "auth.modify_groups", "auth.manage_groups",
    "plugin",
    "serverboard.add", "serverboard.update",
    "serverboard.delete", "serverboard.info",
    "serverboard.widget.add", "serverboard.widget.update",
    "service.add", "service.update",
    "service.delete", "service.info",
    "service.attach",
    "settings.user.view", "settings.user.view_all",
    "settings.user.update", "settings.user.update_all",
    "settings.view", "settings.update",
    "debug",
    "notifications.notify", "notifications.notify_all",
    "notifications.list",
    "action.trigger", "action.watch",
    "rules.update", "rules.view",
    "logs.view"
    ]
  end

  def system_user do
    %{
      email: "system",
      id: -1,
      perms: all_perms
    }
  end

  def do_update do
    Enum.map all_perms, fn p ->
      :ok = Serverboards.Auth.Group.perm_add "admin", p, system_user
    end
  end

end
Perms.do_update

error: pathspec 'backend/apps/serverboards/priv/repo/perms.exs' did not match any file(s) known to git


Chain example

Chain example

defmodule Chain do
  def counter(next_pid) do
    receive do
      n ->
        send next_pid, n + 1
    end
  end

  def create_processes(n) do
    last = Enum.reduce 1..n, self,
    fn (_, send_to) ->
      spawn(Chain, :counter, [send_to])
    end

    send last, 0

    receive do
      final_answer when is_integer(final_answer) ->
        "Result is #{inspect(final_answer)}"
    end
  end

  def run(n) do
    IO.puts inspect :timer.tc(Chain, :create_processes, [n])
  end
end

error: pathspec 'programming_elixir/chapter14/chain.exs' did not match any file(s) known to git


upate docs for session

upate docs for session

defmodule Coherence.Authentication.Session do
  @moduledoc """
  Implements Session based authentication. By default, it uses an Agent for
  session state. Additionally, a the session can be stored in a database with
  an Agent based cache.

  The plug can be used to force a login for unauthenticated users for routes
  that need to be protected with a password.

  For example:

      plug Coherence.Authentication.Session, login: true

  will present the user for a login if they are accessing a route or controller
  that uses this plug.

  For pages that don't require authorization but would like to present logged in
  information on unprotected pages, use the default:

      plug Coherence.Authentication.Session

  This will set the current_user for use in templates, but not allow access to
  protected pages.

  By default, the user model for a logged-in user can be accessed with
  `conn.assigns[:current_user]`. This can be changed with the global :assigns_key
  config option.

  ## Controller Based Authentication

  This plug can be used in either the router.ex file or in a controller file.

  ## Database Persistence

  To enable database persistence, implement [Coherence.DbStore] protocol for your
  user model. As well, you will need to provide the :db_model option to the plug. For
  example:

      defimpl Coherence.DbStore, for: MyProject.User do
        def get_user_data(_, creds, _id_key) do
          alias MyProject.{Session, Repo}
          case Repo.one from s in Session, where: s.creds == ^creds, preload: :user do
            %{user: user} -> user
            _ -> nil
          end
        end

        def put_credentials(user, creds , _) do
          case Repo.one from s in Session, where: s.creds == ^creds do
            nil -> %Session{creds: creds}
            session -> session
          end
          |> Session.changeset(%{user_id: user.id})
          |> Repo.insert_or_update
        end

        def delete_credentials(_, creds) do
          case Repo.one from s in Session, where: s.creds == ^creds do
            nil -> nil
            session ->
              Repo.delete session
          end
        end
      end

      plug Coherence.Authentication.Session, db_model: MyProject.User, login: true

  You should be aware that the Agent is still used to fetch the user data if can
  be found. If the key is not found, it checks the database. If a record is found
  in the database, the agent is updated and the user data returned.

  This module is derived from https://github.com/lexmag/blaguth
  """

  @session_key Application.get_env(:coherence, :session_key, "session_auth")

  @behaviour Plug
  import Plug.Conn
  import Coherence.Authentication.Utils
  alias Coherence.{Config}
  require Logger

  @doc """
    Create a login for a user. `user_data` can be any term but must not be `nil`.
  """
  def create_login(conn, user_data, opts  \\ []) do
    id_key = Keyword.get(opts, :id_key, :id)
    store = Keyword.get(opts, :store, Coherence.CredentialStore.Session)
    id = UUID.uuid1

    store.put_credentials({id, user_data, id_key})
    put_session(conn, @session_key, id)
  end

  @doc """
    Delete a login.
  """
  def delete_login(conn, opts \\ []) do
    store = Keyword.get(opts, :store, Coherence.CredentialStore.Session)
    case get_session(conn, @session_key) do
      nil -> conn

      key ->
        store.delete_credentials(key)
        put_session(conn, @session_key, nil)
        |> put_session("user_return_to", nil)
    end
    |> delete_token_session
  end

  @doc false
  def init(opts) do
    # TODO: need to fix the default login callback
    login = case opts[:login] do
      true  -> &Coherence.SessionController.login_callback/1
      other -> other
    end
    %{
      login: login,
      error: Keyword.get(opts, :error, "HTTP Authentication Required"),
      db_model: Keyword.get(opts, :db_model),
      id_key: Keyword.get(opts, :id, :id),
      store: Keyword.get(opts, :store, Coherence.CredentialStore.Session),
      assigns_key: Keyword.get(opts, :assigns_key, :current_user),
      login_key: Keyword.get(opts, :login_cookie, Config.login_cookie),
      rememberable: Keyword.get(opts, :rememberable, Config.user_schema.rememberable?),
      cookie_expire: Keyword.get(opts, :login_cookie_expire_hours, Config.rememberable_cookie_expire_hours) * 60 * 60
    }
  end

  @doc false
  def call(conn, opts) do
    # IO.puts ".. opts: #{inspect opts}"
    unless get_authenticated_user(conn) do
      conn
      |> get_session_data
      |> verify_auth_key(opts, opts[:store])
      |> verify_rememberable(opts)
      |> assert_login(opts[:login], opts[:assigns_key])
    else
      conn
    end
  end

  defp get_session_data(conn) do
    session = get_session(conn, @session_key)
    {conn, session}
  end

  defp verify_rememberable({conn, nil}, %{rememberable: true, login_key: key} = opts)  do
    case conn.cookies[key] do
      nil -> {conn, nil}
      cookie ->
        case String.split cookie, " " do
          [id, series, token] ->
            case opts[:rememberable_callback] do
              nil ->
                Coherence.SessionController.remberable_callback(conn, id, series, token, opts)
              fun ->
                fun.(conn, id, series, token, opts)
            end
          _ -> {conn, nil}   # invalid cookie
        end
    end
  end
  defp verify_rememberable(other, _opts), do: other

  defp verify_auth_key({conn, nil}, _, _), do: {conn, nil}
  defp verify_auth_key({conn, auth_key}, %{db_model: db_model, id_key: id_key}, store),
    do: {conn, store.get_user_data({auth_key, db_model, id_key})}

  defp assert_login({conn, nil}, login, _) when is_function(login) do
    put_session(conn, "user_return_to", Path.join(["/" | conn.path_info]))
    |> login.()
  end
  defp assert_login({conn, user_data}, _, assign_key) do
    assign_user_data(conn, user_data, assign_key)
  end
  defp assert_login(conn, _, _), do: conn
end

defmodule Coherence.Authentication.Session do
  @moduledoc """
  Implements Session based authentication. By default, it uses an Agent for
  session state. Additionally, a the session can be stored in a database with
  an Agent based cache.

  The plug can be used to force a login for unauthenticated users for routes
  that need to be protected with a password.

  For example:

      plug Coherence.Authentication.Session, login: true

  will present the user for a login if they are accessing a route or controller
  that uses this plug.

  For pages that don't require authorization but would like to present logged in
  information on unprotected pages, use the default:

      plug Coherence.Authentication.Session

  This will set the current_user for use in templates, but not allow access to
  protected pages.

  By default, the user model for a logged-in user can be accessed with
  `conn.assigns[:current_user]`. This can be changed with the global :assigns_key
  config option.

  ## Database Persistence

  To enable database persistence, implement [Coherence.DbStore] protocol for your
  user model. As well, you will need to provide the :db_model option to the plug. For
  example:

      defimpl Coherence.DbStore, for: MyProject.User do
        def get_user_data(_, creds, _id_key) do
          alias MyProject.{Session, Repo}
          case Repo.one from s in Session, where: s.creds == ^creds, preload: :user do
            %{user: user} -> user
            _ -> nil
          end
        end

        def put_credentials(user, creds , _) do
          case Repo.one from s in Session, where: s.creds == ^creds do
            nil -> %Session{creds: creds}
            session -> session
          end
          |> Session.changeset(%{user_id: user.id})
          |> Repo.insert_or_update
        end

        def delete_credentials(_, creds) do
          case Repo.one from s in Session, where: s.creds == ^creds do
            nil -> nil
            session ->
              Repo.delete session
          end
        end
      end

      plug Coherence.Authentication.Session, db_model: MyProject.User, login: true

  You should be aware that the Agent is still used to fetch the user data if can
  be found. If the key is not found, it checks the database. If a record is found
  in the database, the agent is updated and the user data returned.

  This module is derived from https://github.com/lexmag/blaguth
  """

  @session_key Application.get_env(:coherence, :session_key, "session_auth")

  @behaviour Plug
  import Plug.Conn
  import Coherence.Authentication.Utils
  alias Coherence.{Config}
  require Logger

  @doc """
    Create a login for a user. `user_data` can be any term but must not be `nil`.
  """
  def create_login(conn, user_data, opts  \\ []) do
    id_key = Keyword.get(opts, :id_key, :id)
    store = Keyword.get(opts, :store, Coherence.CredentialStore.Session)
    id = UUID.uuid1

    store.put_credentials({id, user_data, id_key})
    put_session(conn, @session_key, id)
  end

  @doc """
    Delete a login.
  """
  def delete_login(conn, opts \\ []) do
    store = Keyword.get(opts, :store, Coherence.CredentialStore.Session)
    case get_session(conn, @session_key) do
      nil -> conn

      key ->
        store.delete_credentials(key)
        put_session(conn, @session_key, nil)
        |> put_session("user_return_to", nil)
    end
    |> delete_token_session
  end

  @doc false
  def init(opts) do
    # TODO: need to fix the default login callback
    login = case opts[:login] do
      true  -> &Coherence.SessionController.login_callback/1
      other -> other
    end
    %{
      login: login,
      error: Keyword.get(opts, :error, "HTTP Authentication Required"),
      db_model: Keyword.get(opts, :db_model),
      id_key: Keyword.get(opts, :id, :id),
      store: Keyword.get(opts, :store, Coherence.CredentialStore.Session),
      assigns_key: Keyword.get(opts, :assigns_key, :current_user),
      login_key: Keyword.get(opts, :login_cookie, Config.login_cookie),
      rememberable: Keyword.get(opts, :rememberable, Config.user_schema.rememberable?),
      cookie_expire: Keyword.get(opts, :login_cookie_expire_hours, Config.rememberable_cookie_expire_hours) * 60 * 60
    }
  end

  @doc false
  def call(conn, opts) do
    # IO.puts ".. opts: #{inspect opts}"
    unless get_authenticated_user(conn) do
      conn
      |> get_session_data
      |> verify_auth_key(opts, opts[:store])
      |> verify_rememberable(opts)
      |> assert_login(opts[:login], opts[:assigns_key])
    else
      conn
    end
  end

  defp get_session_data(conn) do
    session = get_session(conn, @session_key)
    {conn, session}
  end

  defp verify_rememberable({conn, nil}, %{rememberable: true, login_key: key} = opts)  do
    case conn.cookies[key] do
      nil -> {conn, nil}
      cookie ->
        case String.split cookie, " " do
          [id, series, token] ->
            case opts[:rememberable_callback] do
              nil ->
                Coherence.SessionController.remberable_callback(conn, id, series, token, opts)
              fun ->
                fun.(conn, id, series, token, opts)
            end
          _ -> {conn, nil}   # invalid cookie
        end
    end
  end
  defp verify_rememberable(other, _opts), do: other

  defp verify_auth_key({conn, nil}, _, _), do: {conn, nil}
  defp verify_auth_key({conn, auth_key}, %{db_model: db_model, id_key: id_key}, store),
    do: {conn, store.get_user_data({auth_key, db_model, id_key})}

  defp assert_login({conn, nil}, login, _) when is_function(login) do
    put_session(conn, "user_return_to", Path.join(["/" | conn.path_info]))
    |> login.()
  end
  defp assert_login({conn, user_data}, _, assign_key) do
    assign_user_data(conn, user_data, assign_key)
  end
  defp assert_login(conn, _, _), do: conn
end


update working_with_multiple_processes_8

defmodule FibSolver do
  def fib(scheduler) do
    send scheduler, {:ready, self()}
    receive do
      {:fib, n, client} -> send client, {:answer, n, fib_calc(n), self()}
                           fib(scheduler)
      {:shutdown} ->
        exit(:normal)
    end
  end

  # 意図的に、とても非効率にしている
  defp fib_calc(0), do: 0
  defp fib_calc(1), do: 1
  defp fib_calc(n), do: fib_calc(n - 1) + fib_calc(n - 2)
end

defmodule Scheduler do
  def run(num_processes, module, func, to_calculate) do
    (1..num_processes)
    |> Enum.map(fn (_) -> spawn(module, func, [self()]) end)
    |> schedule_processes(to_calculate, [])
  end

  defp schedule_processes(processes, queue, results) do
    receive do
      {:ready, pid} when length(queue) > 0 -> [next | tail] = queue
                                              send pid, {:fib, next, self()}
                                              schedule_processes(processes, tail, results)
      {:ready, pid} -> send pid, {:shutdown}
                       if length(processes) > 1 do
                         schedule_processes(List.delete(processes, pid), queue, results)
                       else
                         Enum.sort(results, fn {n1, _}, {n2, _} -> n1 <= n2 end)
                       end
      {:answer, number, result, _pid} -> schedule_processes(processes, queue, [{number, result} | results])
    end
  end
end

to_process = [37, 37, 37, 37, 37, 37]

Enum.each 1..10, fn num_processes ->
  {time, result} = :timer.tc(Scheduler, :run, [num_processes, FibSolver, :fib, to_process])
  if num_processes == 1 do
    IO.puts inspect result
    IO.puts "\n #   time (s)"
  end
  :io.format "~2B       ~.2f~n", [num_processes, time / 1000000.0]
end

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


Work around Gandalf problem, once again

Work around Gandalf problem, once again

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 StringsAndBinaries-5

add StringsAndBinaries-5

defmodule MyString5 do
  def center(dqs_list) do
    max = max_length(dqs_list)
    Enum.each(dqs_list, &(IO.puts(add_padding(&1, max))))
  end
  defp add_padding(dqs, max_length), do: String.duplicate(" ", div(max_length - String.length(dqs), 2)) <> dqs
  defp max_length(dqs_list), do: Enum.max(Enum.map(dqs_list, &(String.length(&1))))
end

MyString5.center(["cat", "zabra", "elephant"])
#   cat
#  zabra
# elephant

error: pathspec 'lib/StringsAndBinaries-5/center.ex' did not match any file(s) known to git


Indent query string and remove duplication

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/preciz/insta_scrapex.git/'


Initialisation de la track Elixir de Exercism

defmodule HelloWorld do
  @doc """
  Simply returns "Hello, World!"
  """
  @spec hello :: String.t()
  def hello do
    "Hello, World!"
  end
end

error: pathspec 'exercism/elixir/hello-world/lib/hello_world.ex' did not match any file(s) known to git


Add guards

Add guards

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/pdgonzalez872/work_samples.git/'


Fixed compare id in mix task to create thumbnails


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/sharkspeed/dororis.git/'


add steem block schema

add steem block schema

defmodule Glasnost.Steem.Block do
    use Ecto.Schema
    import Ecto.Changeset
    import Ecto.Query
    alias Ecto.Adapters.SQL
    alias Ecto.Multi
    alias Glasnost.Repo

    @primary_key false

    schema "golos_blocks" do
      field :extensions, {:array, :map}
      field :previous, :string
      field :timestamp, :naive_datetime
      field :transaction_merkle_root, :string
      field :transactions, {:array, :map}
      field :witness, :string
      field :witness_signatures, {:array, :string}
      field :height, :integer, primary_key: true

      timestamps
    end

    def changeset(data, params \\ %{}) do
      allowed_params = [:previous, :timestamp, :transaction_merkle_root, :witness, :witness_signatures, :transactions, :height]
      data
      |> cast(params, allowed_params)
      |> unique_constraint(:height)
    end

end

error: pathspec 'lib/glasnost/schemas/steem_block.ex' did not match any file(s) known to git


Added archive thumbnail url for youtube and vimeo

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/'


Moving Stats struct ahead of Character as Character.Stats solves the Module/Struct visibility problem.

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/scherrey/ADnD.git/'


Add module for performing dependency validation/discovery

defmodule ReleaseManager.Deps do
  @moduledoc """
  This module provides functions for retrieving dependency information.
  """

  @doc """
  Discovers missing applications which could prevent a release from running properly.
  Returns a tree to be formatted for output. The tree is a nested kwlist.
  """
  def get_missing_applications(options \\ []), do: get_missing_applications(Mix.Dep.loaded([]), options)
  def get_missing_applications(deps, options) when is_list(deps) and is_list(options) do
    ignore        = Keyword.get(options, :ignore, [])
    implicits     = flatten_tree(get_implicit_applications(ignore))
    included_apps = get_included_applications(deps)

    deps
    |> get_dependency_tree
    |> map_dependency_tree(fn app_name -> Enum.find(deps, fn %Mix.Dep{app: a} -> app_name == a end) end)
    |> filter_dependency_tree(fn %Mix.Dep{app: app, opts: opts} ->
      case is_dep_required?(opts) && not app in implicits do
        false -> false
        true ->
          # If this app is included by another application, ignore it
          not Enum.any?(included_apps, fn {_, children} ->
            app in children
          end)
      end
    end)
    |> map_dependency_tree(fn %Mix.Dep{app: app} -> app end)
  end

  @doc """
  Produces a list of lines to be printed, which display each missing application,
  the depedency graph representing where it comes from, and a short message describing
  where it should be added:

  ## Example

      exrm -> conform -> neotoma          => neotoma is missing from conform
      exrm -> relx -> providers -> getopt => getopt is missing from providers
      exrm -> relx -> getopt              => getopt is missing from relx
      exrm -> relx -> erlware_commons     => erlware_commons is missing from relx
      exrm -> relx -> bbmustache          => bbmustache is missing from relx
  """
  def print_missing_applications(options \\ []) do
    deps = Mix.Dep.loaded([])
    ignore = Keyword.get(options, :ignore, [])
    case get_missing_app_paths(get_missing_applications(deps, ignore: ignore), []) do
      [] -> ""
      missing_apps ->
        parents = missing_apps
                  |> Enum.map(fn
                    path when is_list(path) ->
                      List.first(Enum.drop(path, Enum.count(path) - 2))
                    path when is_atom(path) ->
                      path
                  end)
                  |> Enum.uniq
                  |> Enum.map(fn app -> {app, Enum.find(deps, fn %Mix.Dep{app: a} -> a == app end)} end)
        missing_apps
        |> Enum.map(fn
          path when is_list(path) ->
            parent = List.first(Enum.drop(path, Enum.count(path) - 2))
            dep = Keyword.get(parents, parent)
            {path, dep}
          path when is_atom(path) ->
            {[path], nil}
        end)
        |> format_requirements
    end
  end

  # Formats the requirements built in `print_missing_applications/0`
  defp format_requirements(apps) do
    apps = Enum.map(apps, fn {app_path, from_dep} ->
      path_str     = Enum.join(app_path, " -> ")
      required_app = List.last(app_path)
      case from_dep do
        nil ->
          {path_str, "=> #{required_app} is missing from #{Mix.Project.config[:app]}", String.length(path_str)}
        %Mix.Dep{} ->
          {path_str, "=> #{required_app} is missing from #{from_dep.app}", String.length(path_str)}
      end
    end)
    {_,_,pad_to} = Enum.max_by(apps, fn {_,_,len} -> len end)
    format_requirements(apps, Inspect.Algebra.empty, pad_to)
  end
  defp format_requirements([], doc, _pad_to) do
    doc
    |> Inspect.Algebra.nest(4 * 2)
    |> Inspect.Algebra.format(999)
  end
  defp format_requirements([{app, from, len}|apps], doc, pad_to) do
    glued = Inspect.Algebra.glue(pad_requirement(app, len, pad_to), from)
    doc   = Inspect.Algebra.line(doc, glued)
    format_requirements(apps, doc, pad_to)
  end
  defp pad_requirement(app, len, pad_to) do
    app <> String.duplicate(" ", pad_to - len)
  end

  # Flattens the dependency graph to show paths to individual missing applications
  defp get_missing_app_paths([], _acc), do: []
  defp get_missing_app_paths([{parent, []} | rest], acc) do
    [parent] ++ get_missing_app_paths(rest, acc)
  end
  defp get_missing_app_paths([{parent, children} | rest], acc) do
    result = get_missing_app_paths(children, [parent | acc])
    result ++ get_missing_app_paths(rest, acc)
  end
  defp get_missing_app_paths([app | rest], acc) when is_atom(app) do
    path = Enum.reverse([app | acc])
    [path | get_missing_app_paths(rest, acc)]
  end

  @doc """
  Returns a list of explict applications found in mix.exs :applications/:included_applications
  """
  def get_explicit_applications() do
    app_spec = Mix.Project.get!.application
    Keyword.get(app_spec, :applications, []) ++ Keyword.get(app_spec, :included_applications, [])
  end

  @doc """
  Returns a graph (represented as a nested keyword list) of implicitly included applications
  for the current project.
  """
  def get_implicit_applications(extras \\ []) do
    all_apps = get_included_applications()
    explicit = get_explicit_applications() ++ extras
    get_implicit_apps(explicit, all_apps, [])
  end

  @doc """
  Gets all applications and what applications they include.
  """
  def get_included_applications(), do: get_included_applications(Mix.Dep.loaded([]))
  def get_included_applications(deps) when is_list(deps) do
    deps
    |> Enum.map(&get_applications/1)
    |> List.flatten
    |> Enum.uniq
  end

  # Given a list of application names, and a list of all top_level applications,
  # this function builds a list of all applications which are implicitly included
  # in the release.
  defp get_implicit_apps([], _all_apps, acc), do: acc
  defp get_implicit_apps([app | rest], all_apps, acc) do
    case Keyword.get(all_apps, app, []) do
      []   -> get_implicit_apps(rest, all_apps, acc)
      apps ->
        case get_implicit_apps(apps, all_apps, []) do
          []      -> get_implicit_apps(rest, all_apps, [app | acc])
          subapps -> get_implicit_apps(rest, all_apps, [{app, subapps} | acc])
        end
    end
  end

  defp flatten_tree([]),   do: []
  defp flatten_tree(tree), do: flatten_tree(tree, [])
  defp flatten_tree([], acc), do: acc
  defp flatten_tree([element | rest], acc) when is_list(element), do: flatten_tree(rest, element++acc)
  defp flatten_tree([{parent, children} | rest], acc) do
    flatten_tree(rest, flatten_tree(children, [parent] ++ acc))
  end
  defp flatten_tree([element | rest], acc), do: flatten_tree(rest, [element | acc])

  # Gets applications for a given mix dependency
  defp get_applications(%Mix.Dep{app: app, manager: :mix, opts: opts}) do
    case is_dep_required?(opts) do
      false -> []
      true  ->
        project_dir = Keyword.get(opts, :dest)
        Mix.Project.in_project(app, project_dir, [], fn _ ->
          app_spec = Mix.Project.get.application
          apps     = Keyword.get(app_spec, :applications, [])
          inc_apps = Keyword.get(app_spec, :included_applications, [])
          [{app, apps ++ inc_apps}]
        end)
    end
  end
  # Gets applications for a given rebar dependency
  defp get_applications(%Mix.Dep{app: app, manager: :rebar, opts: opts}) do
    project_dir = Keyword.get(opts, :dest)
    case Path.wildcard(Path.join(project_dir, "**/*.app.src")) do
      [] -> []
      [app_src_path] ->
        case ReleaseManager.Utils.read_terms(app_src_path) do
          [{:application, ^app, config}] ->
            apps     = Keyword.get(config, :applications, [])
            inc_apps = Keyword.get(config, :included_applications, [])
            [{app, apps ++ inc_apps}]
          _ ->
            []
        end
    end
  end

  defp filter_dependency_tree(tree, fun),     do: filter_dependency_tree(tree, fun, [])
  defp filter_dependency_tree([], _fun, acc), do: acc
  defp filter_dependency_tree([dep | rest], fun, acc) when not is_tuple(dep) do
    case fun.(dep) do
      true  -> filter_dependency_tree(rest, fun, [dep | acc])
      false -> filter_dependency_tree(rest, fun, acc)
    end
  end
  defp filter_dependency_tree([{dep, children} | rest], fun, acc) do
    case fun.(dep) do
      true ->
        acc = [{dep, filter_dependency_tree(children, fun, [])} | acc]
        filter_dependency_tree(rest, fun, acc)
      false ->
        filter_dependency_tree(rest, fun, acc)
    end
  end

  defp map_dependency_tree(tree, fun),     do: map_dependency_tree(tree, fun, [])
  defp map_dependency_tree([], _fun, acc), do: acc
  defp map_dependency_tree([{dep, children} | rest], fun, acc) do
    acc = [{fun.(dep), map_dependency_tree(children, fun, [])} | acc]
    map_dependency_tree(rest, fun, acc)
  end
  defp map_dependency_tree([dep | rest], fun, acc) do
    map_dependency_tree(rest, fun, [fun.(dep) | acc])
  end

  # Loads the current project's dependency tree and returns it
  # as list of lists, where elements are either atoms (no children),
  # or key/value pairs (parent/children).
  defp get_dependency_tree(deps) do
    deps
    |> Enum.map(fn dep -> get_dependency_tree(dep, deps) end)
    |> List.flatten
  end
  defp get_dependency_tree(%Mix.Dep{app: a, deps: deps, top_level: true}, all_deps) do
    [{a, get_dependency_tree(deps, all_deps, [])}]
  end
  defp get_dependency_tree(%Mix.Dep{top_level: false}, _all_deps), do: []
  defp get_dependency_tree([], _all_deps, acc), do: acc
  defp get_dependency_tree([%Mix.Dep{app: a} | rest], all_deps, acc) do
    dep = Enum.find(all_deps, fn %Mix.Dep{app: app} -> app == a end)
    children = get_dependency_tree(dep.deps, all_deps, [])
    case children do
      [] -> get_dependency_tree(rest, all_deps, [dep.app | acc])
      _  -> get_dependency_tree(rest, all_deps, [{dep.app, children} | acc])
    end
  end

  # Given the kwlist options from %Mix.Deps{opts: opts},
  # determine if this dependency is required for the current
  # environment
  defp is_dep_required?(opts) when is_list(opts) do
    case Keyword.get(opts, :only) do
      envs when is_list(envs) -> Mix.env in envs
      nil -> true
      env -> Mix.env == env
    end
  end

end

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