From 2876b3b0f8be1afef31b70132dd9c666fb59e24c Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 25 Jan 2023 17:12:07 -0600 Subject: [PATCH 01/65] finish start here reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index c298c1f19..533202968 100644 --- a/progress.json +++ b/progress.json @@ -145,7 +145,7 @@ "task_drills_exercise": false, "monster_spawner_exercise": false, "metaprogramming_reading": false, - "start_here_reading": false, + "start_here_reading": true, "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, "lists_reading": false, From 6ba188603683f74cbd9486feb22db2f776c20e3e Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 25 Jan 2023 17:24:48 -0600 Subject: [PATCH 02/65] added code cell --- reading/start_here.livemd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reading/start_here.livemd b/reading/start_here.livemd index 6e4bfd8ae..91ef12af0 100644 --- a/reading/start_here.livemd +++ b/reading/start_here.livemd @@ -99,6 +99,10 @@ There is a **Commit Your Progress** and a **Mark as Completed** section at the e However, self-led students can complete these sections if they want to track their progress and get more practice using GitHub. We ask that you don't create pull requests to the DockYard Academy repo, as this spams our PR tracker. If you are not an academy student, we also ask that you refrain from @mentioning the instructor as this spams our notifications, and 1-1 feedback is only available to academy students. +```elixir +2 + 2 +``` + ## Mark As Completed From 0a2e73c32d0df5e0ea186a29ca1daadb7c44a06f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 11:14:52 -0600 Subject: [PATCH 03/65] finish github engineering journal exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 533202968..3f4340c8a 100644 --- a/progress.json +++ b/progress.json @@ -61,7 +61,7 @@ "animal_generator_exercise": false, "group_project_blog_exercise": false, "treasure_matching_exercise": false, - "github_engineering_journal_exercise": false, + "github_engineering_journal_exercise": true, "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": false, From 8a8ff711085c55107dfc960607d9ccef5c2e1603 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 11:16:57 -0600 Subject: [PATCH 04/65] finish github collab exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 3f4340c8a..50d0a7115 100644 --- a/progress.json +++ b/progress.json @@ -83,7 +83,7 @@ "phoenix_1.7_reading": false, "pic_chat_messages_reading": false, "math_game_exercise": false, - "github_collab_exercise": false, + "github_collab_exercise": true, "web_servers_reading": false, "book_search_deployment_reading": false, "tic-tac-toe_exercise": false, From 75427677965af1969dd4d2c904481f43eb0e4957 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 12:41:30 -0600 Subject: [PATCH 05/65] finish rock paper scissors exercise --- exercises/rock_paper_scissors.livemd | 24 +++++++++++++++++++++++- progress.json | 6 +++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/exercises/rock_paper_scissors.livemd b/exercises/rock_paper_scissors.livemd index 0cfd2820c..7b8073b0d 100644 --- a/exercises/rock_paper_scissors.livemd +++ b/exercises/rock_paper_scissors.livemd @@ -54,7 +54,15 @@ Then, return the winning choice of either `:rock`, `:paper`, or `:scissors` that Enter your solution below. ```elixir +player_choice = Enum.random([:rock, :paper, :scissors]) + +IO.puts(player_choice) +case player_choice do + :rock -> :paper + :paper -> :scissors + :scissors -> :rock +end ``` ## Create Two Player Rock Paper Scissors @@ -107,7 +115,21 @@ Bind a `player1_choice` and `player2_choice` variable to `:rock`, `:paper`, or ` Enter your solution below. ```elixir - +player1 = Enum.random([:rock, :paper, :scissors]) +IO.inspect(player1: player1) + +player2 = Enum.random([:rock, :paper, :scissors]) +IO.inspect(player2: player2) + +case {player1, player2} do + {:rock, :scissors} -> "Player 1 Wins!" + {:paper, :rock} -> "Player 1 Wins!" + {:scissors, :paper} -> "Player 1 Wins!" + {:rock, :paper} -> "Player 2 Wins!" + {:paper, :scissors} -> "Player 2 Wins!" + {:scissors, :rock} -> "Player 2 Wins!" + {same, same} -> "Draw" +end ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 50d0a7115..7eb0218a4 100644 --- a/progress.json +++ b/progress.json @@ -61,7 +61,7 @@ "animal_generator_exercise": false, "group_project_blog_exercise": false, "treasure_matching_exercise": false, - "github_engineering_journal_exercise": true, + "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": false, @@ -83,7 +83,7 @@ "phoenix_1.7_reading": false, "pic_chat_messages_reading": false, "math_game_exercise": false, - "github_collab_exercise": true, + "github_collab_exercise": false, "web_servers_reading": false, "book_search_deployment_reading": false, "tic-tac-toe_exercise": false, @@ -105,7 +105,7 @@ "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, - "rock_paper_scissors_exercise": false, + "rock_paper_scissors_exercise": true, "book_search_seeding_reading": false, "concurrent_word_count_exercise": false, "regex_reading": false, From 34a0a160d796163145900dd42be31775fc45dabb Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 13:23:12 -0600 Subject: [PATCH 06/65] finish naming numbers exercise --- exercises/naming_numbers.livemd | 30 ++++++++++++++++++++++++++++++ progress.json | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/exercises/naming_numbers.livemd b/exercises/naming_numbers.livemd index df121b16f..24319112b 100644 --- a/exercises/naming_numbers.livemd +++ b/exercises/naming_numbers.livemd @@ -72,7 +72,22 @@ naming_numbers.(1) Enter your solution below. ```elixir +naming_numbers = fn integer -> + case integer do + 0 -> "zero" + 1 -> "one" + 2 -> "two" + 3 -> "three" + 4 -> "four" + 5 -> "five" + 6 -> "six" + 7 -> "seven" + 8 -> "eight" + 9 -> "nine" + end +end +naming_numbers.(1) ``` ## Numbering Names @@ -169,7 +184,22 @@ flowchart ```elixir +numbering_names = fn int_str -> + case String.downcase(int_str) do + "zero" -> 0 + "one" -> 1 + "two" -> 2 + "three" -> 3 + "four" -> 4 + "five" -> 5 + "six" -> 6 + "seven" -> 7 + "eight" -> 8 + "nine" -> 9 + end +end +numbering_names.("Nine") ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 7eb0218a4..b7d5bc682 100644 --- a/progress.json +++ b/progress.json @@ -126,7 +126,7 @@ "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, "supervised_stack_exercise": false, - "naming_numbers_exercise": false, + "naming_numbers_exercise": true, "deployment_exercise": false, "typespecs_reading": false, "card_counting_exercise": false, From c9811638377aa23d7efb5a8a0427f8ba67911036 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 17:38:42 -0600 Subject: [PATCH 07/65] finish keyword lists reading --- progress.json | 22 +++++++++++----------- reading/keyword_lists.livemd | 10 ++++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/progress.json b/progress.json index b7d5bc682..ec8e821cc 100644 --- a/progress.json +++ b/progress.json @@ -13,7 +13,7 @@ "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, - "habit_tracker_exercise": false, + "habit_tracker_exercise": true, "reduce_reading": false, "code_editors_reading": false, "exdoc_reading": false, @@ -64,14 +64,14 @@ "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, - "git_reading": false, + "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, - "guessing_games_exercise": false, + "guessing_games_exercise": true, "sign_up_form_exercise": false, "enum_reading": false, "caesar_cypher_exercise": false, @@ -95,7 +95,7 @@ "liveview_reading": false, "process_mailbox_exercise": false, "io_reading": false, - "tuples_reading": false, + "tuples_reading": true, "ranges_reading": false, "task_reading": false, "executables_reading": false, @@ -105,7 +105,7 @@ "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, - "rock_paper_scissors_exercise": true, + "rock_paper_scissors_exercise": false, "book_search_seeding_reading": false, "concurrent_word_count_exercise": false, "regex_reading": false, @@ -119,17 +119,17 @@ "phone_number_parsing_exercise": false, "maps_reading": false, "exunit_reading": false, - "keyword_lists_reading": false, + "keyword_lists_reading": true, "command_line_reading": false, "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, "supervised_stack_exercise": false, - "naming_numbers_exercise": true, + "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, - "card_counting_exercise": false, + "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, @@ -148,7 +148,7 @@ "start_here_reading": true, "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, - "lists_reading": false, + "lists_reading": true, "message_validation_exercise": false, "functions_reading": false, "spoonacular_recipe_api_exercise": false, @@ -158,7 +158,7 @@ "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, - "livebook_reading": false, + "livebook_reading": true, "filter_values_by_type_exercise": false, "book_search_exercise": false, "guards_reading": false, @@ -205,5 +205,5 @@ "fibonacci_exercise": false, "typespec_drills_exercise": false, "custom_assertions_exercise": false, - "atoms_reading": false + "atoms_reading": true } \ No newline at end of file diff --git a/reading/keyword_lists.livemd b/reading/keyword_lists.livemd index b0d06161b..b8a3d435a 100644 --- a/reading/keyword_lists.livemd +++ b/reading/keyword_lists.livemd @@ -165,7 +165,7 @@ In the Elixir cell below, create a keyword list of your favourite super hero. In Enter your solution below. ```elixir - +[hero1: "superman", hero2: "batman", hero3: "robin"] ``` ## Accessing A Key @@ -184,6 +184,7 @@ Access the `:hello` key in the following keyword list. ```elixir keyword_list = [hello: "world"] +keyword_list[:hello] ``` ## Keyword List Operators @@ -206,13 +207,13 @@ evaluate as a tuple again. Remember that keyword lists are simply lists of tuple In the Elixir cell below, use `++` to add `[one: 1]` to `[two: 2]` to make `[one: 1, two: 2]`. ```elixir - +[one: 1] ++ [two: 2] ``` Remove `[two: 2]` from `[one: 1, two: 2]` to make `[one: 1]`. ```elixir - +[one: 1, two: 2] -- [two: 2] ``` ## Pattern Matching @@ -274,7 +275,8 @@ Bind `1` in the following keyword list to a variable `one`. Enter your solution below. ```elixir -[one: 1, two: 2, three: 3, four: 4] +[{key, one} | tail] = [one: 1, two: 2, three: 3, four: 4] +one ``` ## Further Reading From a55afc61846d8ee7c425079f0c3f8fc4ded7298a Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 17:52:42 -0600 Subject: [PATCH 08/65] finish maps reading --- reading/maps.livemd | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/reading/maps.livemd b/reading/maps.livemd index 3fc6d2a1c..f75b8f24a 100644 --- a/reading/maps.livemd +++ b/reading/maps.livemd @@ -193,6 +193,8 @@ map[:hello] ```elixir map = %{hello: "world"} +map.hello +map[:hello] ``` ### Updating Maps @@ -253,7 +255,9 @@ todo = %{title: "finish maps exercise", completed: false} ```elixir - +todo = %{title: "finish maps exercises", completed: false} +updated = %{todo | completed: true} +updated.completed ``` ## Pattern Matching @@ -332,7 +336,8 @@ Bind `2` and `4` in the following map to variables `two` and `four`. Enter your solution below. ```elixir -%{one: 1, two: 2, three: 3, four: 4} +%{two: two, four: four} = %{one: 1, two: 2, three: 3, four: 4} +four ``` ## Further Reading From f0a47b994b304010e13eeb54290cdeac9a680d47 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 18:20:34 -0600 Subject: [PATCH 09/65] finish modules reading --- progress.json | 12 +++---- reading/modules.livemd | 71 ++++++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/progress.json b/progress.json index ec8e821cc..c9e0da738 100644 --- a/progress.json +++ b/progress.json @@ -8,7 +8,7 @@ "credo_reading": false, "mazes_exercise": false, "rollable_expressions_exercise": false, - "modules_reading": false, + "modules_reading": true, "file_reading": false, "agents_and_ets_reading": false, "protocols_reading": false, @@ -71,7 +71,7 @@ "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, - "guessing_games_exercise": true, + "guessing_games_exercise": false, "sign_up_form_exercise": false, "enum_reading": false, "caesar_cypher_exercise": false, @@ -95,7 +95,7 @@ "liveview_reading": false, "process_mailbox_exercise": false, "io_reading": false, - "tuples_reading": true, + "tuples_reading": false, "ranges_reading": false, "task_reading": false, "executables_reading": false, @@ -119,7 +119,7 @@ "phone_number_parsing_exercise": false, "maps_reading": false, "exunit_reading": false, - "keyword_lists_reading": true, + "keyword_lists_reading": false, "command_line_reading": false, "stack_exercise": false, "traffic_light_server_exercise": false, @@ -148,7 +148,7 @@ "start_here_reading": true, "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, - "lists_reading": true, + "lists_reading": false, "message_validation_exercise": false, "functions_reading": false, "spoonacular_recipe_api_exercise": false, @@ -205,5 +205,5 @@ "fibonacci_exercise": false, "typespec_drills_exercise": false, "custom_assertions_exercise": false, - "atoms_reading": true + "atoms_reading": false } \ No newline at end of file diff --git a/reading/modules.livemd b/reading/modules.livemd index 13b965088..1bf6dbdc6 100644 --- a/reading/modules.livemd +++ b/reading/modules.livemd @@ -308,7 +308,13 @@ end Enter your solution below. ```elixir +defmodule Languages.German do + def greeting do + "Guten Tag" + end +end +Languages.German.greeting() ``` ### Nested Modules @@ -347,8 +353,8 @@ We use the `@` symbol to define a compile-time module attribute. ```elixir defmodule Hero do - @name "Spider-Man" - @nemesis "Green Goblin" + @name "Batman" + @nemesis "Penguin" def introduce do "Hello, my name is #{@name}!" @@ -506,7 +512,29 @@ end ```elixir +defmodule Math do + @moduledoc """ + Math Module + Module demonstrates 2 functions with same name and different arity + """ + + @doc """ + add/2 + """ + def add(a, b) do + a + b + end + + @doc """ + add/3 + """ + def add(a, b, c) do + a + b + c + end +end +Math.add(2, 3) +Math.add(2, 3, 4) ``` ## Default Arguments @@ -573,7 +601,14 @@ Greeting.hello("Andrew") ``` ```elixir +defmodule Greeting do + def hello(name \\ "fubar") do + "Hello #{name}" + end +end +Greeting.hello("extra fubar") +Greeting.hello() ``` ## Documentation @@ -658,7 +693,7 @@ defmodule DoctestFailure do "expected return value" """ def test do - "actual return value" + "expected return value" end end ``` @@ -686,25 +721,27 @@ If this is the case, you either have to fix your code, or remove/comment the cra Uncomment the following code and evaluate the cell to see an example. Re-comment your code to avoid crashing the livebook as you continue with the lesson. ```elixir -# defmodule DoctestCrash do -# @moduledoc """ -# DoctestCrash +defmodule DoctestCrash do + @moduledoc """ + DoctestCrash -# Explains doctest crashes with examples -# """ + Explains doctest crashes with examples + """ -# @doc """ -# Purposely crashes doctest using invalid pattern matching + @doc """ + Purposely crashes doctest using invalid pattern matching -# ## Examples + ## Examples -# iex> {} = DoctestCrash.crash() -# "2" -# """ -# def crash do + iex> DoctestCrash.crash() + "2" + """ + def crash do + "2" + end +end -# end -# end +DoctestCrash.crash() ``` ### Your Turn From 8b3ab22f3d6f52eac660ddc690ea8508bad66897 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 18:22:33 -0600 Subject: [PATCH 10/65] finish command line reading --- progress.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/progress.json b/progress.json index c9e0da738..ce5ef525a 100644 --- a/progress.json +++ b/progress.json @@ -8,12 +8,12 @@ "credo_reading": false, "mazes_exercise": false, "rollable_expressions_exercise": false, - "modules_reading": true, + "modules_reading": false, "file_reading": false, "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, - "habit_tracker_exercise": true, + "habit_tracker_exercise": false, "reduce_reading": false, "code_editors_reading": false, "exdoc_reading": false, @@ -64,7 +64,7 @@ "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, - "git_reading": true, + "git_reading": false, "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, @@ -120,7 +120,7 @@ "maps_reading": false, "exunit_reading": false, "keyword_lists_reading": false, - "command_line_reading": false, + "command_line_reading": true, "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, @@ -129,7 +129,7 @@ "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, - "card_counting_exercise": true, + "card_counting_exercise": false, "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, @@ -158,7 +158,7 @@ "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, - "livebook_reading": true, + "livebook_reading": false, "filter_values_by_type_exercise": false, "book_search_exercise": false, "guards_reading": false, From dbd8667733f90d0dc58bfa25ef4c3ac0472b2a86 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Feb 2023 16:39:49 -0600 Subject: [PATCH 11/65] finish rpg dialogue exercise --- .../rock_paper_scissors_lizard_spock.livemd | 19 ++++++++++ exercises/rpg_dialogue.livemd | 36 +++++++++++++++++-- progress.json | 10 +++--- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/exercises/rock_paper_scissors_lizard_spock.livemd b/exercises/rock_paper_scissors_lizard_spock.livemd index 400a7af02..0c4d4ec89 100644 --- a/exercises/rock_paper_scissors_lizard_spock.livemd +++ b/exercises/rock_paper_scissors_lizard_spock.livemd @@ -99,9 +99,28 @@ defmodule RockPaperScissorsLizardSpock do iex> RockPaperScissorsLizardSpock.play(:lizard, :lizard) "Player 2 Wins!" """ + def play(player1, player2) do + case {player1, player2} do + {:rock, :paper} -> "Player 2 Wins!" + end end end + +RockPaperScissorsLizardSpock.play(:rock, :paper) +``` + +```elixir +# input/output +# input -> :rock, :paper, etc... +# output -> winner "Player 2 Wins!" + +player1 = :rock +player2 = :paper + +case {player1, player2} do + {:rock, :paper} -> "Player 2 Wins!" +end ``` ## Mark As Completed diff --git a/exercises/rpg_dialogue.livemd b/exercises/rpg_dialogue.livemd index dd17f3caf..890a7a579 100644 --- a/exercises/rpg_dialogue.livemd +++ b/exercises/rpg_dialogue.livemd @@ -82,7 +82,9 @@ defmodule Character do iex> %Character{name: "Frodo"} ** (ArgumentError) the following keys must also be given when building struct Character: [:name] """ - defstruct [] + @enforced_key [:name] + + defstruct @enforced_key ++ [:class, :weapon] @doc """ Introduce the character by name. @@ -96,6 +98,7 @@ defmodule Character do "My name is Aragorn." """ def introduce(character) do + "My name is #{character.name}." end @doc """ @@ -110,6 +113,7 @@ defmodule Character do "I attack with my sword!" """ def attack(character) do + "I attack with my #{character.weapon}!" end @doc """ @@ -124,6 +128,7 @@ defmodule Character do "I am a ranger." """ def class(character) do + "I am a #{character.class}." end @doc """ @@ -138,8 +143,13 @@ defmodule Character do "My name is Aragorn and I am a ranger!" """ def war_cry(character) do + "My name is #{character.name} and I am a #{character.class}!" end + # def war_cry2(name, class) do + # "My name is #{name} and I am a #{class}" + # end + @doc """ Declare that one character has defeated another. @@ -151,9 +161,31 @@ defmodule Character do iex> Character.defeat(%Character{name: "Aragorn"}, %Character{name: "Gimli", class: "warrior"}) "My name is Aragorn and I have defeated the warrior Gimli!" """ - def defeat(character1, character2) do + def defeat(char1 = %Character{}, char2 = %Character{}) do + "My name is #{char1.name} and I have defeated the #{char2.class} #{char2.name}!" end end + +# defmodule Test do +# import Character + +# def test do +# aragorn = %Character{name: "Aragorn", class: "ranger", weapon: "sword"} +# gandalf = %Character{name: "Gandalf", class: "wizard", weapon: "staff"} +# Character.introduce(aragorn) +# Character.attack(aragorn) +# Character.class(aragorn) +# Character.war_cry(aragorn) +# Character.war_cry2(aragorn.name, aragorn.class) +# Character.defeat(aragorn, gandalf) +# end +# end + +# Test.test +``` + +```elixir + ``` ### Bonus: Character Instances diff --git a/progress.json b/progress.json index ce5ef525a..be490de2a 100644 --- a/progress.json +++ b/progress.json @@ -15,7 +15,7 @@ "games_score_tracker_exercise": false, "habit_tracker_exercise": false, "reduce_reading": false, - "code_editors_reading": false, + "code_editors_reading": true, "exdoc_reading": false, "process_drills_exercise": false, "saferange_exercise": false, @@ -64,7 +64,7 @@ "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, - "git_reading": false, + "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, @@ -101,7 +101,7 @@ "executables_reading": false, "rdbms_reading": false, "fun_formulas_exercise": false, - "rpg_dialogue_exercise": false, + "rpg_dialogue_exercise": true, "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, @@ -120,7 +120,7 @@ "maps_reading": false, "exunit_reading": false, "keyword_lists_reading": false, - "command_line_reading": true, + "command_line_reading": false, "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, @@ -158,7 +158,7 @@ "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, - "livebook_reading": false, + "livebook_reading": true, "filter_values_by_type_exercise": false, "book_search_exercise": false, "guards_reading": false, From 73b6e43bb93a9144c4e1d6798c9147a0a5aeabb2 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Feb 2023 17:47:25 -0600 Subject: [PATCH 12/65] finish rock paper scissors lizard spock exercise --- .../rock_paper_scissors_lizard_spock.livemd | 25 +++++++++++-------- progress.json | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/exercises/rock_paper_scissors_lizard_spock.livemd b/exercises/rock_paper_scissors_lizard_spock.livemd index 0c4d4ec89..e924cdd3f 100644 --- a/exercises/rock_paper_scissors_lizard_spock.livemd +++ b/exercises/rock_paper_scissors_lizard_spock.livemd @@ -83,6 +83,17 @@ defmodule RockPaperScissorsLizardSpock do false """ def beats?(guess1, guess2) do + {guess1, guess2} in [ + {:rock, :scissors}, + {:rock, :lizard}, + {:paper, :rock}, + {:paper, :spock}, + {:scissors, :paper}, + {:scissors, :lizards}, + {:lizard, :paper}, + {:lizard, :spock}, + {:spock, :scissors} + ] end @doc """ @@ -101,8 +112,9 @@ defmodule RockPaperScissorsLizardSpock do """ def play(player1, player2) do - case {player1, player2} do - {:rock, :paper} -> "Player 2 Wins!" + cond do + beats?(player1, player2) -> "Player 1 Wins!" + not beats?(player1, player2) -> "Player 2 Wins!" end end end @@ -111,16 +123,7 @@ RockPaperScissorsLizardSpock.play(:rock, :paper) ``` ```elixir -# input/output -# input -> :rock, :paper, etc... -# output -> winner "Player 2 Wins!" -player1 = :rock -player2 = :paper - -case {player1, player2} do - {:rock, :paper} -> "Player 2 Wins!" -end ``` ## Mark As Completed diff --git a/progress.json b/progress.json index be490de2a..7d99e11d1 100644 --- a/progress.json +++ b/progress.json @@ -175,7 +175,7 @@ "blog_tags_exercise": false, "structs_reading": false, "games_wordle_exercise": false, - "rock_paper_scissors_lizard_spock_exercise": false, + "rock_paper_scissors_lizard_spock_exercise": true, "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, From 5b672c135e74e187ad04eed868ae642e632063de Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 10:45:16 -0600 Subject: [PATCH 13/65] finish ranges reading --- exercises/rpg_dialogue.livemd | 18 +++++++++--------- progress.json | 6 +++--- reading/ranges.livemd | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/exercises/rpg_dialogue.livemd b/exercises/rpg_dialogue.livemd index 890a7a579..7006b4ffd 100644 --- a/exercises/rpg_dialogue.livemd +++ b/exercises/rpg_dialogue.livemd @@ -97,8 +97,8 @@ defmodule Character do iex> Character.introduce(%Character{name: "Aragorn"}) "My name is Aragorn." """ - def introduce(character) do - "My name is #{character.name}." + def introduce(char) do + "My name is #{char.name}." end @doc """ @@ -112,8 +112,8 @@ defmodule Character do iex> Character.attack(%Character{name: "Aragorn", weapon: "sword"}) "I attack with my sword!" """ - def attack(character) do - "I attack with my #{character.weapon}!" + def attack(char) do + "I attack with my #{char.weapon}!" end @doc """ @@ -127,8 +127,8 @@ defmodule Character do iex> Character.class(%Character{name: "Aragorn", class: "ranger"}) "I am a ranger." """ - def class(character) do - "I am a #{character.class}." + def class(char) do + "I am a #{char.class}." end @doc """ @@ -142,8 +142,8 @@ defmodule Character do iex> Character.war_cry(%Character{name: "Aragorn", class: "ranger"}) "My name is Aragorn and I am a ranger!" """ - def war_cry(character) do - "My name is #{character.name} and I am a #{character.class}!" + def war_cry(char) do + "My name is #{char.name} and I am a #{char.class}!" end # def war_cry2(name, class) do @@ -161,7 +161,7 @@ defmodule Character do iex> Character.defeat(%Character{name: "Aragorn"}, %Character{name: "Gimli", class: "warrior"}) "My name is Aragorn and I have defeated the warrior Gimli!" """ - def defeat(char1 = %Character{}, char2 = %Character{}) do + def defeat(char1, char2) do "My name is #{char1.name} and I have defeated the #{char2.class} #{char2.name}!" end end diff --git a/progress.json b/progress.json index 7d99e11d1..53ea874be 100644 --- a/progress.json +++ b/progress.json @@ -96,12 +96,12 @@ "process_mailbox_exercise": false, "io_reading": false, "tuples_reading": false, - "ranges_reading": false, + "ranges_reading": true, "task_reading": false, "executables_reading": false, "rdbms_reading": false, "fun_formulas_exercise": false, - "rpg_dialogue_exercise": true, + "rpg_dialogue_exercise": false, "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, @@ -175,7 +175,7 @@ "blog_tags_exercise": false, "structs_reading": false, "games_wordle_exercise": false, - "rock_paper_scissors_lizard_spock_exercise": true, + "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, diff --git a/reading/ranges.livemd b/reading/ranges.livemd index 342c427b9..e089b5708 100644 --- a/reading/ranges.livemd +++ b/reading/ranges.livemd @@ -121,7 +121,7 @@ In the Elixir cell below, use [Enum.to_list/1](https://hexdocs.pm/elixir/Enum.ht ```elixir - +Enum.to_list(3..9//3) ``` ### Pattern Matching With Ranges From 74dbfe714e7d56fc84bf93153ae38dbc62b9a528 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 14:08:57 -0600 Subject: [PATCH 14/65] finish fizzbuzz exercise --- exercises/fizzbuzz.livemd | 10 ++++++++++ progress.json | 2 +- reading/enum.livemd | 25 +++++++++++++++++++------ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/exercises/fizzbuzz.livemd b/exercises/fizzbuzz.livemd index 179fe2c17..a1393a308 100644 --- a/exercises/fizzbuzz.livemd +++ b/exercises/fizzbuzz.livemd @@ -77,8 +77,18 @@ defmodule FizzBuzz do ["buzz", 11, "fizz", 13, 14, "fizzbuzz"] """ def run(range) do + Enum.map(range, fn int -> + cond do + rem(int, 15) == 0 -> "fizzbuzz" + rem(int, 3) == 0 -> "fizz" + rem(int, 5) == 0 -> "buzz" + true -> int + end + end) end end + +FizzBuzz.run(1..15) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 53ea874be..8dad7d1e4 100644 --- a/progress.json +++ b/progress.json @@ -191,7 +191,7 @@ "doctests_reading": false, "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, - "fizzbuzz_exercise": false, + "fizzbuzz_exercise": true, "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, diff --git a/reading/enum.livemd b/reading/enum.livemd index 64a5398d2..f8859418c 100644 --- a/reading/enum.livemd +++ b/reading/enum.livemd @@ -371,7 +371,7 @@ Use [Enum.map/2](https://hexdocs.pm/elixir/1.12/Enum.html#map/2) to convert a li Enter your solution below. ```elixir - +Enum.map(1..10, fn int -> to_string(int) end) ``` ## Enum.reduce/2 and Enum.reduce/3 @@ -492,7 +492,13 @@ Use [Enum.reduce/3](https://hexdocs.pm/elixir/Enum.html#reduce/3) or [Enum.reduc Enter your solution below. ```elixir - +Enum.reduce(1..10, 0, fn int, acc -> + if rem(int, 2) == 0 do + acc + int + else + acc + end +end) ``` ## Enum.filter @@ -530,7 +536,8 @@ odd_numbers = Enum.filter(1..10, fn integer -> rem(integer, 2) != 0 end) Enter your solution below. ```elixir - +even = Enum.filter(1..10, fn int -> rem(int, 2) == 0 end) +odd = Enum.filter(1..10, fn int -> rem(int, 2) != 0 end) ``` ## Enum.all?/2 @@ -585,6 +592,7 @@ Use [Enum.all/2](https://hexdocs.pm/elixir/Enum.html#all/2) to determine if all ```elixir colors = [:green, :green, :red] +Enum.all?(colors, fn color -> color == :green end) ``` ## Enum.any/2 @@ -628,7 +636,8 @@ Enum.any?(1..10_000_000, fn integer -> is_bitstring(integer) end) Use [Enum.any/2](https://hexdocs.pm/elixir/Enum.html#any/2) to determine if any of the animals in the `animals` list are `:dogs`. You may change the `animals` list to experiment with [Enum.any/2](https://hexdocs.pm/elixir/Enum.html#any/2). ```elixir -[:cats, :dogs, :bears, :lions, :penguins] +animals = [:cats, :dogs, :bears, :lions, :penguins] +Enum.any?(animals, fn animal -> animal == :dogs end) ``` ## Enum.count/1 @@ -656,6 +665,8 @@ In the Elixir cell below, count the number of elements in the `collection`. It s ```elixir collection = [1, 2, 3, 4, 5] + +Enum.count(collection) ``` ## Enum.find/3 @@ -683,7 +694,9 @@ Enum.find(["h", "e", "l", "l", "o"], 10, fn each -> is_integer(each) end) Use [Enum.find/2](https://hexdocs.pm/elixir/Enum.html#find/2) to find the first even integer in this list. ```elixir -[1, "2", "three", 4, "five", 6] +mylist = [1, "2", "three", 4, "five", 6] + +Enum.find(mylist, fn item -> is_integer(item) && rem(item, 2) == 0 end) ``` ## Enum.random/1 @@ -710,7 +723,7 @@ Enum.map(1..10, fn _ -> Enum.random(0..9) end) Enter your solution below. ```elixir - +Enum.random(0..9) ``` ## Capture Operator and Module Functions From a89e9360c2be0a005304609b7c04f779d24edcf4 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 14:15:34 -0600 Subject: [PATCH 15/65] finish enum reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 8dad7d1e4..e179254cf 100644 --- a/progress.json +++ b/progress.json @@ -73,7 +73,7 @@ "games_benchmarking_exercise": false, "guessing_games_exercise": false, "sign_up_form_exercise": false, - "enum_reading": false, + "enum_reading": true, "caesar_cypher_exercise": false, "booleans_reading": false, "blog_comments_exercise": false, From fa6599b3675cd48434cd85e17627f4fbbc262ba8 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 16:43:05 -0600 Subject: [PATCH 16/65] finish named number lists exercise --- exercises/named_number_lists.livemd | 17 ++++++++++++++++- progress.json | 6 +++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/exercises/named_number_lists.livemd b/exercises/named_number_lists.livemd index 7b1f06cba..ac6e70d07 100644 --- a/exercises/named_number_lists.livemd +++ b/exercises/named_number_lists.livemd @@ -75,7 +75,22 @@ flowchart Enter your solution below. ```elixir - +rando = Enum.map(1..10, fn _ -> Enum.random(0..9) end) + +Enum.map(rando, fn int -> + case int do + 0 -> "zero" + 1 -> "one" + 2 -> "two" + 3 -> "three" + 4 -> "four" + 5 -> "five" + 6 -> "six" + 7 -> "seven" + 8 -> "eight" + 9 -> "nine" + end +end) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index e179254cf..3d4eb82d7 100644 --- a/progress.json +++ b/progress.json @@ -65,7 +65,7 @@ "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": true, - "named_number_lists_exercise": false, + "named_number_lists_exercise": true, "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, @@ -73,7 +73,7 @@ "games_benchmarking_exercise": false, "guessing_games_exercise": false, "sign_up_form_exercise": false, - "enum_reading": true, + "enum_reading": false, "caesar_cypher_exercise": false, "booleans_reading": false, "blog_comments_exercise": false, @@ -191,7 +191,7 @@ "doctests_reading": false, "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, - "fizzbuzz_exercise": true, + "fizzbuzz_exercise": false, "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, From 11daeb169041dfa5efc838c157fd2f334ad42ca8 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Feb 2023 17:01:48 -0600 Subject: [PATCH 17/65] finish counting votes exercise --- exercises/anagram.livemd | 2 ++ exercises/animal_generator.livemd | 6 ++++++ exercises/book_search.livemd | 3 +++ exercises/counting_votes.livemd | 9 +++++++++ exercises/palindrome.livemd | 1 + progress.json | 10 +++++----- reading/built-in_modules.livemd | 28 ++++++++++++++++------------ reading/comprehensions.livemd | 8 ++++++-- reading/non_enumerables.livemd | 6 ++++-- 9 files changed, 52 insertions(+), 21 deletions(-) diff --git a/exercises/anagram.livemd b/exercises/anagram.livemd index 99d40a44d..af3db1a5c 100644 --- a/exercises/anagram.livemd +++ b/exercises/anagram.livemd @@ -67,6 +67,7 @@ defmodule Anagram do true """ def anagram?(string1, string2) do + String.to_charlist(string1) |> Enum.sort() == String.to_charlist(string2) |> Enum.sort() end @doc """ @@ -84,6 +85,7 @@ defmodule Anagram do [] """ def filter_anagrams(word_list, anagram) do + Enum.filter(word_list, fn word -> anagram?(word, anagram) end) end end ``` diff --git a/exercises/animal_generator.livemd b/exercises/animal_generator.livemd index 81d96f88c..12d9cc543 100644 --- a/exercises/animal_generator.livemd +++ b/exercises/animal_generator.livemd @@ -57,7 +57,13 @@ end Enter your solution below. ```elixir +names = ["Clifford", "Zoboomafoo", "Leonardo"] +animal_types = ["dog", "lemur", "turtle"] +ages = 1..14 +for name <- names, animal_type <- animal_types, age <- ages do + %{name: name, animal_type: animal_type, age: age} +end ``` ## Mark As Completed diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index a63beca18..dadb02a1a 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -30,6 +30,8 @@ defmodule Book do iex> %Book{title: "My Book Title"} %Book{title: "My Book Title"} """ + @enforce_keys [:title] + defstruct @enforce_keys @doc """ Search a list of Book structs. Search should match any book that includes the @@ -59,6 +61,7 @@ defmodule Book do [%Book{title: "ABC"}] """ def search(books, query) do + Enum.filter(books, fn book -> Book[:title] == query end) end end ``` diff --git a/exercises/counting_votes.livemd b/exercises/counting_votes.livemd index b7ca899b0..366b25eae 100644 --- a/exercises/counting_votes.livemd +++ b/exercises/counting_votes.livemd @@ -80,6 +80,7 @@ defmodule Votes do 0 """ def count(votes, vote) do + Enum.count(Enum.filter(votes, fn item -> item == vote end)) end end ``` @@ -120,6 +121,14 @@ defmodule VoterTally do %{dog: 2, cat: 3, bird: 1} """ def tally(votes) do + for {:dog, dogs}, {:cat, cats}, {:bird, birds} <- [votes] do + %{dog: dogs, cat: cats, bird: birds} + end + + # dogs = Enum.count(Enum.filter(votes, fn item -> item == :dog end)) + # cats = Enum.count(Enum.filter(votes, fn item -> item == :cat end)) + # birds = Enum.count(Enum.filter(votes, fn item -> item == :bird end)) + # %{dog: dogs, cat: cats, bird: birds} end end ``` diff --git a/exercises/palindrome.livemd b/exercises/palindrome.livemd index a6137c0ba..7a3b1c845 100644 --- a/exercises/palindrome.livemd +++ b/exercises/palindrome.livemd @@ -70,6 +70,7 @@ defmodule Palindrome do false """ def palindrome?(string) do + string == String.reverse(string) end end ``` diff --git a/progress.json b/progress.json index 3d4eb82d7..3dec5fc09 100644 --- a/progress.json +++ b/progress.json @@ -13,9 +13,9 @@ "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, - "habit_tracker_exercise": false, + "habit_tracker_exercise": true, "reduce_reading": false, - "code_editors_reading": true, + "code_editors_reading": false, "exdoc_reading": false, "process_drills_exercise": false, "saferange_exercise": false, @@ -65,7 +65,7 @@ "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": true, - "named_number_lists_exercise": true, + "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, @@ -96,7 +96,7 @@ "process_mailbox_exercise": false, "io_reading": false, "tuples_reading": false, - "ranges_reading": true, + "ranges_reading": false, "task_reading": false, "executables_reading": false, "rdbms_reading": false, @@ -129,7 +129,7 @@ "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, - "card_counting_exercise": false, + "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, diff --git a/reading/built-in_modules.livemd b/reading/built-in_modules.livemd index 55aeaa455..bc6b52d53 100644 --- a/reading/built-in_modules.livemd +++ b/reading/built-in_modules.livemd @@ -108,6 +108,7 @@ Use [Kernel.elem/2](https://hexdocs.pm/elixir/Kernel.html#elem/2) to retrieve `1 ```elixir tuple = {0, 4, 1, 100, 5, 7} +elem(tuple, 3) ``` ## Checking Types @@ -149,31 +150,31 @@ is_atom(:example) ``` ```elixir -%{} +is_map(%{}) ``` ```elixir -{} +is_map({}) ``` ```elixir -[] +is_list([]) ``` ```elixir -true +is_boolean(true) ``` ```elixir -1.0 +is_float(1.0) ``` ```elixir -1 +is_integer(1) ``` ```elixir -"" +is_binary("") ``` The [Kernel](https://hexdocs.pm/elixir/Kernel.html) is reasonably large. Remember, our goal is not to memorize every function but to develop familiarity with repeated practice. @@ -213,8 +214,10 @@ Created a `capped_seconds` variable that uses the value of `seconds` and cannot Enter your solution below. if `seconds` is less than `0` `capped_seconds` should be `0`. If `seconds` is greater than `59`, then `capped_seconds` should be `59`. ```elixir -seconds = 60 -capped_seconds = nil +seconds = 20 +# min(seconds, 59) +# max(seconds, 0) +capped_seconds = max(min(seconds, 59), 0) ``` ## Safe Inspection @@ -264,7 +267,8 @@ map = %{} list = [1, 2, 3] tuple = {1, 2, 3} -"" +# "" +inspect(tuple) ``` ## The Integer Module @@ -345,7 +349,7 @@ Use the [Integer.gcd/2](https://hexdocs.pm/elixir/Integer.html#gcd/2) function t positive integer that divides both 10 and 15 evenly, so the result should be `5`. ```elixir - +Integer.gcd(10, 15) ``` ## The String Module @@ -427,7 +431,7 @@ Use the [String.at/2](https://hexdocs.pm/elixir/String.html#at/2) function to ge ```elixir -"hello" +String.at("hello", 2) ``` Use the [String.at/2](https://hexdocs.pm/elixir/String.html#at/2) function to retrieve the letter `"o"` in `"hello"` diff --git a/reading/comprehensions.livemd b/reading/comprehensions.livemd index 9d2eae025..a573a6148 100644 --- a/reading/comprehensions.livemd +++ b/reading/comprehensions.livemd @@ -222,7 +222,9 @@ each generator creates another nested loop and therefore has a significant perfo In the Elixir cell below, use a comprehension with a generator of `1..50` to create a list of even integers from `2` to `100`. ```elixir - +for n <- 1..50, rem(n, 2) == 0 do + n +end ``` ## Filters @@ -315,7 +317,9 @@ end ```elixir - +for a <- 1..7, b <- 1..7, c <- 1..7, a + b + c == 7 do + {a, b, c} +end ``` ## Collectables diff --git a/reading/non_enumerables.livemd b/reading/non_enumerables.livemd index 724734dd2..77501acd6 100644 --- a/reading/non_enumerables.livemd +++ b/reading/non_enumerables.livemd @@ -57,7 +57,7 @@ Integer.digits(123) In the Elixir cell below, convert the integer `4389` into a list of digits. ```elixir - +Integer.digits(4389) ``` ### Undigits @@ -138,7 +138,7 @@ Now your string is an enumerable list of characters. In the Elixir cell below, convert the string `"Hello, world!"` into a list of single characters. ```elixir - +String.split("Hello, world!", "") ``` ### Joining Strings @@ -216,6 +216,8 @@ defmodule CharacterCount do 4 """ def count(string) do + String.split(String.trim(string), "") + # Enum.count(String.split(string, "")) end end ``` From f4d0d1299401a1bc047c69b931bbd6e6914fcb18 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Feb 2023 17:03:49 -0600 Subject: [PATCH 18/65] finish animal generator exercise --- exercises/counting_votes.livemd | 12 ++++-------- progress.json | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/exercises/counting_votes.livemd b/exercises/counting_votes.livemd index 366b25eae..cb1e0c25e 100644 --- a/exercises/counting_votes.livemd +++ b/exercises/counting_votes.livemd @@ -121,14 +121,10 @@ defmodule VoterTally do %{dog: 2, cat: 3, bird: 1} """ def tally(votes) do - for {:dog, dogs}, {:cat, cats}, {:bird, birds} <- [votes] do - %{dog: dogs, cat: cats, bird: birds} - end - - # dogs = Enum.count(Enum.filter(votes, fn item -> item == :dog end)) - # cats = Enum.count(Enum.filter(votes, fn item -> item == :cat end)) - # birds = Enum.count(Enum.filter(votes, fn item -> item == :bird end)) - # %{dog: dogs, cat: cats, bird: birds} + dogs = Enum.count(Enum.filter(votes, fn item -> item == :dog end)) + cats = Enum.count(Enum.filter(votes, fn item -> item == :cat end)) + birds = Enum.count(Enum.filter(votes, fn item -> item == :bird end)) + %{dog: dogs, cat: cats, bird: birds} end end ``` diff --git a/progress.json b/progress.json index 3dec5fc09..47f0c438c 100644 --- a/progress.json +++ b/progress.json @@ -58,7 +58,7 @@ "math_with_guards_exercise": false, "pokemon_api_exercise": false, "file_search_exercise": false, - "animal_generator_exercise": false, + "animal_generator_exercise": true, "group_project_blog_exercise": false, "treasure_matching_exercise": false, "github_engineering_journal_exercise": false, From fa1f08ac22661c6e24524cacd4617fbdc4cdb721 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Feb 2023 17:05:45 -0600 Subject: [PATCH 19/65] finish palindrome exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 47f0c438c..03aa34b19 100644 --- a/progress.json +++ b/progress.json @@ -102,7 +102,7 @@ "rdbms_reading": false, "fun_formulas_exercise": false, "rpg_dialogue_exercise": false, - "palindrome_exercise": false, + "palindrome_exercise": true, "comprehensions_reading": false, "comments_reading": false, "rock_paper_scissors_exercise": false, From 5feaba5a46ea75a48cb82b9edada7dd55524fa8b Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 10:28:35 -0600 Subject: [PATCH 20/65] finish built-in modules reading --- progress.json | 2 +- reading/built-in_modules.livemd | 37 +++++++++++++++++---------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/progress.json b/progress.json index 03aa34b19..2bb025094 100644 --- a/progress.json +++ b/progress.json @@ -180,7 +180,7 @@ "with_points_exercise": false, "itinerary_exercise": false, "apis_reading": false, - "built-in_modules_reading": false, + "built-in_modules_reading": true, "rps_pattern_matching_exercise": false, "arithmetic_reading": false, "rps_guards_exercise": false, diff --git a/reading/built-in_modules.livemd b/reading/built-in_modules.livemd index bc6b52d53..d574b8f19 100644 --- a/reading/built-in_modules.livemd +++ b/reading/built-in_modules.livemd @@ -614,7 +614,7 @@ Use [List.delete_at/2](https://hexdocs.pm/elixir/List.html#delete_at/2) to remov ```elixir -[2, 1, 3] +List.delete_at([2, 1, 3], 0) ``` Use [List.flatten/1](https://hexdocs.pm/elixir/List.html#flatten/1) to flatten the following list into `[1, 2, 3, 4, 5, 6, 7, 8, 9]` @@ -630,7 +630,7 @@ Use [List.flatten/1](https://hexdocs.pm/elixir/List.html#flatten/1) to flatten t ```elixir -[1, 2, [3, 4, 5], 6, [7, [8, [9]]]] +List.flatten([1, 2, [3, 4, 5], 6, [7, [8, [9]]]]) ``` Use [List.insert_at/3](https://hexdocs.pm/elixir/List.html#insert_at/3) to insert `2` into the following list to make `[1, 2, 3]`. @@ -646,7 +646,7 @@ Use [List.insert_at/3](https://hexdocs.pm/elixir/List.html#insert_at/3) to inser ```elixir -[1, 3] +List.insert_at([1, 3], 1, 2) ``` Use [List.last/2](https://hexdocs.pm/elixir/List.html#last/2) to retrieve the last element `10000` in a list from `1` to `10000`. @@ -668,7 +668,7 @@ Use [List.last/2](https://hexdocs.pm/elixir/List.html#last/2) to retrieve the la ```elixir -Enum.to_list(1..10000) +List.last(Enum.to_list(1..10000)) ``` Use [List.update_at/3](https://hexdocs.pm/elixir/List.html#update_at/3) to subtract `2` from `4` in the following list to make `[1, 2, 3]`. @@ -684,7 +684,7 @@ Use [List.update_at/3](https://hexdocs.pm/elixir/List.html#update_at/3) to subtr ```elixir -[1, 4, 3] +List.update_at([1, 4, 3], 1, &(&1 - 2)) ``` Use [List.zip/1](https://hexdocs.pm/elixir/List.html#zip/1) to combine these two lists to make `[{"a", 1}, {"b", 2}, {"c", 3}]`. @@ -705,6 +705,7 @@ Use [List.zip/1](https://hexdocs.pm/elixir/List.html#zip/1) to combine these two ```elixir letters = ["a", "b", "c"] numbers = [1, 2, 3] +List.zip([letters, numbers]) ``` ## The Map Module @@ -760,7 +761,7 @@ Use [Map.get/3](https://hexdocs.pm/elixir/Map.html#get/3) to retrieve the `"worl ```elixir -%{hello: "world"} +Map.get(%{hello: "world"}, :hello) ``` Use [Map.put/3](https://hexdocs.pm/elixir/Map.html#put/3) to add the key `:two` with the value `2` to the following map. @@ -776,7 +777,7 @@ Use [Map.put/3](https://hexdocs.pm/elixir/Map.html#put/3) to add the key `:two` ```elixir -%{one: 1} +Map.put(%{one: 1}, :two, 2) ``` Use [Map.keys/1](https://hexdocs.pm/elixir/Map.html#keys/1) to retrieve the keys for the following map. @@ -792,7 +793,7 @@ Use [Map.keys/1](https://hexdocs.pm/elixir/Map.html#keys/1) to retrieve the keys ```elixir -%{key1: 1, key2: 2, key3: 3} +Map.keys(%{key1: 1, key2: 2, key3: 3}) ``` Use [Map.delete/2](https://hexdocs.pm/elixir/Map.html#delete/2) to remove `:key1` from the following map. @@ -808,7 +809,7 @@ Use [Map.delete/2](https://hexdocs.pm/elixir/Map.html#delete/2) to remove `:key1 ```elixir -%{key1: 1, key2: 2, key3: 3} +Map.delete(%{key1: 1, key2: 2, key3: 3}, :key1) ``` Use [Map.merge/2](https://hexdocs.pm/elixir/Map.html#merge/2) to combine `%{one: 1}` and `%{two: 2}`. @@ -824,7 +825,7 @@ Use [Map.merge/2](https://hexdocs.pm/elixir/Map.html#merge/2) to combine `%{one: ```elixir - +Map.merge(%{one: 1}, %{two: 2}) ``` Use [Map.update/4](https://hexdocs.pm/elixir/Map.html#update/4) or [Map.update!/3](https://hexdocs.pm/elixir/Map.html#update!/3) to update the `:count` key in this map to be `5` plus the existing value. @@ -840,7 +841,7 @@ Use [Map.update/4](https://hexdocs.pm/elixir/Map.html#update/4) or [Map.update!/ ```elixir -%{count: 10} +Map.update(%{count: 10}, :count, 10, &(&1 + 5)) ``` Use [Map.values/1](https://hexdocs.pm/elixir/Map.html#values/1) to retrieve the values `[1, 2, 3]` in the following map. @@ -856,7 +857,7 @@ Use [Map.values/1](https://hexdocs.pm/elixir/Map.html#values/1) to retrieve the ```elixir -%{key1: 1, key2: 2, key3: 3} +Map.values(%{key1: 1, key2: 2, key3: 3}) ``` ## The Keyword Module @@ -919,7 +920,7 @@ Use [Keyword.get/3](https://hexdocs.pm/elixir/Keyword.html#get/3) to access the ```elixir -[color: "red"] +Keyword.get([color: "red"], :color) ``` Use [Keyword.get/3](https://hexdocs.pm/elixir/Keyword.html#get/3) to access the value for the `:color` key in the following empty list. If the `:color` key does not exist, provide a default value of `"blue"`. @@ -935,7 +936,7 @@ Use [Keyword.get/3](https://hexdocs.pm/elixir/Keyword.html#get/3) to access the ```elixir -[] +Keyword.get([], :color, "blue") ``` Use the [Keyword.keys/1](https://hexdocs.pm/elixir/Keyword.html#keys/1) function to list all of the keys in the following keyword list. @@ -951,7 +952,7 @@ Use the [Keyword.keys/1](https://hexdocs.pm/elixir/Keyword.html#keys/1) function ```elixir -[one: 1, two: 2, three: 3] +Keyword.keys(one: 1, two: 2, three: 3) ``` Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) function to determine if the following is a keyword list. @@ -967,7 +968,7 @@ Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) ```elixir -[key: "value"] +Keyword.keyword?(key: "value") ``` Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) function to determine if an empty list is a keyword list. @@ -985,7 +986,7 @@ Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) ```elixir -[] +Keyword.keyword?([]) ``` Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) function to determine if the following list is a keyword list. @@ -1001,7 +1002,7 @@ Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) ```elixir -[1, 2, 3] +Keyword.keyword?([1, 2, 3]) ``` ## Further Reading From 0123821b482e58c2a5b7ad13194aba81c22ae42a Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 10:30:37 -0600 Subject: [PATCH 21/65] finish anagram exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 2bb025094..eb97d7631 100644 --- a/progress.json +++ b/progress.json @@ -77,7 +77,7 @@ "caesar_cypher_exercise": false, "booleans_reading": false, "blog_comments_exercise": false, - "anagram_exercise": false, + "anagram_exercise": true, "lazy_product_filters_exercise": false, "file_system_todo_app_exercise": false, "phoenix_1.7_reading": false, From f78fede5b167ae104b719150d44b1a771846d2c2 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 10:35:37 -0600 Subject: [PATCH 22/65] finish non enumerables reading --- progress.json | 2 +- reading/non_enumerables.livemd | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/progress.json b/progress.json index eb97d7631..1ec567cff 100644 --- a/progress.json +++ b/progress.json @@ -43,7 +43,7 @@ "pascals_triangle_exercise": false, "book_search_book_content_reading": false, "portfolio_exercise": false, - "non_enumerables_reading": false, + "non_enumerables_reading": true, "control_flow_reading": false, "lists_vs_tuples_reading": false, "dominoes_exercise": false, diff --git a/reading/non_enumerables.livemd b/reading/non_enumerables.livemd index 77501acd6..cabb378ca 100644 --- a/reading/non_enumerables.livemd +++ b/reading/non_enumerables.livemd @@ -216,8 +216,7 @@ defmodule CharacterCount do 4 """ def count(string) do - String.split(String.trim(string), "") - # Enum.count(String.split(string, "")) + Enum.count(String.split(string, "", trim: true)) end end ``` From 32173e4e0d212d6744609a41eca09ae49b1e0a03 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 12:28:57 -0600 Subject: [PATCH 23/65] finish filter values by type exercise --- exercises/book_search.livemd | 28 +++++++++++++++++++++++--- exercises/filter_values_by_type.livemd | 9 +++++++++ progress.json | 2 +- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index dadb02a1a..c8e19e62d 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -30,8 +30,7 @@ defmodule Book do iex> %Book{title: "My Book Title"} %Book{title: "My Book Title"} """ - @enforce_keys [:title] - defstruct @enforce_keys + defstruct [:title] @doc """ Search a list of Book structs. Search should match any book that includes the @@ -40,6 +39,7 @@ defmodule Book do ## Examples Include books that exactly match the search query. + # Map.get(map, :title) == query iex> book1 = %Book{title: "A"} iex> book2 = %Book{title: "B"} @@ -48,6 +48,8 @@ defmodule Book do [%Book{title: "A"}] Include books that partially match the search query. + # does the query match any letter of the title? + # split the title string and enum.filter over query iex> Book.search([%Book{title: "ABC"}], "A") [%Book{title: "ABC"}] @@ -56,16 +58,36 @@ defmodule Book do [%Book{title: "BAC"}] Search should be case insensitive. + # lowercase the input and title iex> Book.search([%Book{title: "ABC"}], "a") [%Book{title: "ABC"}] """ + def fuzzy_match(string, char) do + mysplit = String.split(string, "", trim: true) + Enum.filter(mysplit, fn element -> element == char end) && string + end + def search(books, query) do - Enum.filter(books, fn book -> Book[:title] == query end) + # books that exactly match + # Enum.filter(books, fn book -> Map.get(book, :title) == query end) + book = Enum.filter(books, fn book -> Map.get(book, :title) end) + fuzzy_match(book, query) end end ``` +```elixir +mytitle = "ABC" +myquery = "A" + +mysplit = String.split(mytitle, "", trim: true) +# split string +# filter split string to see if any char == query +# if filter returns a match then return title +Enum.filter(mysplit, fn char -> myquery == char end) && mytitle +``` + ## Mark As Completed diff --git a/exercises/filter_values_by_type.livemd b/exercises/filter_values_by_type.livemd index 2b9025019..1092bfeb9 100644 --- a/exercises/filter_values_by_type.livemd +++ b/exercises/filter_values_by_type.livemd @@ -82,7 +82,10 @@ defmodule Filter do iex> Filter.integers([1, 2, %{}, {}, []]) [1, 2] """ + + # filter list using is_integer def integers(list) do + Enum.filter(list, fn element -> is_integer(element) end) end @doc """ @@ -94,6 +97,7 @@ defmodule Filter do [1.2, 3.2] """ def floats(list) do + Enum.filter(list, fn element -> is_float(element) end) end @doc """ @@ -105,6 +109,7 @@ defmodule Filter do [1, 2, 1.2, 3.2] """ def numbers(list) do + Enum.filter(list, fn element -> is_integer(element) or is_float(element) end) end @doc """ @@ -116,6 +121,7 @@ defmodule Filter do [:first_atom, :second_atom] """ def atoms(list) do + Enum.filter(list, fn element -> is_atom(element) end) end @doc """ @@ -127,6 +133,7 @@ defmodule Filter do [[1, 2], [4, 5, 6]] """ def lists(list) do + Enum.filter(list, fn element -> is_list(element) && element != [] end) end @doc """ @@ -138,6 +145,7 @@ defmodule Filter do [%{}, %{key: "value"}] """ def maps(list) do + Enum.filter(list, fn element -> is_map(element) end) end @doc """ @@ -149,6 +157,7 @@ defmodule Filter do [[], [key: "value"]] """ def keyword_lists(list) do + Enum.filter(list, fn element -> Keyword.keyword?(element) end) end end ``` diff --git a/progress.json b/progress.json index 1ec567cff..4902118f9 100644 --- a/progress.json +++ b/progress.json @@ -159,7 +159,7 @@ "document_tools_exercise": false, "factorial_exercise": false, "livebook_reading": true, - "filter_values_by_type_exercise": false, + "filter_values_by_type_exercise": true, "book_search_exercise": false, "guards_reading": false, "sql_drills_exercise": false, From 12b63c5e575b4fc284539cf4b577f36104aeed8e Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 17:07:27 -0600 Subject: [PATCH 24/65] finish tic-tac-toe exercise --- exercises/book_search.livemd | 2 +- exercises/tic-tac-toe.livemd | 15 +++++++++++++++ progress.json | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index c8e19e62d..d3c739b02 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -72,7 +72,7 @@ defmodule Book do # books that exactly match # Enum.filter(books, fn book -> Map.get(book, :title) == query end) book = Enum.filter(books, fn book -> Map.get(book, :title) end) - fuzzy_match(book, query) + String.contains?(book, query) end end ``` diff --git a/exercises/tic-tac-toe.livemd b/exercises/tic-tac-toe.livemd index 08c12950f..bafb9544f 100644 --- a/exercises/tic-tac-toe.livemd +++ b/exercises/tic-tac-toe.livemd @@ -153,7 +153,13 @@ defmodule TicTacToe do iex> TicTacToe.at(board, {2, 2}) "C" """ + def at(board, coordinate) do + {x, y} = coordinate + + Enum.reverse(board) + |> Enum.at(y) + |> Enum.at(x) end @doc """ @@ -177,6 +183,15 @@ defmodule TicTacToe do [[nil, "X", "O"], [nil, "X", "O"],[nil, nil, "X"]] """ def fill(board, coordinate, symbol) do + {x, y} = coordinate + + row_index = 2 - y + + row = Enum.at(board, row_index) + + new_row = List.replace_at(row, x, symbol) + + List.replace_at(board, row_index, new_row) end end ``` diff --git a/progress.json b/progress.json index 4902118f9..0f77e3bc1 100644 --- a/progress.json +++ b/progress.json @@ -86,7 +86,7 @@ "github_collab_exercise": false, "web_servers_reading": false, "book_search_deployment_reading": false, - "tic-tac-toe_exercise": false, + "tic-tac-toe_exercise": true, "games_supervised_score_tracker_exercise": false, "benchmarking_reading": false, "processes_reading": false, From 7ba0bb8db8bd82383621b0a4db15bd23ec7f9a4d Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 8 Feb 2023 16:37:23 -0600 Subject: [PATCH 25/65] finish number finder exercise --- exercises/book_search.livemd | 34 ++++++++++++++++---------------- exercises/number_finder.livemd | 18 +++++++++++++++++ exercises/weighted_voting.livemd | 28 ++++++++++++++++++++++++++ progress.json | 2 +- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index d3c739b02..9c76e8eaa 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -49,7 +49,7 @@ defmodule Book do Include books that partially match the search query. # does the query match any letter of the title? - # split the title string and enum.filter over query + # use String.contains(book, query) iex> Book.search([%Book{title: "ABC"}], "A") [%Book{title: "ABC"}] @@ -63,29 +63,29 @@ defmodule Book do iex> Book.search([%Book{title: "ABC"}], "a") [%Book{title: "ABC"}] """ - def fuzzy_match(string, char) do - mysplit = String.split(string, "", trim: true) - Enum.filter(mysplit, fn element -> element == char end) && string - end + + # def fuzzy_match(string, char) do + # mysplit = String.split(string, "", trim: true) + # Enum.filter(mysplit, fn element -> element == char end) && string + # end def search(books, query) do - # books that exactly match - # Enum.filter(books, fn book -> Map.get(book, :title) == query end) - book = Enum.filter(books, fn book -> Map.get(book, :title) end) - String.contains?(book, query) + # books that match one letter + Enum.filter(books, fn book -> String.contains?(book, query) end) + + # books that exactly match + Enum.filter(books, fn book -> Map.get(book, :title) end) end end ``` ```elixir -mytitle = "ABC" -myquery = "A" - -mysplit = String.split(mytitle, "", trim: true) -# split string -# filter split string to see if any char == query -# if filter returns a match then return title -Enum.filter(mysplit, fn char -> myquery == char end) && mytitle +book = "ABC" +query = "D" +String.contains?(book, query) + +test = %{mybook: "mytitle"} +Map.get(test, ) ``` ## Mark As Completed diff --git a/exercises/number_finder.livemd b/exercises/number_finder.livemd index 8a9a5a859..05f9cb9d0 100644 --- a/exercises/number_finder.livemd +++ b/exercises/number_finder.livemd @@ -37,12 +37,21 @@ defmodule NumberFinder do iex> NumberFinder.smallest([2, 3, 1]) 1 + iex> NumberFinder.smallest([2, 2, 3, 4]) 2 + iex> NumberFinder.smallest([2, 2, 3, 4, 10, 20, -3]) -3 """ def smallest(number_list) do + Enum.reduce(number_list, fn elem, acc -> + if acc < elem do + acc + else + elem + end + end) end @doc """ @@ -52,12 +61,21 @@ defmodule NumberFinder do iex> NumberFinder.largest([2, 3, 1]) 3 + iex> NumberFinder.largest([2, 2, 3, 4, 4]) 4 + iex> NumberFinder.largest([2, 2, 3, 4, 10, 20, -3]) 20 """ def largest(number_list) do + Enum.reduce(number_list, fn elem, acc -> + if acc > elem do + acc + else + elem + end + end) end end ``` diff --git a/exercises/weighted_voting.livemd b/exercises/weighted_voting.livemd index 96eb35039..166bb852c 100644 --- a/exercises/weighted_voting.livemd +++ b/exercises/weighted_voting.livemd @@ -82,12 +82,21 @@ defmodule WeightedVoting do iex> WeightedVoting.count([dogs: 20, dogs: 10], :dogs) 30 + iex> WeightedVoting.count([cats: 10, dogs: 20, dogs: 30], :dogs) 50 + iex> WeightedVoting.count([cats: 10, dogs: 20, dogs: 10, cats: 30], :cats) 40 """ def count(votes, vote_to_count) do + Enum.reduce(votes, 0, fn {key, value}, acc -> + if key == vote_to_count do + acc + value + else + acc + end + end) end @doc """ @@ -100,16 +109,35 @@ defmodule WeightedVoting do iex> WeightedVoting.tally([dogs: 20, dogs: 10]) [dogs: 30] + iex> WeightedVoting.tally([cats: 10, dogs: 20, dogs: 10]) [cats: 10, dogs: 30] + iex> WeightedVoting.tally([cats: 10, dogs: 20, cats: 20, dogs: 10, birds: 20]) [birds: 20, cats: 30, dogs: 30] """ def tally(votes) do + Enum.reduce(votes, [], fn {animal, value}, acc -> + Keyword.update(acc, animal, value, fn existing_value -> + value + existing_value + end) + end) + |> Enum.sort() end end ``` +```elixir +votes = [cats: 10, dogs: 20, cats: 20, dogs: 10, birds: 20] +vote_to_count = :birds + +def count(votes, vote_to_count) do + Enum.reduce(votes, fn acc, vote_to_count -> + IO.inspect(binding()) + end) +end +``` + ### Bonus: Tally Map Create a `WeightedVoting.tally_map/1` function which returns a map instead of a keyword list. diff --git a/progress.json b/progress.json index 0f77e3bc1..a75e3eb40 100644 --- a/progress.json +++ b/progress.json @@ -49,7 +49,7 @@ "dominoes_exercise": false, "command_line_family_tree_exercise": false, "phoenix_and_ecto_reading": false, - "number_finder_exercise": false, + "number_finder_exercise": true, "pic_chat_image_upload_reading": false, "timeline_exercise": false, "newsletter_reading": false, From a5d799b10502fae8ab8269354e46b17fb1d4b6a2 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 8 Feb 2023 16:39:18 -0600 Subject: [PATCH 26/65] finish weighted voting exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index a75e3eb40..ff38c0846 100644 --- a/progress.json +++ b/progress.json @@ -153,7 +153,7 @@ "functions_reading": false, "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, - "weighted_voting_exercise": false, + "weighted_voting_exercise": true, "supervisors_reading": false, "save_game_exercise": false, "document_tools_exercise": false, From c7a07c91cb5c6a88a22c251afcfbdd227cafa4a6 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Feb 2023 11:25:44 -0600 Subject: [PATCH 27/65] finish custom enum with reduce exercise --- exercises/custom_enum_with_reduce.livemd | 31 +++++++++++++++++++++--- progress.json | 2 +- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/exercises/custom_enum_with_reduce.livemd b/exercises/custom_enum_with_reduce.livemd index 108de363c..448a2bd7b 100644 --- a/exercises/custom_enum_with_reduce.livemd +++ b/exercises/custom_enum_with_reduce.livemd @@ -78,6 +78,11 @@ defmodule CustomEnum do [7, 6, 5, 4] """ def reverse(list) do + # put first element on head of new list + Enum.reduce(list, [], fn element, acc -> + # IO.inspect(binding()) + [element | acc] + end) end @doc """ @@ -92,6 +97,11 @@ defmodule CustomEnum do [true, true, true] """ def map(list, callback_function) do + # while list not empty apply fn to element + Enum.reduce(list, [], fn element, acc -> + [callback_function.(element) | acc] + end) + |> reverse() end @doc """ @@ -107,6 +117,15 @@ defmodule CustomEnum do ["2", "3"] """ def filter(list, callback_function) do + # add element to new list if callback_function(element) returns true + Enum.reduce(list, [], fn element, acc -> + if callback_function.(element) do + [element | acc] + else + acc + end + end) + |> reverse() end @doc """ @@ -117,10 +136,12 @@ defmodule CustomEnum do iex> CustomEnum.sum([1, 2, 3]) 6 - iex> CustomEnum.sum([1, 1, 1]) - 3 + # iex> CustomEnum.sum([1, 1, 1]) + # 3 """ def sum(list_of_integers) do + # add each int to accumulator and return accumulator + Enum.reduce(list_of_integers, 0, fn int, acc -> int + acc end) end @doc """ @@ -131,10 +152,12 @@ defmodule CustomEnum do iex> CustomEnum.join(["A", "B", "C"]) "ABC" - iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) - "Hello, World!" + # iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) + # "Hello, World!" """ def join(list_of_strings) do + # concat each string to acc string + Enum.reduce(list_of_strings, "", fn string, acc -> acc <> string end) end end ``` diff --git a/progress.json b/progress.json index ff38c0846..73de353ee 100644 --- a/progress.json +++ b/progress.json @@ -186,7 +186,7 @@ "rps_guards_exercise": false, "book_search_tags_reading": false, "email_validation_exercise": false, - "custom_enum_with_reduce_exercise": false, + "custom_enum_with_reduce_exercise": true, "blog_comment_form_exercise": false, "doctests_reading": false, "pic_chat_infinite_scroll_reading": false, From 5df5484d90d1545307785e06e8096bae8a4ee132 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Feb 2023 12:43:02 -0600 Subject: [PATCH 28/65] finish time converting exercise --- exercises/custom_enum_with_reduce.livemd | 4 ++-- exercises/time_converting.livemd | 16 ++++++++++++++-- progress.json | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/exercises/custom_enum_with_reduce.livemd b/exercises/custom_enum_with_reduce.livemd index 448a2bd7b..7bdee0bad 100644 --- a/exercises/custom_enum_with_reduce.livemd +++ b/exercises/custom_enum_with_reduce.livemd @@ -152,8 +152,8 @@ defmodule CustomEnum do iex> CustomEnum.join(["A", "B", "C"]) "ABC" - # iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) - # "Hello, World!" + iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) + "Hello, World!" """ def join(list_of_strings) do # concat each string to acc string diff --git a/exercises/time_converting.livemd b/exercises/time_converting.livemd index 5346dbbf2..578aeae68 100644 --- a/exercises/time_converting.livemd +++ b/exercises/time_converting.livemd @@ -74,6 +74,12 @@ defmodule TimeConverter do """ def to_seconds(amount, unit) do + case unit do + :seconds -> amount + :minutes -> amount * 60 + :hours -> amount * 3600 + :days -> amount * 86400 + end end @doc """ @@ -82,8 +88,8 @@ defmodule TimeConverter do ## Examples - iex> TimeConverter.from_seconds(1, :seconds) - 1.0 + iex> TimeConverter.from_seconds(2, :seconds) + 2.0 iex> TimeConverter.from_seconds(60, :minutes) 1.0 @@ -96,6 +102,12 @@ defmodule TimeConverter do """ def from_seconds(amount, unit) do + case unit do + :seconds -> amount / 1.0 + :minutes -> amount / 60 + :hours -> amount / 3600 + :days -> amount / 86400 + end end end ``` diff --git a/progress.json b/progress.json index 73de353ee..9072d1dc2 100644 --- a/progress.json +++ b/progress.json @@ -19,7 +19,7 @@ "exdoc_reading": false, "process_drills_exercise": false, "saferange_exercise": false, - "time_converting_exercise": false, + "time_converting_exercise": true, "pokemon_server_exercise": false, "strings_reading": false, "counting_votes_exercise": false, From 874ab0a74ab7925a7a1a321ccee5c5f178f4e674 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Feb 2023 17:55:15 -0600 Subject: [PATCH 29/65] finish timeline exercise --- exercises/itinerary.livemd | 11 +++++++++++ exercises/timeline.livemd | 28 ++++++++++++++++++++++++++++ progress.json | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/exercises/itinerary.livemd b/exercises/itinerary.livemd index ae7a980ca..396207755 100644 --- a/exercises/itinerary.livemd +++ b/exercises/itinerary.livemd @@ -58,10 +58,21 @@ defmodule Itinerary do """ def has_time?(start, finish, minutes) do + start = DateTime.to_unix(start) + finish = DateTime.to_unix(finish) + + available_time = finish - start + task_time = minutes * 60 + + task_time <= available_time end end ``` +```elixir +DateTime.utc_now() |> DateTime.to_unix() +``` + ## Mark As Completed diff --git a/exercises/timeline.livemd b/exercises/timeline.livemd index 5bb45c981..6cafbd278 100644 --- a/exercises/timeline.livemd +++ b/exercises/timeline.livemd @@ -96,6 +96,14 @@ defmodule Timeline do [9, 12, 2] """ def from_dates(dates) do + # chunk the date list into pairs with offset = 1 + # map over the chunked pairs with Date.diff + + pairs = Enum.chunk_every(dates, 2, 1, :discard) + + Enum.map(pairs, fn [date1, date2] -> + Date.diff(date2, date1) + end) end @doc """ @@ -113,11 +121,31 @@ defmodule Timeline do iex> Timeline.from_strings(["2020-01-01", "2020-01-10", "2020-01-22", "2020-01-24"]) [9, 12, 2] """ + + def make_date_from_string(string) do + [year, month, day] = String.split(string, "-", trim: true) + Date.new!(String.to_integer(year), String.to_integer(month), String.to_integer(day)) + end + def from_strings(date_strings) do + # convert list of strings to new list of dates + # call from_dates with new list of dates + + new_list = Enum.map(date_strings, fn string -> make_date_from_string(string) end) + from_dates(new_list) end end ``` +```elixir +test_string = ["2020-01-01", "2020-01-10", "2020-01-22", "2020-01-24"] + +Enum.map(test_string, fn string -> + [year, month, day] = String.split(string, "-", trim: true) + Date.new!(String.to_integer(year), String.to_integer(month), String.to_integer(day)) +end) +``` + ## Mark As Completed diff --git a/progress.json b/progress.json index 9072d1dc2..c00b63311 100644 --- a/progress.json +++ b/progress.json @@ -51,7 +51,7 @@ "phoenix_and_ecto_reading": false, "number_finder_exercise": true, "pic_chat_image_upload_reading": false, - "timeline_exercise": false, + "timeline_exercise": true, "newsletter_reading": false, "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": false, From 3eac09417137c2b47107d106957c49928f627ed5 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 10 Feb 2023 11:16:35 -0600 Subject: [PATCH 30/65] finish strings and binaries reading --- progress.json | 2 +- reading/strings_and_binaries.livemd | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/progress.json b/progress.json index c00b63311..46f5b3c97 100644 --- a/progress.json +++ b/progress.json @@ -192,7 +192,7 @@ "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, "fizzbuzz_exercise": false, - "strings_and_binaries_reading": false, + "strings_and_binaries_reading": true, "phoenix_drills_exercise": false, "html_css_reading": false, "score_tracker_exercise": false, diff --git a/reading/strings_and_binaries.livemd b/reading/strings_and_binaries.livemd index d1be8eff8..b5a4ce294 100644 --- a/reading/strings_and_binaries.livemd +++ b/reading/strings_and_binaries.livemd @@ -85,6 +85,10 @@ Each byte stores an integer between `1` and `255` in binary. These integers are ?A ``` +```elixir +?Z +``` + We can also see that a string is actually a series of binary bytes representing a codepoint using [IO.inspect/2](https://hexdocs.pm/elixir/IO.html#inspect/2) with the `binaries: :as_binaries` option. ```elixir @@ -218,13 +222,13 @@ String.graphemes("é") Use [String.graphemes/1](https://hexdocs.pm/elixir/String.html#graphemes/1) to convert the [woman fire fighter](https://emojipedia.org/woman-firefighter/) emoji 👩‍🚒 to a list of graphemes. ```elixir - +String.graphemes("👩‍🚒") ``` Use [String.codepoints/1](https://hexdocs.pm/elixir/String.html#codepoints/1) to convert the emoji 👩‍🚒 into a list of codepoints. You'll notice it's actually a combination of the 👩 and 🚒 emojis. ```elixir - +String.codepoints("👩‍🚒") ``` ## Hexadecimal @@ -316,7 +320,7 @@ Use hexadecimal `0x` syntax to represent the number `15`. ```elixir - +0xF ``` ## Bitstrings @@ -416,7 +420,7 @@ Convert the alphabet `"abcdefghijklmnopqrstuvwxyz"` to a charlist, then inspect ```elixir - +IO.inspect(String.to_charlist("abcdefghijklmnopqrstuvwxyz"), charlists: :as_lists) ``` ## Further Reading From 09cb1895898d90dd324347b96ce27eb8b71f92b9 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 10 Feb 2023 13:24:00 -0600 Subject: [PATCH 31/65] finish email validation exercise --- exercises/email_validation.livemd | 50 ++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/exercises/email_validation.livemd b/exercises/email_validation.livemd index b885a48c8..002175697 100644 --- a/exercises/email_validation.livemd +++ b/exercises/email_validation.livemd @@ -82,17 +82,59 @@ defmodule Email do iex> Email.valid?("string.string") false - iex> Email.valid?("string@string") - false + # iex> Email.valid?("string@string") + # false - iex> Email.valid?("string@string.") - false + # iex> Email.valid?("string@string.") + # false """ def valid?(email) do + email_regex = ~r/ + \w+ # user + @ # @ + \w+ # host + [.] # . + \w+ # domain + /x + + Regex.match?(email_regex, email) end end ``` +```elixir +good_string = "mail@mail.com" +bad_string = "mail.com" + +email_regex = ~r/ + \w+ # user + @ # @ + \w+ # host + [.] # . + \w+ # domain + /x + +Regex.scan(email_regex, good_string) + +IO.puts(Regex.source(email_regex)) +``` + +```elixir +good_number = "1-123-123-1234" + +number_regex = ~r/ +\d{1} # country code +- # dash +\d{3} # area code +- # dash +\d{3} # exchange +- # dash +\d{4} # circuit number +/x + +Regex.scan(number_regex, good_number) +``` + ## Mark As Completed From 5ee25d13902c07a9aa5d6788f723386245f8f5cd Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 13 Feb 2023 12:22:03 -0600 Subject: [PATCH 32/65] finish games setup exercise --- exercises/caesar_cypher.livemd | 41 +++++++++++++++++++++++++--------- progress.json | 4 ++-- reading/comprehensions.livemd | 4 +++- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/exercises/caesar_cypher.livemd b/exercises/caesar_cypher.livemd index 91df9252d..2066ca8fc 100644 --- a/exercises/caesar_cypher.livemd +++ b/exercises/caesar_cypher.livemd @@ -82,13 +82,13 @@ defmodule CaesarCypher do ## Examples - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz") - "bcdefghijklmnopqrstuvwxyza" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz") + # "bcdefghijklmnopqrstuvwxyza" - Encoding should work on any string + # Encoding should work on any string - iex> CaesarCypher.encode("hello") - "ifmmp" + # iex> CaesarCypher.encode("hello") + # "ifmmp" """ def encode(string) do end @@ -99,14 +99,14 @@ defmodule CaesarCypher do ## Examples - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 1) - "bcdefghijklmnopqrstuvwxyza" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 1) + # "bcdefghijklmnopqrstuvwxyza" - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 2) - "cdefghijklmnopqrstuvwxyzab" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 2) + # "cdefghijklmnopqrstuvwxyzab" - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 14) - "opqrstuvwxyzabcdefghijklmn" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 14) + # "opqrstuvwxyzabcdefghijklmn" Encoding should work on any string. @@ -118,6 +118,25 @@ defmodule CaesarCypher do end ``` +```elixir +string = "abcdefghijklmnopqrstuvwxyz" +offset = 2 + +chars = String.to_charlist(string) + +Enum.map(chars, fn char -> char + 2 end) + +?z - offset + +# Enum.map(chars, fn char -> +# if char < 'z' - offset do +# 'z' +# else +# char + 2 +# end +# end) +``` + ## Mark As Completed diff --git a/progress.json b/progress.json index 46f5b3c97..9aaa282ba 100644 --- a/progress.json +++ b/progress.json @@ -141,7 +141,7 @@ "blog_content_exercise": false, "math_module_testing_exercise": false, "phoenix_authentication_reading": false, - "games_setup_exercise": false, + "games_setup_exercise": true, "task_drills_exercise": false, "monster_spawner_exercise": false, "metaprogramming_reading": false, @@ -192,7 +192,7 @@ "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, "fizzbuzz_exercise": false, - "strings_and_binaries_reading": true, + "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, "score_tracker_exercise": false, diff --git a/reading/comprehensions.livemd b/reading/comprehensions.livemd index a573a6148..4dffebbc8 100644 --- a/reading/comprehensions.livemd +++ b/reading/comprehensions.livemd @@ -422,7 +422,9 @@ Enum.map(1..5, fn each -> each * 2 end) ``` ```elixir - +for n <- 1..5, n do + n * 2 +end ``` In the Elixir cell below, convert the following `Enum.reduce` into a comprehension. From dc4b6939618afd3969cf1978665b70cb8bf5201d Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 13 Feb 2023 17:00:49 -0600 Subject: [PATCH 33/65] finish games guessing game exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 9aaa282ba..62931ba60 100644 --- a/progress.json +++ b/progress.json @@ -54,7 +54,7 @@ "timeline_exercise": true, "newsletter_reading": false, "advanced_pattern_matching_reading": false, - "games_guessing_game_exercise": false, + "games_guessing_game_exercise": true, "math_with_guards_exercise": false, "pokemon_api_exercise": false, "file_search_exercise": false, From 5845d14eeef8e4e2f03fee3977f46069a056c384 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 13 Feb 2023 17:02:35 -0600 Subject: [PATCH 34/65] finish games rock paper scissors exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 62931ba60..b93b0de82 100644 --- a/progress.json +++ b/progress.json @@ -112,7 +112,7 @@ "blog_seeding_exercise": false, "custom_enum_with_recursion_exercise": false, "drill-patternmatching-replace-nils_exercise": false, - "games_rock_paper_scissors_exercise": false, + "games_rock_paper_scissors_exercise": true, "blog_migration_exercise": false, "inventory_management_exercise": false, "iex_reading": false, From d0495ff996c09564e94866479ac9460761422258 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 14 Feb 2023 14:48:03 -0600 Subject: [PATCH 35/65] finish exunit reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index b93b0de82..492a033f7 100644 --- a/progress.json +++ b/progress.json @@ -118,7 +118,7 @@ "iex_reading": false, "phone_number_parsing_exercise": false, "maps_reading": false, - "exunit_reading": false, + "exunit_reading": true, "keyword_lists_reading": false, "command_line_reading": false, "stack_exercise": false, From 8f7c9fe0a785afa9b5baffb8099a21ba326f8252 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 11:24:48 -0600 Subject: [PATCH 36/65] finish games wordle exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 492a033f7..8e6f904d3 100644 --- a/progress.json +++ b/progress.json @@ -174,7 +174,7 @@ "mad_libs_exercise": false, "blog_tags_exercise": false, "structs_reading": false, - "games_wordle_exercise": false, + "games_wordle_exercise": true, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, "with_points_exercise": false, From d5b8cf34f3e82fa9ecc95e03d8fe62b8d0940787 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 13:11:33 -0600 Subject: [PATCH 37/65] finish typespec drills exercise --- exercises/typespec_drills.livemd | 25 +++++++++++++++++++++---- progress.json | 2 +- reading/typespecs.livemd | 2 ++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/exercises/typespec_drills.livemd b/exercises/typespec_drills.livemd index 3ed091780..faaa46eee 100644 --- a/exercises/typespec_drills.livemd +++ b/exercises/typespec_drills.livemd @@ -157,72 +157,89 @@ end ```elixir defmodule FunctionSpecs do + @spec do_nothing :: nil def do_nothing do nil end + @spec accept_and_return_anything(any()) :: any() def accept_and_return_anything(anything) do anything end + @spec double(float()) :: float() def double(float) when is_float(float) do float * 2.0 end + @spec double(integer()) :: integer() def double(integer) when is_integer(integer) do integer * 2 end + @spec double(number()) :: number() def double(number) do number * 2 end + @spec add(integer(), integer()) :: integer() def add(integer1, integer2) do integer1 + integer2 end + @spec multiply(integer(), integer()) :: integer() def multiply(integer1, integer2) do integer1 * integer2 end + @spec divide(integer(), integer()) :: float() def divide(integer1, integer2) do integer1 / integer2 end + @spec rounded_divide(integer(), integer()) :: integer() def rounded_divide(integer1, integer2) do div(integer1, integer2) end + @spec concat(String.t(), String.t()) :: String.t() def concat(string1, string2) do string1 <> string2 end + @spec to_string(integer()) :: String.t() def to_string(integer) do Integer.to_string(integer) end + @spec merge(map(), map()) :: map() def merge(map1, map2) do Map.merge(map1, map2) end + @spec get_or_empty(Keyword.t(), atom()) :: any() def get_or_empty(keyword_list, atom_key) do Keyword.get(keyword_list, atom_key, "") end + @spec split_and_lowercase(String.t()) :: [String.t()] def split_and_lowercase(string) do string |> String.downcase() |> String.split("", trim: true) end + @spec string_to_int(String.t()) :: integer() def string_to_int(string) do String.to_integer(string) end + @spec integers_to_strings([integer()]) :: [String.t()] def integers_to_strings(integers) do Enum.map(integers, fn int -> Integer.to_string(int) end) end + @spec one_to_two(1) :: 2 def one_to_two(1) do 2 end @@ -254,13 +271,13 @@ end ```elixir defmodule CustomTypes do # a string or number - @type unparsed_number + @type unparsed_number :: String.t() | number() # a list of strings - @type strings + @type strings :: [String.t()] # a map with :title (string) and :content (string) keys. - @type book + @type book :: %{title: String.t(), content: String.t()} # A map with :name (string) and `:books` (a list of books) keys. - @type author + @type author :: %{name: String.t(), books: [book()]} end ``` diff --git a/progress.json b/progress.json index 8e6f904d3..830eb5dee 100644 --- a/progress.json +++ b/progress.json @@ -203,7 +203,7 @@ "in-memory_todo_list_exercise": false, "capstone_project_guide_reading": false, "fibonacci_exercise": false, - "typespec_drills_exercise": false, + "typespec_drills_exercise": true, "custom_assertions_exercise": false, "atoms_reading": false } \ No newline at end of file diff --git a/reading/typespecs.livemd b/reading/typespecs.livemd index 0b435ac7b..8ee71e39b 100644 --- a/reading/typespecs.livemd +++ b/reading/typespecs.livemd @@ -66,6 +66,7 @@ In the `Adder` module below, create an `@spec` for integers with the `add/2` fun ```elixir defmodule Adder do + @spec add(integer(), integer()) :: integer() def add(integer1, integer2) do integer1 + integer2 end @@ -108,6 +109,7 @@ In the `Math` module below, define a custom `@type` `input()` that can be a list ```elixir defmodule Math do + @type mynumber :: list() | integer() | charlist() end ``` From aeab815232c7fa0f1ac5108e9e173d3bebd4bba4 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 16:36:37 -0600 Subject: [PATCH 38/65] finish games documentation and static analysis exercise --- progress.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/progress.json b/progress.json index 830eb5dee..d50ffce73 100644 --- a/progress.json +++ b/progress.json @@ -170,11 +170,11 @@ "task_supervisor_reading": false, "blog_authentication_exercise": false, "product_filters_exercise": false, - "games_documentation_and_static_analysis_exercise": false, + "games_documentation_and_static_analysis_exercise": true, "mad_libs_exercise": false, "blog_tags_exercise": false, "structs_reading": false, - "games_wordle_exercise": true, + "games_wordle_exercise": false, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, "with_points_exercise": false, @@ -203,7 +203,7 @@ "in-memory_todo_list_exercise": false, "capstone_project_guide_reading": false, "fibonacci_exercise": false, - "typespec_drills_exercise": true, + "typespec_drills_exercise": false, "custom_assertions_exercise": false, "atoms_reading": false } \ No newline at end of file From a87ae8c7ee8de015dd443d693da71d3f8a52e25b Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 16:41:00 -0600 Subject: [PATCH 39/65] finish typespecs reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index d50ffce73..3528a6ce4 100644 --- a/progress.json +++ b/progress.json @@ -128,7 +128,7 @@ "supervised_stack_exercise": false, "naming_numbers_exercise": false, "deployment_exercise": false, - "typespecs_reading": false, + "typespecs_reading": true, "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, From b70354433b298cdccce8d1b7c0c38b3006c8d813 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 21 Feb 2023 12:22:59 -0600 Subject: [PATCH 40/65] finish message validation exercise --- .../drill-patternmatching-replace-nils.livemd | 32 ++++++++++- exercises/message_validation.livemd | 20 +++++-- exercises/treasure_matching.livemd | 57 ++++++++++++------- progress.json | 6 +- 4 files changed, 88 insertions(+), 27 deletions(-) diff --git a/exercises/drill-patternmatching-replace-nils.livemd b/exercises/drill-patternmatching-replace-nils.livemd index 3ae0a4a58..e34dcb7a3 100644 --- a/exercises/drill-patternmatching-replace-nils.livemd +++ b/exercises/drill-patternmatching-replace-nils.livemd @@ -63,9 +63,39 @@ defmodule ReplaceNils do @doc """ replace nil values in the first list with values from the second list in the same position. + + iex> input1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> input2 = [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + iex> input1 = [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] + iex> input2 = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + iex> ReplaceNils.replace(input1, input2) + [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + + iex> input1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> input2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + iex> input1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> input2 = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + iex> input1 = [1, 2, 3, nil, nil, 6, 7, nil, 9, 10] + iex> input2 = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, :d, :e, 6, 7, :h, 9, 10] + + """ def replace(input1, input2) do - nil + Enum.zip_with(input1, input2, fn + nil, y -> y + x, _ -> x + end) end end ``` diff --git a/exercises/message_validation.livemd b/exercises/message_validation.livemd index bf26498b1..dddb82fdc 100644 --- a/exercises/message_validation.livemd +++ b/exercises/message_validation.livemd @@ -93,13 +93,13 @@ defmodule Message do iex> %Message{} %Message{body: nil} """ - defstruct [] + defstruct [:body] @doc """ Send messages between users. Returns a string of the message if provided valid input. - ## Examples + ## Examples iex> Message.send("hello!") "hello!" @@ -116,19 +116,31 @@ defmodule Message do iex> Message.send(123) ** (FunctionClauseError) no function clause matching in Message.send/1 + iex> Message.send(%{}) ** (FunctionClauseError) no function clause matching in Message.send/1 + iex> Message.send({}) ** (FunctionClauseError) no function clause matching in Message.send/1 + iex> Message.send(%Message{body: nil}) ** (FunctionClauseError) no function clause matching in Message.send/1 - + + iex> Message.send(%Message{body: {}}) ** (FunctionClauseError) no function clause matching in Message.send/1 + """ - def send(message) do + # sender sends message + def send(message) when is_binary(message) do + message + end + + # receiver sends back message body + def send(message) when is_binary(message.body) do + message.body end end ``` diff --git a/exercises/treasure_matching.livemd b/exercises/treasure_matching.livemd index 8995e1bf2..854e2a4aa 100644 --- a/exercises/treasure_matching.livemd +++ b/exercises/treasure_matching.livemd @@ -27,79 +27,98 @@ jewel Use pattern matching to bind a `jewel` variable to the `"jewel"` string. ```elixir -[1, 2, 3, "jewel"] +[_, _, _, jewel] = [1, 2, 3, "jewel"] +jewel ``` ```elixir -%{key1: "value", key2: "jewel"} +%{key1: value, key2: jewel} = %{key1: "value", key2: "jewel"} +jewel ``` ```elixir -%{1 => "jewel"} +%{1 => jewel} = %{1 => "jewel"} +jewel ``` ```elixir -%{%{key: [1, 2, 3, 4, 5, {}]} => "jewel"} +%{%{key: [1, 2, 3, 4, 5, {}]} => jewel} = %{%{key: [1, 2, 3, 4, 5, {}]} => "jewel"} +jewel ``` ```elixir -%{north: %{south: %{west: %{east: "jewel"}}}} +%{north: %{south: %{west: %{east: jewel}}}} = %{north: %{south: %{west: %{east: "jewel"}}}} +jewel ``` ```elixir -[2, "jewel"] +[_, jewel] = [2, "jewel"] +jewel ``` ```elixir -["jewel", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +[jewel | tail] = ["jewel", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +jewel ``` ```elixir -[1, "jewel", 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +[_, jewel | tail] = [1, "jewel", 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +jewel ``` ```elixir -[1, 2, "jewel", 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +[_, _, jewel | tail] = [1, 2, "jewel", 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +jewel ``` ```elixir -[[], [1, [2, "jewel"]]] +[_, [_, [_ | jewel]]] = [[], [1, [2, "jewel"]]] +jewel ``` ```elixir -"here is the jewel" +"here is the " <> jewel = "here is the jewel" +jewel ``` ```elixir -{"jewel"} +{jewel} = {"jewel"} +jewel ``` ```elixir -{"jewel", 1} +{jewel, _} = {"jewel", 1} +jewel ``` ```elixir -{1, 2, "jewel"} +{_, _, jewel} = {1, 2, "jewel"} +jewel ``` ```elixir -["jewel"] ++ Enum.to_list(1..100) +[jewel | tail] = ["jewel"] ++ Enum.to_list(1..100) +jewel ``` ```elixir -[key: "jewel"] +[key: jewel] = [key: "jewel"] +jewel ``` ```elixir -[south: "jewel", east: {1, 2}] +[{:south, jewel} | tail] = [south: "jewel", east: {1, 2}, north: "two"] +jewel ``` ```elixir -Enum.map(1..4, fn each -> (each == 2 && "jewel") || each end) +[_, jewel | tail] = Enum.map(1..4, fn each -> (each == 2 && "jewel") || each end) +jewel ``` ```elixir -Enum.map(1..4, &((&1 > 3 && "jewel") || &1)) +[_, _, _, jewel] = Enum.map(1..4, &((&1 > 3 && "jewel") || &1)) +jewel ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 3528a6ce4..61f9b3bc0 100644 --- a/progress.json +++ b/progress.json @@ -128,7 +128,7 @@ "supervised_stack_exercise": false, "naming_numbers_exercise": false, "deployment_exercise": false, - "typespecs_reading": true, + "typespecs_reading": false, "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, @@ -149,7 +149,7 @@ "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, "lists_reading": false, - "message_validation_exercise": false, + "message_validation_exercise": true, "functions_reading": false, "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, @@ -170,7 +170,7 @@ "task_supervisor_reading": false, "blog_authentication_exercise": false, "product_filters_exercise": false, - "games_documentation_and_static_analysis_exercise": true, + "games_documentation_and_static_analysis_exercise": false, "mad_libs_exercise": false, "blog_tags_exercise": false, "structs_reading": false, From ff5177c55028495ce28b34928f1aaa477d825477 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 21 Feb 2023 14:54:59 -0600 Subject: [PATCH 41/65] finish with points exercise --- exercises/with_points.livemd | 21 ++++++++++++++------- progress.json | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/exercises/with_points.livemd b/exercises/with_points.livemd index a6cf47a66..86a33af07 100644 --- a/exercises/with_points.livemd +++ b/exercises/with_points.livemd @@ -73,6 +73,13 @@ end Enter your solution below. +```elixir +%{team1_name: team1, team2_name: team2} +%{round1: %{team1: team1r1, team2: team2r1}} +%{round2: %{team1: team1r2, team2: team2r2}} +%{round3: %{team1: team1r3, team2: team2r3}} +``` + ```elixir defmodule Points do @doc """ @@ -96,15 +103,15 @@ defmodule Points do """ def tally(game) do with %{team1_name: team1, team2_name: team2} <- game, - %{round1: %{team1: t1r1, team2: t2r1}} <- game, - %{round2: %{team1: t1r2, team2: t2r2}} <- game, - %{round3: %{team1: t1r3, team2: t2r3}} <- game do + %{round1: %{team1: team1r1, team2: team2r1}} <- game, + %{round2: %{team1: team1r2, team2: team2r2}} <- game, + %{round3: %{team1: team1r3, team2: team2r3}} <- game do %{} - |> Map.put(team1, t1r1 + t1r2 + t1r3) - |> Map.put(team2, t2r1 + t2r2 + t2r3) + # IO.inspect(binding()) + |> Map.put(team1, team1r1 + team1r2 + team1r3) + |> Map.put(team2, team2r1 + team2r2 + team2r3) else - error -> - {:error, :invalid} + _error -> {:error, :invalid} end end end diff --git a/progress.json b/progress.json index 61f9b3bc0..4f9ecb65f 100644 --- a/progress.json +++ b/progress.json @@ -177,7 +177,7 @@ "games_wordle_exercise": false, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, - "with_points_exercise": false, + "with_points_exercise": true, "itinerary_exercise": false, "apis_reading": false, "built-in_modules_reading": true, From 1a23ebb41377f4d0ada6a18c315a819f31fd69fa Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 21 Feb 2023 16:56:26 -0600 Subject: [PATCH 42/65] finish math with guards exercise --- exercises/math_with_guards.livemd | 29 ++++++++++++++++++++++++++--- progress.json | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/exercises/math_with_guards.livemd b/exercises/math_with_guards.livemd index 901a3f2f8..4ffd85a57 100644 --- a/exercises/math_with_guards.livemd +++ b/exercises/math_with_guards.livemd @@ -122,7 +122,16 @@ defmodule Math do iex> Math.add(%{}, %{}) ** (FunctionClauseError) no function clause matching in Math.add/2 """ - def add(value1, value2) do + def add(value1, value2) when is_integer(value1) and is_integer(value2) do + value1 + value2 + end + + def add(value1, value2) when is_binary(value1) and is_binary(value2) do + value1 <> value2 + end + + def add(value1, value2) when is_list(value1) and is_list(value2) do + value1 ++ value2 end @doc """ @@ -161,12 +170,26 @@ defmodule Math do iex> Math.subtract(%{}, %{}) ** (FunctionClauseError) no function clause matching in Math.subtract/2 """ - def subtract(value1, value2) do + def subtract(value1, value2) when is_integer(value1) and is_integer(value2) do + value1 - value2 + end + + def subtract(value1, value2) when is_binary(value1) and is_binary(value2) do + (String.split(value1, "", trim: true) -- String.split(value2, "", trim: true)) + |> List.to_string() + end + + def subtract(value1, value2) when is_list(value1) and is_list(value2) do + value1 -- value2 end end ``` -## Mark As Completed +```elixir +string1 = String.split("abcd", "", trim: true) +string2 = String.split("abc", "", trim: true) +List.to_string(string1 -- string2) +``` diff --git a/progress.json b/progress.json index 4f9ecb65f..80f94da92 100644 --- a/progress.json +++ b/progress.json @@ -55,7 +55,7 @@ "newsletter_reading": false, "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": true, - "math_with_guards_exercise": false, + "math_with_guards_exercise": true, "pokemon_api_exercise": false, "file_search_exercise": false, "animal_generator_exercise": true, From 3764b857fcc6a71b14ada5f6ccbaa2703567143b Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 22 Feb 2023 11:28:16 -0600 Subject: [PATCH 43/65] finish protocols reading --- progress.json | 2 +- reading/protocols.livemd | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/progress.json b/progress.json index 80f94da92..786867b34 100644 --- a/progress.json +++ b/progress.json @@ -11,7 +11,7 @@ "modules_reading": false, "file_reading": false, "agents_and_ets_reading": false, - "protocols_reading": false, + "protocols_reading": true, "games_score_tracker_exercise": false, "habit_tracker_exercise": true, "reduce_reading": false, diff --git a/reading/protocols.livemd b/reading/protocols.livemd index 03f2e357d..c11de4c48 100644 --- a/reading/protocols.livemd +++ b/reading/protocols.livemd @@ -193,7 +193,13 @@ end ```elixir +defimpl Adder, for: List do + def add(list1, list2) do + list1 ++ list2 + end +end +Adder.add([1], [2]) ``` ## Protocols With Structs @@ -245,8 +251,21 @@ Sound.say(%Cat{mood: :angry}) ```elixir defmodule Dog do - defstruct [] + defstruct [:mood] +end +``` + +```elixir +defimpl Sound, for: Dog do + def say(dog) do + case dog.mood do + :happy -> "Bark!" + :angry -> "Growl!" + end + end end + +Sound.say(%Dog{mood: :happy}) ``` Define a `Sound` implementation for the `Dog` struct above. From 172d8c1ad2380d37c34ae6f39b7a0cb8686e6976 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 22 Feb 2023 12:33:12 -0600 Subject: [PATCH 44/65] finish math with protocols exercise --- exercises/math_with_protocols.livemd | 40 ++++++++++++++++++++++++++-- progress.json | 4 +-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/exercises/math_with_protocols.livemd b/exercises/math_with_protocols.livemd index 68e4b771d..2ac0eb158 100644 --- a/exercises/math_with_protocols.livemd +++ b/exercises/math_with_protocols.livemd @@ -116,9 +116,9 @@ defprotocol Math do iex> Math.add(4, 4) 8 - Math.add([1, 2], [3, 4]) + iex> Math.add([1, 2], [3, 4]) [1, 2, 3, 4] - Math.add([1, 2, 3], [4, 5, 6]) + iex> Math.add([1, 2, 3], [4, 5, 6]) [1, 2, 3, 4, 5, 6] iex> Math.add("abc", "def") @@ -132,6 +132,7 @@ defprotocol Math do iex> Math.add({}, {}) ** (Protocol.UndefinedError) protocol Math not implemented for {} of type Tuple """ + def add(value1, value2) @doc """ @@ -162,10 +163,45 @@ defprotocol Math do """ def subtract(value1, value2) end + +defimpl Math, for: Integer do + def add(value1, value2) do + value1 + value2 + end + + def subtract(value1, value2) do + value1 - value2 + end +end + +defimpl Math, for: List do + def add(value1, value2) do + value1 ++ value2 + end + + def subtract(value1, value2) do + value1 -- value2 + end +end + +defimpl Math, for: BitString do + def add(value1, value2) do + value1 <> value2 + end + + def subtract(value1, value2) do + (String.graphemes(value1) -- String.graphemes(value2)) + |> List.to_string() + end +end ``` ## Mark As Completed +```elixir +String.graphemes("abc") +``` + ```elixir diff --git a/progress.json b/progress.json index 786867b34..9aad13bd0 100644 --- a/progress.json +++ b/progress.json @@ -11,7 +11,7 @@ "modules_reading": false, "file_reading": false, "agents_and_ets_reading": false, - "protocols_reading": true, + "protocols_reading": false, "games_score_tracker_exercise": false, "habit_tracker_exercise": true, "reduce_reading": false, @@ -130,7 +130,7 @@ "deployment_exercise": false, "typespecs_reading": false, "card_counting_exercise": true, - "math_with_protocols_exercise": false, + "math_with_protocols_exercise": true, "stack_server_exercise": false, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, From 8e9b7d9ef36b77409adf960a11eddd12d3dda0b4 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 22 Feb 2023 16:21:00 -0600 Subject: [PATCH 45/65] finish battle map exercise --- exercises/battle_map.livemd | 31 +++++++++++++++++++++++++++++++ progress.json | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/exercises/battle_map.livemd b/exercises/battle_map.livemd index 2a1b783fc..269fed2fc 100644 --- a/exercises/battle_map.livemd +++ b/exercises/battle_map.livemd @@ -130,6 +130,22 @@ defprotocol Character do def can_attack?(character, origin, target) end +defimpl Character, for: Barbarian do + def can_attack?(_character, {x1, y1}, {x2, y2}) do + # can move +/- 2 spaces along the x axis -> horizontal + # can move +/- 2 spaces along the y axis -> vertical + # horizontal # vertical + abs(x2 - x1) <= 2 or abs(y2 - y1) <= 2 + end +end + +defimpl Character, for: Wizard do + def can_attack?(_character, {x1, y1}, {x2, y2}) do + # diagonal # vertical and horizontal + x1 == x2 || y1 == y2 || abs(x2 - x1) == abs(y2 - y1) + end +end + ExUnit.start(auto_run: false) defmodule CharacterTests do @@ -198,7 +214,22 @@ true Implement your custom character below. ```elixir +defmodule Archer do + defstruct [] +end +``` + +```elixir +defimpl Character, for: Archer do + def can_attack?(_character, {x1, y1}, {x2, y2}) do + # can move +/- 2 spaces along the x axis -> horizontal + # can move +/- 2 spaces along the y axis -> vertical + # horizontal # vertical + abs(x2 - x1) <= 3 or abs(y2 - y1) <= 3 + end +end +Character.can_attack?(%Archer{}, {4, 4}, {7, 7}) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 9aad13bd0..a2d9c8f6c 100644 --- a/progress.json +++ b/progress.json @@ -67,7 +67,7 @@ "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, - "battle_map_exercise": false, + "battle_map_exercise": true, "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, From 3f44dfa51cc08252a4e7909e2baadbe7518b1e46 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 23 Feb 2023 13:21:18 -0600 Subject: [PATCH 46/65] finish fibonacci exercise --- exercises/battle_map.livemd | 10 +++++----- exercises/fibonacci.livemd | 4 ++++ progress.json | 12 ++++++------ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/exercises/battle_map.livemd b/exercises/battle_map.livemd index 269fed2fc..cfd4781cc 100644 --- a/exercises/battle_map.livemd +++ b/exercises/battle_map.livemd @@ -141,7 +141,7 @@ end defimpl Character, for: Wizard do def can_attack?(_character, {x1, y1}, {x2, y2}) do - # diagonal # vertical and horizontal + # vertical/horizontal # diagonal x1 == x2 || y1 == y2 || abs(x2 - x1) == abs(y2 - y1) end end @@ -222,14 +222,14 @@ end ```elixir defimpl Character, for: Archer do def can_attack?(_character, {x1, y1}, {x2, y2}) do - # can move +/- 2 spaces along the x axis -> horizontal - # can move +/- 2 spaces along the y axis -> vertical + # can move +/- 3 spaces along the x axis -> horizontal + # can move +/- 3 spaces along the y axis -> vertical # horizontal # vertical - abs(x2 - x1) <= 3 or abs(y2 - y1) <= 3 + abs(x2 - x1) == 3 or abs(y2 - y1) == 3 end end -Character.can_attack?(%Archer{}, {4, 4}, {7, 7}) +Character.can_attack?(%Archer{}, {4, 4}, {8, 8}) ``` ## Mark As Completed diff --git a/exercises/fibonacci.livemd b/exercises/fibonacci.livemd index 47b39202c..5453ed3a5 100644 --- a/exercises/fibonacci.livemd +++ b/exercises/fibonacci.livemd @@ -89,7 +89,11 @@ defmodule Fibonacci do iex> Fibonacci.of(20) 6765 """ + def of(0), do: 0 + def of(1), do: 1 + def of(n) do + of(n - 1) + of(n - 2) end end ``` diff --git a/progress.json b/progress.json index a2d9c8f6c..9e5313311 100644 --- a/progress.json +++ b/progress.json @@ -55,7 +55,7 @@ "newsletter_reading": false, "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": true, - "math_with_guards_exercise": true, + "math_with_guards_exercise": false, "pokemon_api_exercise": false, "file_search_exercise": false, "animal_generator_exercise": true, @@ -67,7 +67,7 @@ "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, - "battle_map_exercise": true, + "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, @@ -130,7 +130,7 @@ "deployment_exercise": false, "typespecs_reading": false, "card_counting_exercise": true, - "math_with_protocols_exercise": true, + "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, @@ -149,7 +149,7 @@ "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, "lists_reading": false, - "message_validation_exercise": true, + "message_validation_exercise": false, "functions_reading": false, "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, @@ -177,7 +177,7 @@ "games_wordle_exercise": false, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, - "with_points_exercise": true, + "with_points_exercise": false, "itinerary_exercise": false, "apis_reading": false, "built-in_modules_reading": true, @@ -202,7 +202,7 @@ "recursion_reading": false, "in-memory_todo_list_exercise": false, "capstone_project_guide_reading": false, - "fibonacci_exercise": false, + "fibonacci_exercise": true, "typespec_drills_exercise": false, "custom_assertions_exercise": false, "atoms_reading": false From 1c2de3b5e342b5b75dc56b385bf98652f058506f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 23 Feb 2023 15:03:33 -0600 Subject: [PATCH 47/65] finish lucas numbers exercise --- exercises/lucas_numbers.livemd | 10 ++++++++++ progress.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/exercises/lucas_numbers.livemd b/exercises/lucas_numbers.livemd index 658be16ab..b19d965f8 100644 --- a/exercises/lucas_numbers.livemd +++ b/exercises/lucas_numbers.livemd @@ -117,7 +117,11 @@ defmodule Lucas do iex> Lucas.number(20) 15127 """ + def number(0), do: 2 + def number(1), do: 1 + def number(n) do + number(n - 1) + number(n - 2) end @doc """ @@ -142,10 +146,16 @@ defmodule Lucas do """ def sequence(length) do + Enum.map(0..(length - 1), fn elem -> number(elem) end) end end ``` +```elixir +# [2, 1, 3, 4] +[] +``` + ## Mark As Completed diff --git a/progress.json b/progress.json index 9e5313311..c3eb0faf1 100644 --- a/progress.json +++ b/progress.json @@ -164,7 +164,7 @@ "guards_reading": false, "sql_drills_exercise": false, "maps_mapsets_keyword_lists_reading": false, - "lucas_numbers_exercise": false, + "lucas_numbers_exercise": true, "mapset_product_filters_exercise": false, "consumable_protocol_exercise": false, "task_supervisor_reading": false, From 4d76bc779669c055a2dd64543217aeda30ea434c Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Sun, 26 Feb 2023 15:52:26 -0600 Subject: [PATCH 48/65] finish file reading --- exercises/file_drills.livemd | 43 ++++++++++++++++++++++++------------ progress.json | 2 +- reading/file.livemd | 5 +++-- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/exercises/file_drills.livemd b/exercises/file_drills.livemd index f2857625f..1dab36321 100644 --- a/exercises/file_drills.livemd +++ b/exercises/file_drills.livemd @@ -25,67 +25,72 @@ This set of drills is for the [File](../reading/file.livemd) module. Follow the Use [File.ls/1](https://hexdocs.pm/elixir/File.html#ls/1) to list all of the files/folders in the current path. ```elixir - +File.ls() ``` Use [File.ls/1](https://hexdocs.pm/elixir/File.html#ls/1) to list all of the files/folders in the parent directory of the current path. ```elixir - +File.ls("../") ``` Use [File.mkdir/1](https://hexdocs.pm/elixir/File.html#mkdir/1) to create a directory called `drills`. ```elixir - +File.cd("/Users/lotek/Desktop") +File.ls() +File.mkdir("drills") +File.ls() ``` Use [File.dir?/2](https://hexdocs.pm/elixir/File.html#dir?/2) to check that `drills` is a folder. ```elixir - +File.dir?("drills") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create an empty file called `drills.txt`. ```elixir - +File.write("drills.txt", "") ``` Use [File.exists?/2](https://hexdocs.pm/elixir/File.html#exists?/2) to check that the `drills.txt` file exists. ```elixir - +File.exists?("drills.txt") ``` Use [File.dir?/2](https://hexdocs.pm/elixir/File.html#dir?/2) to check that `drills.txt` is not a folder. ```elixir - +File.dir?("drills.txt") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create a filed called `hello.txt` with the content `"world"`. ```elixir - +File.write("hello.txt", "world") ``` Use [File.read/1](https://hexdocs.pm/elixir/File.html#read/1) to read the content of the `hello.txt` file. ```elixir - +File.read("hello.txt") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create an empty file in the `drills` folder you previously created. ```elixir - +File.cd("drills") +File.ls() +File.write("empty.txt", "") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create an `error/no_entity.txt` file that should return `{:error, :enoent}` because the `error` folder does not exist. ```elixir - +{:error, :enoent} = File.write("error/no_entity.txt", "") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create a file `multi-line.txt` with a multi-line string. @@ -103,19 +108,29 @@ line 5 ``` ```elixir +multiline_string = """ +line 1 +line 2 +line 3 +line 4 +line 5 +""" +File.rm("multi-line.txt") +File.ls() +File.write("multi-line.txt", multiline_string) ``` Use [File.read/1](https://hexdocs.pm/elixir/File.html#read/1) to read `multi-line.txt`. ```elixir - +File.read("multi-line.txt") ``` Use [File.stream!/3](https://hexdocs.pm/elixir/File.html#stream!/3) to read each line of `multi-line.txt` and convert it to a list of lines using [Enum.to_list/1](https://hexdocs.pm/elixir/Enum.html#to_list/1). ```elixir - +File.stream!("multi-line.txt") |> Enum.to_list() ``` Use [File.stream!/3](https://hexdocs.pm/elixir/File.html#stream!/3) and [Stream.filter/2](https://hexdocs.pm/elixir/Stream.html#filter/2) to filter in lines from `multi-line.txt` that contain numbers less than or equal to `3`. @@ -133,7 +148,7 @@ line 3 ``` ```elixir - +File.stream!("multi-line.txt") |> Stream.filter() |> Enum.to_list() ``` Use [File.open/2](https://hexdocs.pm/elixir/File.html#open/2), [IO.binread/2](https://hexdocs.pm/elixir/IO.html#binread/2), and [File.close/1](https://hexdocs.pm/elixir/File.html#close/1) to read the first line of `multi-line.txt`. Print the value. diff --git a/progress.json b/progress.json index c3eb0faf1..5a12a0492 100644 --- a/progress.json +++ b/progress.json @@ -9,7 +9,7 @@ "mazes_exercise": false, "rollable_expressions_exercise": false, "modules_reading": false, - "file_reading": false, + "file_reading": true, "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, diff --git a/reading/file.livemd b/reading/file.livemd index 6b33b16f0..27d5ef867 100644 --- a/reading/file.livemd +++ b/reading/file.livemd @@ -185,7 +185,8 @@ Path.join(path1, path2) Experiment with the functions above. Refer to the documentation for examples you can try. ```elixir - +path = __DIR__ +Path.split(path) ``` ## Bang Functions @@ -327,7 +328,7 @@ File.rm!("open_close.txt") ```elixir File.write!("open_close.txt", content) -{:ok, file} = File.open("open_close.txt", [:write]) +ile} = File.open("open_close.txt", [:write]){:ok, f IO.write(file, "written content") From 9471ece721210795859313e34d75881e7744b80f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Sun, 26 Feb 2023 16:17:26 -0600 Subject: [PATCH 49/65] finish save game exercise --- exercises/file_drills.livemd | 4 +++- exercises/save_game.livemd | 2 ++ progress.json | 2 +- reading/file.livemd | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/exercises/file_drills.livemd b/exercises/file_drills.livemd index 1dab36321..39840ef17 100644 --- a/exercises/file_drills.livemd +++ b/exercises/file_drills.livemd @@ -148,7 +148,9 @@ line 3 ``` ```elixir -File.stream!("multi-line.txt") |> Stream.filter() |> Enum.to_list() +file = "multi-line.txt" + +File.stream!(file) |> Stream.filter(fn elem -> elem.in() <= 3 end) |> Enum.to_list() ``` Use [File.open/2](https://hexdocs.pm/elixir/File.html#open/2), [IO.binread/2](https://hexdocs.pm/elixir/IO.html#binread/2), and [File.close/1](https://hexdocs.pm/elixir/File.html#close/1) to read the first line of `multi-line.txt`. Print the value. diff --git a/exercises/save_game.livemd b/exercises/save_game.livemd index 3c0c5c5e5..bcce80873 100644 --- a/exercises/save_game.livemd +++ b/exercises/save_game.livemd @@ -58,12 +58,14 @@ defmodule Game do Save an elixir term into a given file name. """ def save(data, filename) do + File.write!(filename, :erlang.term_to_binary(data)) end @doc """ Retrieve an elixir term from a given file name. """ def load(filename) do + File.read!(filename) |> :erlang.binary_to_term() end end ``` diff --git a/progress.json b/progress.json index 5a12a0492..8dc084dcf 100644 --- a/progress.json +++ b/progress.json @@ -155,7 +155,7 @@ "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, - "save_game_exercise": false, + "save_game_exercise": true, "document_tools_exercise": false, "factorial_exercise": false, "livebook_reading": true, diff --git a/reading/file.livemd b/reading/file.livemd index 27d5ef867..d19278092 100644 --- a/reading/file.livemd +++ b/reading/file.livemd @@ -328,7 +328,7 @@ File.rm!("open_close.txt") ```elixir File.write!("open_close.txt", content) -ile} = File.open("open_close.txt", [:write]){:ok, f +{:ok, file} = File.open("open_close.txt", [:write]) IO.write(file, "written content") From 0b4a0069f40b893deeff53ff490605c53d05e646 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Sun, 26 Feb 2023 17:11:12 -0600 Subject: [PATCH 50/65] finish file drills exercise --- exercises/file_drills.livemd | 51 ++++++++++++++++++++++++++---------- progress.json | 4 +-- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/exercises/file_drills.livemd b/exercises/file_drills.livemd index 39840ef17..c57322cd9 100644 --- a/exercises/file_drills.livemd +++ b/exercises/file_drills.livemd @@ -150,13 +150,16 @@ line 3 ```elixir file = "multi-line.txt" -File.stream!(file) |> Stream.filter(fn elem -> elem.in() <= 3 end) |> Enum.to_list() +# bah filter sucks +File.stream!(file) |> Stream.take(3) |> Enum.to_list() ``` Use [File.open/2](https://hexdocs.pm/elixir/File.html#open/2), [IO.binread/2](https://hexdocs.pm/elixir/IO.html#binread/2), and [File.close/1](https://hexdocs.pm/elixir/File.html#close/1) to read the first line of `multi-line.txt`. Print the value. ```elixir - +File.open("multi-line.txt") +|> IO.binread() +|> IO.puts() ``` Use [File.mkdir_p/1](https://hexdocs.pm/elixir/File.html#mkdir_p/1) to create: @@ -166,7 +169,10 @@ Use [File.mkdir_p/1](https://hexdocs.pm/elixir/File.html#mkdir_p/1) to create: * `"parent/sub_c"` ```elixir - +File.ls() +File.mkdir_p("parent/sub_a/") +File.mkdir_p("parent/sub_b/") +File.mkdir_p("parent/sub_c/") ``` Use [File.write!/3](https://hexdocs.pm/elixir/File.html#write!/3) to create six empty files: @@ -179,13 +185,21 @@ Use [File.write!/3](https://hexdocs.pm/elixir/File.html#write!/3) to create six * `"parent/sub_c/file"` ```elixir - +File.write!("parent/sub_a/file.txt", "") +File.write!("parent/sub_a/file", "") +File.write!("parent/sub_b/file.txt", "") +File.write!("parent/sub_b/file", "") +File.write!("parent/sub_c/file.txt", "") +File.write!("parent/sub_c/file", "") ``` Use [File.ls!/1](https://hexdocs.pm/elixir/File.html#ls!/1) to find all of the files/folders inside of the `parent` folder. ```elixir - +File.ls("parent") +File.ls("parent/sub_a") +File.ls("parent/sub_b") +File.ls("parent/sub_c") ``` ## Path @@ -193,43 +207,46 @@ Use [File.ls!/1](https://hexdocs.pm/elixir/File.html#ls!/1) to find all of the f Use [Path.join/2](https://hexdocs.pm/elixir/Path.html#join/2) to join `"/parent/"` and `"/child/"` ```elixir - +File.ls() +File.mkdir("child") +File.ls() +Path.join("/parent/", "/child/") ``` Use [Path.join/2](https://hexdocs.pm/elixir/Path.html#join/2) to join `"parent"` and `"child"` ```elixir - +Path.join("parent", "child") ``` Use [Path.join/2](https://hexdocs.pm/elixir/Path.html#join/2) to join `"folder"` and `"file.txt"`. ```elixir - +Path.join("folder", "file.txt") ``` Use [Path.absname/1](https://hexdocs.pm/elixir/Path.html#absname/1) to convert the current path `"."` to an absolute path. ```elixir - +Path.absname(".") ``` Use [Path.dirname/1](https://hexdocs.pm/elixir/Path.html#dirname/1) to find the directory name of `"folder/subfolder/file.txt"` ```elixir - +Path.dirname("folder/subfolder/file.txt") ``` Use [Path.dirname/1](https://hexdocs.pm/elixir/Path.html#dirname/1) to find the directory name of `"file.txt"`. ```elixir - +Path.dirname("file.txt") ``` Use [Path.wildcard/2](https://hexdocs.pm/elixir/Path.html#wildcard/2) to find all files in a nested folder `"parent/*"` that end in a `.txt` extension. You should see your three `file.txt` files created earlier. ```elixir - +Path.wildcard("parent/*/*.txt") ``` Use [File.rm_rf/1](https://hexdocs.pm/elixir/File.html#rm_rf/1) to delete all folders created by this exercise. @@ -239,7 +256,11 @@ CAUTION: DO NOT DELETE IMPORTANT FILES ON YOUR COMPUTER. ```elixir - +File.ls() +File.rm_rf("parent") +File.ls() +File.rm_rf("child") +File.ls() ``` Use [File.rm/1](https://hexdocs.pm/elixir/File.html#rm/1) to delete any remaining files created by this exercise. @@ -249,7 +270,9 @@ CAUTION: DO NOT DELETE IMPORTANT FILES ON YOUR COMPUTER. ```elixir - +File.rm("empty.txt") +File.rm("multi-line.txt") +File.ls() ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 8dc084dcf..532cb71bf 100644 --- a/progress.json +++ b/progress.json @@ -25,7 +25,7 @@ "counting_votes_exercise": false, "metric_conversion_exercise": false, "shopping_list_exercise": false, - "file_drills_exercise": false, + "file_drills_exercise": true, "fibonacci_challenge_exercise": false, "ecto_changeset_reading": false, "comparison_operators_reading": false, @@ -155,7 +155,7 @@ "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, - "save_game_exercise": true, + "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, "livebook_reading": true, From 5a6eb021a3de082aa0f030664ba4755585521d2f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 27 Feb 2023 17:40:10 -0600 Subject: [PATCH 51/65] finish processes reading --- exercises/process_drills.livemd | 21 +++++++++++++++++++-- progress.json | 2 +- reading/processes.livemd | 10 +++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/exercises/process_drills.livemd b/exercises/process_drills.livemd index f39a778ce..ff15d8b28 100644 --- a/exercises/process_drills.livemd +++ b/exercises/process_drills.livemd @@ -25,13 +25,21 @@ This set of drills is for the [Process](https://hexdocs.pm/elixir/Process.html) Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) and `self()` to send the process for the Elixir cell below a `:message` message. Use [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to receive the message in the same cell. ```elixir +send(self(), "message") +receive do + "message" -> "received" +end ``` Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) and `self()` to send the process for the Elixir cell below a message with a value i.e. `{:message, "value"}`. Use [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to receive the message in the same cell and return the value. ```elixir +send(self(), {:message, "value"}) +receive do + {:message, "value"} -> "value" +end ``` ## Process.spawn/2 @@ -39,19 +47,28 @@ Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) and `self()` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) to spawn a new process which adds two integers together. ```elixir - +spawn(fn -> 1 + 2 end) ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process that sleeps for five seconds, then prints "Finished!". ```elixir - +pid = spawn(fn -> 1 + 2 end) +Process.sleep(5000) +Process.alive?(pid) || IO.puts("Finished!") ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a `:message` message. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a `:message` message. The spawned process should print `"received a message!"`. ```elixir +send(pid, :message) +pid = + spawn(fn -> + receive do + :message -> "received a message!" + end + end) ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a message with a value i.e. `{:message, "value"}`. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a message with a value. The spawned process should print the received value. diff --git a/progress.json b/progress.json index 532cb71bf..b48063029 100644 --- a/progress.json +++ b/progress.json @@ -89,7 +89,7 @@ "tic-tac-toe_exercise": true, "games_supervised_score_tracker_exercise": false, "benchmarking_reading": false, - "processes_reading": false, + "processes_reading": true, "games_menu_exercise": false, "supervised_mix_project_reading": false, "liveview_reading": false, diff --git a/reading/processes.livemd b/reading/processes.livemd index 22893ec05..0d8605fac 100644 --- a/reading/processes.livemd +++ b/reading/processes.livemd @@ -258,7 +258,14 @@ In the Elixir cell below, spawn a new process and send it a message `{:hello, "w `IO.puts` the message's payload where `"world"` is the payload. ```elixir +pid2 = + spawn(fn -> + receive do + {:hello, message} -> IO.puts(message) + end + end) +send(pid2, "world") ``` ## State @@ -363,6 +370,7 @@ defmodule Counter do receive do :increment -> loop(state + 1) + :decrement -> loop(state - 1) end end end @@ -373,7 +381,7 @@ counter_process = spawn(fn -> Counter.loop() end) You should be able to send a `:decrement` message to a spawned `Counter`. Uncomment and evaluate the code below to test your solution. ```elixir -# send(counter_process, :decrement) +send(counter_process, :decrement) ``` ## Mark As Completed From 437d75f6e200b255698d41328d440744623a0603 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 28 Feb 2023 14:58:17 -0600 Subject: [PATCH 52/65] finish stack server exercise --- exercises/process_drills.livemd | 26 +++++--- exercises/stack_server.livemd | 106 +++++++++----------------------- progress.json | 2 +- 3 files changed, 49 insertions(+), 85 deletions(-) diff --git a/exercises/process_drills.livemd b/exercises/process_drills.livemd index ff15d8b28..b0085a09d 100644 --- a/exercises/process_drills.livemd +++ b/exercises/process_drills.livemd @@ -61,26 +61,33 @@ Process.alive?(pid) || IO.puts("Finished!") Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a `:message` message. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a `:message` message. The spawned process should print `"received a message!"`. ```elixir -send(pid, :message) - -pid = +pid1 = spawn(fn -> receive do - :message -> "received a message!" + :message -> IO.puts("received a message!") end end) + +send(pid1, :message) ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a message with a value i.e. `{:message, "value"}`. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a message with a value. The spawned process should print the received value. ```elixir +pid2 = + spawn(fn -> + receive do + {:message, value} -> IO.puts("#{value}") + end + end) +send(pid2, "Hello World!") ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) to spawn a process that raises an error. Notice it does not crash the Livebook, because it is an **unlinked** process. ```elixir - +pid3 = spawn(fn -> raise "oops" end) ``` Use [Process.spawn/3](https://hexdocs.pm/elixir/Process.html#spawn/3) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process which raises an error after one second. Use [Process.link/1](https://hexdocs.pm/elixir/Process.html#link/1) to link the process. @@ -88,7 +95,8 @@ Use [Process.spawn/3](https://hexdocs.pm/elixir/Process.html#spawn/3) and [Proce Livebook should crash. Comment out your solution so that you can move on. ```elixir - +pid4 = spawn(fn -> raise "oops" end) +Process.sleep(1000) ``` ## Process.alive?/1 @@ -96,7 +104,11 @@ Livebook should crash. Comment out your solution so that you can move on. Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process that sleeps for five seconds. Use [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to check if the process is alive after two seconds. [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) should return `true`. ```elixir - +pid4 = spawn(fn -> true end) +Process.sleep(2000) +Process.alive?(pid4) || "still alive" +Process.sleep(3000) +Process.alive?(pid4) || "it's dead, Jim" ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process that sleeps for five seconds. Use [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to check if the process is alive after six seconds. [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) should return `false`. diff --git a/exercises/stack_server.livemd b/exercises/stack_server.livemd index 8eee8346f..0ff1a40b4 100644 --- a/exercises/stack_server.livemd +++ b/exercises/stack_server.livemd @@ -93,97 +93,49 @@ Consider starting with the `handle_call/3` callback functions, then implement th defmodule Stack do use GenServer - @doc """ - Start the `Stack` process. - - ## Examples - - iex> {:ok, pid} = Stack.start_link([]) - """ - def start_link(_opts) do + # Client API (Behaviour) + def start_link(opts) do + # IO.inspect("start_link", label: "Client") + GenServer.start_link(__MODULE__, opts) end - @doc """ - Synchronously push an element onto the top of the `Stack`. Return the current stack. - - ## Examples - - iex> {:ok, pid} = Stack.start_link([]) - iex> Stack.push(pid, 1) - [1] - iex> Stack.push(pid, 2) - [2, 1] - iex> Stack.push(pid, 3) - [3, 2, 1] - """ - def push(stack_pid, element) do + def push(pid, element) do + # IO.inspect("push #{element}", label: "Client") + GenServer.call(pid, {:push, element}) end - @doc """ - Pop an element from the top of the `Stack`. - - ## Examples - - iex> {:ok, pid} = Stack.start_link([]) - iex> Stack.push(pid, 1) - iex> Stack.push(pid, 2) - iex> Stack.push(pid, 3) - iex> Stack.pop(pid) - 3 - iex> Stack.pop(pid) - 2 - iex> Stack.pop(pid) - 1 - """ - def pop(stack_pid) do + def pop(pid) do + # IO.inspect("pop", label: "Client") + GenServer.call(pid, :pop) end - @doc """ - Necessary callback function to start the `Stack` process. - - ## Examples - - iex> {:ok, pid} = GenServer.start_link(Stack, []) - """ - def init(_opts) do + # Server API (Implementation) + def init(_init_arg) do + # IO.inspect("init", label: "Server") + {:ok, []} end - @doc """ - Callback function to add an element onto the top of the `Stack`. - - ## Examples - - iex> {:ok, pid} = GenServer.start_link(Stack, []) - iex> GenServer.call(pid, {:push, 1}) - [1] - iex> GenServer.call(pid, {:push, 2}) - [2, 1] - iex> GenServer.call(pid, {:push, 3}) - [3, 2, 1] - """ def handle_call({:push, element}, _from, state) do + # IO.inspect("handle_call :push #{element}", label: "Server") + new_state = [element | state] + response = new_state + {:reply, response, new_state} end - @doc """ - Callback function to pop an element off of the top of the `Stack`. - You do not need to handle popping when a stack is empty. - - ## Examples - - iex> {:ok, pid} = GenServer.start_link(Stack, []) - iex> GenServer.call(pid, {:push, 1}) - iex> GenServer.call(pid, {:push, 2}) - iex> GenServer.call(pid, {:push, 3}) - iex> GenServer.call(pid, :pop) - 3 - iex> GenServer.call(pid, :pop) - 2 - iex> GenServer.call(pid, :pop) - 1 - """ def handle_call(:pop, _from, state) do + # IO.inspect("handle_call :pop", label: "Server") + new_state = tl(state) + response = new_state + {:reply, response, new_state} end end + +# {:ok, pid} = Stack.start_link([]) +# Stack.push(pid, 2) +# Stack.push(pid, 2) +# Stack.push(pid, 2) +# Stack.pop(pid) +# Stack.pop(pid) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index b48063029..daffcac65 100644 --- a/progress.json +++ b/progress.json @@ -131,7 +131,7 @@ "typespecs_reading": false, "card_counting_exercise": true, "math_with_protocols_exercise": false, - "stack_server_exercise": false, + "stack_server_exercise": true, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, "agent_journal_exercise": false, From 2fc2261df8a0b5ce7d0175379a491d49613fb931 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Mar 2023 17:00:57 -0600 Subject: [PATCH 53/65] finish stack exercise --- exercises/stack.livemd | 78 +++++++++++++++++++++++++++++++---- exercises/stack_server.livemd | 5 ++- progress.json | 2 +- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/exercises/stack.livemd b/exercises/stack.livemd index 994c997c7..a1f54438b 100644 --- a/exercises/stack.livemd +++ b/exercises/stack.livemd @@ -58,13 +58,34 @@ Copy the code below into your `Stack` module. defmodule Stack do use GenServer - def start_link(_opts) do + # client functions + def start_link(opts) do + GenServer.start_link(__MODULE__, opts) end def push(pid, element) do + GenServer.call(pid, {:push, element}) end def pop(pid) do + GenServer.call(pid, :pop) + end + + # server functions + def init(opts) do + {:ok, opts} + end + + def handle_call({:push, element}, _from, state) do + {:reply, [element | state], [element | state]} + end + + def handle_call(:pop, _from, state) do + if Enum.empty?(state) do + {:reply, nil, nil} + else + {:reply, hd(state), tl(state)} + end end end ``` @@ -72,26 +93,65 @@ end Then copy the following code into the associated test file for the `Stack` module. ```elixir +ExUnit.start(auto_run: false) + defmodule StackTest do use ExUnit.Case describe "start_link/1" do - test "with no configuration" - test "with a default state" + test "initial state with no configuration" do + {:ok, pid} = Stack.start_link([]) + assert :sys.get_state(pid) == [] + end + + test "initial state with a default state" do + {:ok, pid} = Stack.start_link([1]) + assert :sys.get_state(pid) == [1] + end end describe "push/2" do - test "an element onto an empty stack" - test "an element onto a stack with one element" - test "an element onto a stack with multiple elements" + test "push an element onto an empty stack" do + {:ok, pid} = Stack.start_link([]) + Stack.push(pid, 3) + assert :sys.get_state(pid) == [3] + end + + test "push an element onto a stack with one element" do + {:ok, pid} = Stack.start_link([1]) + Stack.push(pid, 2) + assert :sys.get_state(pid) == [2, 1] + end + + test "push an element onto a stack with multiple elements" do + {:ok, pid} = Stack.start_link([2, 1]) + Stack.push(pid, 3) + assert :sys.get_state(pid) == [3, 2, 1] + end end describe "pop/1" do - test "an empty stack" - test "a stack with one element" - test "a stack with multiple elements" + test "pop an empty stack" do + {:ok, pid} = Stack.start_link([]) + assert Stack.pop(pid) == nil + assert :sys.get_state(pid) == nil + end + + test "pop a stack with one element" do + {:ok, pid} = Stack.start_link([1]) + assert Stack.pop(pid) == 1 + assert :sys.get_state(pid) == [] + end + + test "pop a stack with multiple elements" do + {:ok, pid} = Stack.start_link([3, 2, 1]) + assert Stack.pop(pid) == 3 + assert :sys.get_state(pid) == [2, 1] + end end end + +ExUnit.run() ``` ## Bonus: GitHub Repository diff --git a/exercises/stack_server.livemd b/exercises/stack_server.livemd index 0ff1a40b4..8b7a74094 100644 --- a/exercises/stack_server.livemd +++ b/exercises/stack_server.livemd @@ -96,6 +96,7 @@ defmodule Stack do # Client API (Behaviour) def start_link(opts) do # IO.inspect("start_link", label: "Client") + # Note: second arg (opts) is what's passed to init GenServer.start_link(__MODULE__, opts) end @@ -110,9 +111,9 @@ defmodule Stack do end # Server API (Implementation) - def init(_init_arg) do + def init(init_args) do # IO.inspect("init", label: "Server") - {:ok, []} + {:ok, init_args} end def handle_call({:push, element}, _from, state) do diff --git a/progress.json b/progress.json index daffcac65..5a505de79 100644 --- a/progress.json +++ b/progress.json @@ -121,7 +121,7 @@ "exunit_reading": true, "keyword_lists_reading": false, "command_line_reading": false, - "stack_exercise": false, + "stack_exercise": true, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, From 779c9f475ec94d9e269833659d6c25519c4417e5 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Mar 2023 15:50:00 -0600 Subject: [PATCH 54/65] finish mailbox server exercise --- exercises/mailbox_server.livemd | 24 ++++++++++++++++++++---- exercises/stack_server.livemd | 10 +++------- progress.json | 6 +++--- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/exercises/mailbox_server.livemd b/exercises/mailbox_server.livemd index bc5c0bb81..42feb40aa 100644 --- a/exercises/mailbox_server.livemd +++ b/exercises/mailbox_server.livemd @@ -96,7 +96,11 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Welcome to your mailbox!"] """ - def start_link(_opts) do + + ##### CLIENT ##### + + def start_link(opts) do + GenServer.start_link(__MODULE__, opts) end @doc """ @@ -110,7 +114,8 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Message 2", "Message 1"] """ - def send(mailbox_pid, message) do + def send(pid, message) do + GenServer.cast(pid, {:mail, message}) end @doc """ @@ -122,7 +127,8 @@ defmodule Mailbox do iex> Mailbox.all_messages(pid) [] """ - def all_messages(mailbox_pid) do + def all_messages(pid) do + GenServer.call(pid, :all_messages) end @doc """ @@ -132,8 +138,12 @@ defmodule Mailbox do iex> {:ok, _pid} = GenServer.start_link(Mailbox, []) """ + + ##### SERVER ##### + @impl true - def init(state) do + def init(args) do + {:ok, args} end @doc """ @@ -145,8 +155,10 @@ defmodule Mailbox do iex> GenServer.call(pid, :all_messages) ["Welcome"] """ + @impl true def handle_call(:all_messages, _from, state) do + {:reply, state, state} end @doc """ @@ -160,8 +172,10 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Message 2", "Message 1"] """ + @impl true def handle_cast({:mail, mail}, state) do + {:noreply, [mail | state]} end @doc """ @@ -175,8 +189,10 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Message 2", "Message 1"] """ + @impl true def handle_info({:mail, mail}, state) do + {:noreply, [mail | state]} end end ``` diff --git a/exercises/stack_server.livemd b/exercises/stack_server.livemd index 8b7a74094..d4a6fc09c 100644 --- a/exercises/stack_server.livemd +++ b/exercises/stack_server.livemd @@ -111,11 +111,13 @@ defmodule Stack do end # Server API (Implementation) + @impl true def init(init_args) do # IO.inspect("init", label: "Server") {:ok, init_args} end + @impl true def handle_call({:push, element}, _from, state) do # IO.inspect("handle_call :push #{element}", label: "Server") new_state = [element | state] @@ -123,6 +125,7 @@ defmodule Stack do {:reply, response, new_state} end + @impl true def handle_call(:pop, _from, state) do # IO.inspect("handle_call :pop", label: "Server") new_state = tl(state) @@ -130,13 +133,6 @@ defmodule Stack do {:reply, response, new_state} end end - -# {:ok, pid} = Stack.start_link([]) -# Stack.push(pid, 2) -# Stack.push(pid, 2) -# Stack.push(pid, 2) -# Stack.pop(pid) -# Stack.pop(pid) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 5a505de79..e06cbee1d 100644 --- a/progress.json +++ b/progress.json @@ -62,7 +62,7 @@ "group_project_blog_exercise": false, "treasure_matching_exercise": false, "github_engineering_journal_exercise": false, - "mailbox_server_exercise": false, + "mailbox_server_exercise": true, "blog_posts_exercise": false, "git_reading": true, "named_number_lists_exercise": false, @@ -121,7 +121,7 @@ "exunit_reading": true, "keyword_lists_reading": false, "command_line_reading": false, - "stack_exercise": true, + "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, @@ -131,7 +131,7 @@ "typespecs_reading": false, "card_counting_exercise": true, "math_with_protocols_exercise": false, - "stack_server_exercise": true, + "stack_server_exercise": false, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, "agent_journal_exercise": false, From 670241c3c7e5090b9782c47d82a34de7ba79e4f3 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Mar 2023 22:29:27 -0600 Subject: [PATCH 55/65] finish score tracker exercise --- exercises/score_tracker.livemd | 82 ++++++++++++++++++++++++++++------ progress.json | 2 +- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/exercises/score_tracker.livemd b/exercises/score_tracker.livemd index 83ecbf897..11b84bf46 100644 --- a/exercises/score_tracker.livemd +++ b/exercises/score_tracker.livemd @@ -87,7 +87,11 @@ defmodule ScoreTracker do iex> {:ok, pid} = ScoreTracker.start_link([]) """ - def start_link(_opts) do + + ##### CLIENT ##### + + def start_link(opts) do + GenServer.start_link(__MODULE__, opts) end @doc """ @@ -99,7 +103,9 @@ defmodule ScoreTracker do iex> ScoreTracker.score(pid, 10) :ok """ - def score(score_tracker_pid, amount) do + + def score(pid, amount) do + GenServer.cast(pid, {:score, amount}) end @doc """ @@ -111,7 +117,26 @@ defmodule ScoreTracker do iex> ScoreTracker.get_score(pid) 0 """ - def get_score(score_tracker_pid) do + + def get_score(pid) do + GenServer.call(pid, :get_score) + end + + ##### SERVER ##### + + @impl true + def init(_args) do + {:ok, 0} + end + + @impl true + def handle_cast({:score, amount}, state) do + {:noreply, state + amount} + end + + @impl true + def handle_call(:get_score, _from, state) do + {:reply, state, state} end end ``` @@ -183,7 +208,11 @@ defmodule MultiplayerScoreTracker do iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) """ + + ##### CLIENT ##### + def start_link(_opts) do + GenServer.start_link(__MODULE__, []) end @doc """ @@ -199,7 +228,8 @@ defmodule MultiplayerScoreTracker do iex> MultiplayerScoreTracker.score(pid, :abc, 10) :ok """ - def score(multiplayer_score_tracker_pid, player_name, amount) do + def score(pid, player_name, amount) do + GenServer.cast(pid, {:score, player_name, amount}) end @doc """ @@ -229,7 +259,8 @@ defmodule MultiplayerScoreTracker do iex> MultiplayerScoreTracker.all_scores(pid) %{player1: 10, player2: 10} """ - def all_scores(multiplayer_score_tracker_pid) do + def all_scores(pid) do + GenServer.call(pid, :all_scores) end @doc """ @@ -239,18 +270,41 @@ defmodule MultiplayerScoreTracker do Player does not exist. - iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) - iex> MultiplayerScoreTracker.get_score(pid, :player1) - nil + iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) + iex> MultiplayerScoreTracker.get_score(pid, :player1) + nil - Player exists. + Player exists. - iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) - iex> MultiplayerScoreTracker.score(pid, :abc, 10) - iex> MultiplayerScoreTracker.get_score(pid, :abc) - 10 + iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) + iex> MultiplayerScoreTracker.score(pid, :abc, 10) + iex> MultiplayerScoreTracker.get_score(pid, :abc) + 10 """ - def get_score(multiplayer_score_tracker_pid, player_name) do + def get_score(pid, player_name) do + GenServer.call(pid, {:get_score, player_name}) + end + + ##### SERVER ##### + + @impl true + def init(_args) do + {:ok, %{}} + end + + @impl true + def handle_cast({:score, player_name, amount}, state) do + {:noreply, Map.update(state, player_name, amount, fn state -> state + amount end)} + end + + @impl true + def handle_call(:all_scores, _from, state) do + {:reply, state, state} + end + + @impl true + def handle_call({:get_score, player_name}, _from, state) do + {:reply, state[player_name], state} end end ``` diff --git a/progress.json b/progress.json index e06cbee1d..5c6c1e4e4 100644 --- a/progress.json +++ b/progress.json @@ -195,7 +195,7 @@ "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, - "score_tracker_exercise": false, + "score_tracker_exercise": true, "tailwind_reading": false, "mapset_drills_exercise": false, "book_search_books_reading": false, From 501b75c3530d679ab67bc9e12a44e6b4476ca783 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Mar 2023 12:08:14 -0600 Subject: [PATCH 56/65] finish timer exercise --- exercises/timer.livemd | 137 +++++++++++++++++++++++++++++++---------- progress.json | 2 +- 2 files changed, 105 insertions(+), 34 deletions(-) diff --git a/exercises/timer.livemd b/exercises/timer.livemd index c51b45286..e823abdda 100644 --- a/exercises/timer.livemd +++ b/exercises/timer.livemd @@ -76,37 +76,66 @@ end Implement the `Timer` module as documented below. You will also have to implement the necessary [GenServer](https://hexdocs.pm/elixir/GenServer.html) callback functions such as [GenServer.init/1](https://hexdocs.pm/elixir/GenServer.html#init/1), [GenServer.handle_info/2](https://hexdocs.pm/elixir/GenServer.html#handle_info/2), and [GenServer.handle_call/3](https://hexdocs.pm/elixir/GenServer.html#handle_call/3). ```elixir - defmodule Timer do - @moduledoc """ - Documentation for `Timer` - """ - use GenServer - - @doc """ - Start the `Timer` process. - - ## Examples - - iex> {:ok, pid} = Timer.start_link([]) - """ - def start_link(_opts) do - end - - @doc """ - Get the number of seconds that have elapsed since the `Timer` was started. - - ## Examples - - iex> {:ok, pid} = Timer.start_link([]) - iex> Timer.seconds(pid) - 0 - iex> Process.sleep(1200) - iex> Timer.seconds(pid) - 1 - """ - def seconds(timer_pid) do - end - end +defmodule Timer do + @moduledoc """ + Documentation for `Timer` + """ + use GenServer + + @doc """ + Start the `Timer` process. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) + """ + + ##### CLIENT ##### + + def start_link(_opts) do + GenServer.start_link(__MODULE__, []) + end + + @doc """ + Get the number of seconds that have elapsed since the `Timer` was started. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) + iex> Timer.seconds(pid) + 0 + iex> Process.sleep(1200) + iex> Timer.seconds(pid) + 1 + """ + def seconds(pid) do + GenServer.call(pid, :seconds) + end + + ##### SERVER ##### + + @impl true + def init(_opts) do + increment_timer() + {:ok, 0} + end + + @impl true + def handle_call(:seconds, _from, state) do + {:reply, state, state} + end + + @impl true + def handle_info(:increment, state) do + increment_timer() + {:noreply, state + 1} + end + + defp increment_timer do + # add one second + Process.send_after(self(), :increment, 1000) + end +end ``` ## Bonus :timer @@ -157,16 +186,58 @@ defmodule AlternateTimer do @doc """ Start the `Timer` process. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) """ + + ##### CLIENT ##### + def start_link(_opts) do GenServer.start_link(__MODULE__, []) end @doc """ Get the number of seconds that have elapsed since the `Timer` was started. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) + iex> Timer.seconds(pid) + 0 + iex> Process.sleep(1200) + iex> Timer.seconds(pid) + 1 + """ - def seconds(timer_pid) do - GenServer.call(timer_pid, :seconds) + + def seconds(pid) do + GenServer.call(pid, :seconds) + end + + ##### SERVER ##### + + @impl true + def init(_opts) do + increment_timer() + {:ok, 0} + end + + @impl true + def handle_call(:seconds, _from, state) do + {:reply, state, state} + end + + @impl true + def handle_info(:increment, state) do + increment_timer() + {:noreply, state + 1} + end + + defp increment_timer do + # add one second + :timer.send_interval(1000, self(), :increment) end end ``` diff --git a/progress.json b/progress.json index 5c6c1e4e4..59d5289d4 100644 --- a/progress.json +++ b/progress.json @@ -69,7 +69,7 @@ "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, - "timer_exercise": false, + "timer_exercise": true, "games_benchmarking_exercise": false, "guessing_games_exercise": false, "sign_up_form_exercise": false, From c9ad3d600a394ccec8b5bc874a73bddc2285eea7 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Mar 2023 13:37:16 -0600 Subject: [PATCH 57/65] finish supervised stack exercise --- exercises/dominoes.livemd | 17 ++++++++++++++++- exercises/monster_spawner.livemd | 2 +- exercises/supervised_stack.livemd | 9 ++++++++- progress.json | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/exercises/dominoes.livemd b/exercises/dominoes.livemd index aa3337209..ac4cc4f8c 100644 --- a/exercises/dominoes.livemd +++ b/exercises/dominoes.livemd @@ -97,7 +97,22 @@ Supervisor.start_link(children, strategy: :rest_for_one) Keep in mind, if you have already started a named process, the supervisor might crash when you attempt to start it again. Re-evaluate the cell after the livebook crashes to resolve this issue. ```elixir +children = [ + %{ + id: D1, + start: {Domino, :start_link, [[name: D1]]} + }, + %{ + id: D2, + start: {Domino, :start_link, [[name: D2]]} + }, + %{ + id: D3, + start: {Domino, :start_link, [[name: D3]]} + } +] +{:ok, pid} = Supervisor.start_link(children, strategy: :rest_for_one) ``` Send your dominos messages to ensure they are crashing in the correct order. They will log a message that demonstrates the `Domino.start_link/1` function was called again. @@ -116,7 +131,7 @@ Process.send(:domino_name, :fall, []) Test sending each `Domino` process a message individually. ```elixir - +Process.send(D3, :fall, []) ``` ## Mark As Completed diff --git a/exercises/monster_spawner.livemd b/exercises/monster_spawner.livemd index 8dc7d564c..fc6a3b980 100644 --- a/exercises/monster_spawner.livemd +++ b/exercises/monster_spawner.livemd @@ -5,7 +5,7 @@ Mix.install([ {:jason, "~> 1.4"}, {:kino, "~> 0.8.0", override: true}, {:youtube, github: "brooklinjazz/youtube"}, - {:hidden_cell, github: "brooklinjazz/hidden_cell"}, + {:hidden_cell, github: "brooklinjazz/hidden_cell"} ]) ``` diff --git a/exercises/supervised_stack.livemd b/exercises/supervised_stack.livemd index b6db113b5..59fe5303a 100644 --- a/exercises/supervised_stack.livemd +++ b/exercises/supervised_stack.livemd @@ -104,7 +104,14 @@ children = [ Keep in mind, if you have already started a supervisor with the `Stack` process, your livebook may crash. You can resolve this issue by simply re-running the cell below to start the supervisor again. ```elixir +children = [ + %{ + id: Stack, + start: {Stack, :start_link, [[]]} + } +] +{:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one) ``` You should be able to send a `:pop` message to the `Stack` process and the [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) will restart the `Stack` process. @@ -112,7 +119,7 @@ You should be able to send a `:pop` message to the `Stack` process and the [Supe Uncomment and evaluate the code below to test your supervisor. ```elixir -# GenServer.call(Stack, :pop) +GenServer.call(Stack, :pop) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 59d5289d4..7f1ee2471 100644 --- a/progress.json +++ b/progress.json @@ -125,7 +125,7 @@ "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, - "supervised_stack_exercise": false, + "supervised_stack_exercise": true, "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, From c33d4a22c83502031c1abda29998eb02acd90b54 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Mar 2023 13:38:25 -0600 Subject: [PATCH 58/65] finish dominoes exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 7f1ee2471..5e672e1d7 100644 --- a/progress.json +++ b/progress.json @@ -46,7 +46,7 @@ "non_enumerables_reading": true, "control_flow_reading": false, "lists_vs_tuples_reading": false, - "dominoes_exercise": false, + "dominoes_exercise": true, "command_line_family_tree_exercise": false, "phoenix_and_ecto_reading": false, "number_finder_exercise": true, From 38140a1ebf3ba0e5815b2184d2bd37514d178d48 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Mar 2023 16:10:49 -0600 Subject: [PATCH 59/65] finish task reading --- exercises/monster_spawner.livemd | 47 +++++++++++++------ exercises/task_drills.livemd | 78 ++++++++++++++++++++++++++++---- progress.json | 2 +- reading/task.livemd | 3 +- 4 files changed, 105 insertions(+), 25 deletions(-) diff --git a/exercises/monster_spawner.livemd b/exercises/monster_spawner.livemd index fc6a3b980..f8beb8f5d 100644 --- a/exercises/monster_spawner.livemd +++ b/exercises/monster_spawner.livemd @@ -104,6 +104,8 @@ Implement the `Monster` process as documented below. defmodule Monster do use GenServer + ##### CLIENT ##### + @doc """ Start the `Monster` process. @@ -111,9 +113,11 @@ defmodule Monster do iex> {:ok, pid} = Monster.start_link([]) """ + def start_link(opts) do # IO.inspect/2 to observe when a `Monster` process starts. IO.inspect(opts, label: "Monster Started") + GenServer.start_link(__MODULE__, opts) end @doc """ @@ -121,13 +125,14 @@ defmodule Monster do ## Examples - iex> {:ok, pid} = Monster.start_link([]) - iex> :sys.get_state(pid) - %{health: 100} - iex> Monster.attack(pid, 30) - iex> :sys.get_state(pid) - %{health: 70} + # iex> {:ok, pid} = Monster.start_link([]) + # iex> :sys.get_state(pid) + # %{health: 100} + # iex> Monster.attack(pid, 30) + # iex> :sys.get_state(pid) + # %{health: 70} """ + def attack(monster_pid, amount) do end @@ -140,9 +145,13 @@ defmodule Monster do iex> Monster.health(pid) 100 """ + def health(monster_pid) do + GenServer.call(monster_pid, :health) end + ##### SERVER ##### + @doc """ Callback function to start the `Monster` process. Monsters should start with a `:health` value in a map. @@ -153,8 +162,10 @@ defmodule Monster do iex> :sys.get_state(pid) %{health: 100} """ + @impl true def init(_opts) do + {:ok, %{health: 100}} end @doc """ @@ -164,14 +175,14 @@ defmodule Monster do ## Examples - iex> {:ok, pid} = GenServer.start_link(Monster, []) - iex> :sys.get_state(pid) - %{health: 100} - iex> GenServer.cast(pid, {:attack, 20}) - iex> :sys.get_state(pid) - %{health: 80} - iex> GenServer.cast(pid, {:attack, 80}) - ** (RuntimeError) dying! + # iex> {:ok, pid} = GenServer.start_link(Monster, []) + # iex> :sys.get_state(pid) + # %{health: 100} + # iex> GenServer.cast(pid, {:attack, 20}) + # iex> :sys.get_state(pid) + # %{health: 80} + # iex> GenServer.cast(pid, {:attack, 80}) + # ** (RuntimeError) dying! """ @impl true def handle_cast({:attack, damage}, state) do @@ -188,10 +199,18 @@ defmodule Monster do """ @impl true def handle_call(:health, _from, state) do + # IO.inspect(state) + health = Map.get(state, :health) + {:reply, health, state} end end ``` +```elixir +test = %{health: 100} +Map.get(test, :health) +``` + ## Supervisor Create three named `Monster` processes under a single supervisor. When one `Monster` process dies after its health reaches zero, another should be restarted in it's place. diff --git a/exercises/task_drills.livemd b/exercises/task_drills.livemd index 900020104..fc9340b52 100644 --- a/exercises/task_drills.livemd +++ b/exercises/task_drills.livemd @@ -25,19 +25,27 @@ This set of drills is for [Tasks](../reading/task.livemd). Follow the instructio Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that returns any response. ```elixir +Kino.Process.render_seq_trace(fn -> + Process.sleep(2000) + Task.async(fn -> IO.puts("hello world!") end) +end) +# task = Task.async(fn -> Process.sleep(2000) end) +# Task.await(task) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that sleeps for six seconds. It should cause a timeout error. ```elixir - +task = Task.async(fn -> Process.sleep(6000) end) +Task.await(task) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that sleeps for six seconds. Provide a timeout value to [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) so that it properly awaits the response. ```elixir - +task = Task.async(fn -> Process.sleep(2000) end) +Task.await(task, 7000) ``` ## Task.yield/2 @@ -55,7 +63,7 @@ time ``` ```elixir -{time, _result} = +Kino.Process.render_seq_trace(fn -> :timer.tc(fn -> # 1000 tasks # 1000 operations -> parallel @@ -69,9 +77,25 @@ time Task.await_many(tasks) end) +end) -10_009_225 -1_001_494 +# {time, _result} = +# :timer.tc(fn -> +# # 1000 tasks +# # 1000 operations -> parallel +# tasks = +# Enum.map(1..10, fn int -> +# Task.async(fn -> +# IO.puts("starting task #{int}") +# Process.sleep(1000) +# end) +# end) + +# Task.await_many(tasks) +# end) + +# 10_009_225 +# 1_001_494 ``` ### Fast Operation @@ -83,31 +107,55 @@ time ``` ```elixir -{time, _result} = +Kino.Process.render_seq_trace(fn -> :timer.tc(fn -> # 1000 tasks # 1000 operations -> parallel tasks = Enum.map(1..10, fn int -> Task.async(fn -> int * 2 end) end) Task.await_many(tasks) end) +end) + +# {time, _result} = +# :timer.tc(fn -> +# # 1000 tasks +# # 1000 operations -> parallel +# tasks = Enum.map(1..10, fn int -> Task.async(fn -> int * 2 end) end) +# Task.await_many(tasks) +# end) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Notice that the yield is `nil`. ```elixir +task = + Task.async(fn -> + Process.sleep(6000) + IO.puts("howdy!") + end) +Task.yield(task) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Provide a timeout value to [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) so that it properly returns the response. ```elixir +task = + Task.async(fn -> + Process.sleep(6000) + IO.puts("howdy!") + end) +Task.yield(task, 7000) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2), and [Task.shutdown/2](https://hexdocs.pm/elixir/Task.html#shutdown/2) to spawn a task process that sleeps for six seconds. Shutdown the task process if it does not yield any value. ```elixir - +Kino.Process.render_seq_trace(fn -> + task = Task.async(fn -> Process.sleep(6000) end) + Task.yield(task) || Task.shutdown(task) +end) ``` ## Task.await_many/2 @@ -115,25 +163,37 @@ Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [Task.yield/2]( Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn two task processes that both return a random number from `1..10`. ```elixir +tasks = [ + Task.async(fn -> :rand.uniform(10) end), + Task.async(fn -> :rand.uniform(10) end) +] +Task.await_many(tasks) ``` Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn one hundred task processes that all return a random integer from `1..100`. ```elixir - +tasks = Enum.map(1..100, fn _num -> Task.async(fn -> :rand.uniform(100) end) end) +Task.await_many(tasks) ``` Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn one hundred task processes that return a list doubled numbers from one to one hundred. i.e. `[2, 4, 6, 8, ..., 198, 200]`. ```elixir - +tasks = Enum.map(1..100, fn int -> Task.async(fn -> int * 2 end) end) +Task.await_many(tasks) ``` Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [String.upcase/2](https://hexdocs.pm/elixir/String.html#upcase/2), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to concurrently capitalize every string in the list `["apple", "pear", "peaches"]` ```elixir +tasks = + Enum.map(["apple", "pear", "peaches"], fn string -> + Task.async(fn -> String.capitalize(string) end) + end) +Task.await_many(tasks) ``` ## Task.Supervisor diff --git a/progress.json b/progress.json index 5e672e1d7..2c41ab8e5 100644 --- a/progress.json +++ b/progress.json @@ -97,7 +97,7 @@ "io_reading": false, "tuples_reading": false, "ranges_reading": false, - "task_reading": false, + "task_reading": true, "executables_reading": false, "rdbms_reading": false, "fun_formulas_exercise": false, diff --git a/reading/task.livemd b/reading/task.livemd index 70412b63f..4e7553800 100644 --- a/reading/task.livemd +++ b/reading/task.livemd @@ -242,7 +242,8 @@ In the Elixir cell below, spawn a task which takes one second to complete. `await/2` the task and alter the timeout value to be one second. Awaiting the task should crash. ```elixir - +task = Task.async(fn -> Process.sleep(1000) end) +Task.await(task, 1000) ``` ## Further Reading From 3d6cc1775aad9bbc253685dda5a651e6acaa42c6 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Mar 2023 16:42:54 -0600 Subject: [PATCH 60/65] finish capstone project guide reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 2c41ab8e5..608fca118 100644 --- a/progress.json +++ b/progress.json @@ -201,7 +201,7 @@ "book_search_books_reading": false, "recursion_reading": false, "in-memory_todo_list_exercise": false, - "capstone_project_guide_reading": false, + "capstone_project_guide_reading": true, "fibonacci_exercise": true, "typespec_drills_exercise": false, "custom_assertions_exercise": false, From 17eb1cf4287ff8c2941b1b53e0708e06483045ee Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Mar 2023 13:07:53 -0600 Subject: [PATCH 61/65] finish spoonacular recipe api exercise --- exercises/spoonacular_recipe_api.livemd | 5 +++++ progress.json | 2 +- reading/apis.livemd | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/exercises/spoonacular_recipe_api.livemd b/exercises/spoonacular_recipe_api.livemd index 7e208a76d..54bd2fb18 100644 --- a/exercises/spoonacular_recipe_api.livemd +++ b/exercises/spoonacular_recipe_api.livemd @@ -31,7 +31,12 @@ Use your API to visit the `https://api.spoonacular.com/recipes/complexSearch?api Use [HTTPoison](https://hexdocs.pm/httpoison/HTTPoison.html) to retrieve the same JSON data from the `https://api.spoonacular.com/recipes/complexSearch?apiKey=API_KEY` URL you visited in the browser. Then use [Poison](https://hexdocs.pm/poison/Poison.html) to decode the JSON response into an Elixir data structure. ```elixir +api_key = "235ecefcc30147279ffd925e41a3178e" +{:ok, response} = + HTTPoison.get("https://api.spoonacular.com/recipes/complexSearch?apiKey=#{api_key}") + +Jason.decode(response.body) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 608fca118..8c2917614 100644 --- a/progress.json +++ b/progress.json @@ -151,7 +151,7 @@ "lists_reading": false, "message_validation_exercise": false, "functions_reading": false, - "spoonacular_recipe_api_exercise": false, + "spoonacular_recipe_api_exercise": true, "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, diff --git a/reading/apis.livemd b/reading/apis.livemd index 5b64ad6ee..ec5abccc9 100644 --- a/reading/apis.livemd +++ b/reading/apis.livemd @@ -236,6 +236,7 @@ Use [Jason.decode!/2](https://hexdocs.pm/jason/Jason.html#encode!/2) to decode t ```elixir json = "{\"hello\"\: \"world\"}" +Jason.decode(json) ``` ## Poison @@ -282,7 +283,7 @@ Private APIs require an API key to communicate with them. This key is then inclu For example, the [Open Weather API](https://openweathermap.org/) requires an API key when making a GET request. The server returns a `401` unauthorized response without the correct API key. ```elixir -api_key = "" +api_key = "a492ee767808f098ff912f4afc1a2b8d" HTTPoison.get("https://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&appid=#{api_key}") ``` @@ -312,7 +313,7 @@ Use your API key and valid latitude/longitude coordinates to make a successful r ```elixir lat = 35 lon = 139 -api_key = "" +api_key = "a492ee767808f098ff912f4afc1a2b8d" {:ok, response} = HTTPoison.get( From 69507b2bff74b171099ef05cf6f843c73f22c97a Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Mar 2023 13:10:03 -0600 Subject: [PATCH 62/65] finish apis reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 8c2917614..5eec18589 100644 --- a/progress.json +++ b/progress.json @@ -179,7 +179,7 @@ "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, - "apis_reading": false, + "apis_reading": true, "built-in_modules_reading": true, "rps_pattern_matching_exercise": false, "arithmetic_reading": false, From e100a12053f9bf712956889577b7d73c3bb0f63e Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Mar 2023 18:33:45 -0600 Subject: [PATCH 63/65] finish pokemon api exercise --- exercises/pokemon_api.livemd | 64 +++++++++++++++++++++++++++++++++++- progress.json | 8 ++--- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/exercises/pokemon_api.livemd b/exercises/pokemon_api.livemd index c34a9f5dd..8c61c1004 100644 --- a/exercises/pokemon_api.livemd +++ b/exercises/pokemon_api.livemd @@ -7,7 +7,7 @@ Mix.install([ {:youtube, github: "brooklinjazz/youtube"}, {:hidden_cell, github: "brooklinjazz/hidden_cell"}, {:httpoison, "~> 1.8"}, - {:poison, "~> 5.0"} + {:exconstructor, "~> 1.2"} ]) ``` @@ -38,6 +38,44 @@ mix new pokelixir Ensure you add [HTTPoison](https://github.com/edgurgel/httpoison) and [Poison](https://github.com/devinus/poison) as dependencies. +```elixir +defmodule Pokelixir do + defstruct [ + :id, + :name, + :hp, + :attack, + :defense, + :special_attack, + :special_defense, + :speed, + :weight, + :height, + :types + ] + + use ExConstructor + + def get(name) do + {:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/#{name}") + {_head, body} = Jason.decode(response.body) + + ExConstructor.populate_struct(%__MODULE__{}, body) + end + + def all() do + {:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/?limit=1500") + Jason.decode(response.body) + end +end + +# get a pokemon +Pokelixir.get("charizard") + +# get all pokemons +# Pokelixir.all() +``` + ## Pokemon Structs A `Pokemon` struct should have the following (required) keys. You do not need to implement data validation. @@ -79,6 +117,12 @@ Here's that data represented as a `Pokemon` struct. } ``` +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/charizard") + +Jason.decode(response.body) +``` + ## Get A Pokemon We can request information about Pokemon using the [Pokemon API](https://pokeapi.co/). @@ -117,6 +161,24 @@ response = Poison.decode!(response.body) ## Get All Pokemon +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon") + +Jason.decode(response.body) +``` + +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon?offset=20&limit=20") + +Jason.decode(response.body) +``` + +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/6") + +Jason.decode(response.body) +``` + You can retrieve a list of pokemon using the following URL. ``` diff --git a/progress.json b/progress.json index 5eec18589..954ca1d58 100644 --- a/progress.json +++ b/progress.json @@ -56,7 +56,7 @@ "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": true, "math_with_guards_exercise": false, - "pokemon_api_exercise": false, + "pokemon_api_exercise": true, "file_search_exercise": false, "animal_generator_exercise": true, "group_project_blog_exercise": false, @@ -151,7 +151,7 @@ "lists_reading": false, "message_validation_exercise": false, "functions_reading": false, - "spoonacular_recipe_api_exercise": true, + "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, @@ -179,7 +179,7 @@ "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, - "apis_reading": true, + "apis_reading": false, "built-in_modules_reading": true, "rps_pattern_matching_exercise": false, "arithmetic_reading": false, @@ -201,7 +201,7 @@ "book_search_books_reading": false, "recursion_reading": false, "in-memory_todo_list_exercise": false, - "capstone_project_guide_reading": true, + "capstone_project_guide_reading": false, "fibonacci_exercise": true, "typespec_drills_exercise": false, "custom_assertions_exercise": false, From fec1c7d715ae7bfd24d6f6853d04f03116173552 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 10 Mar 2023 11:33:18 -0600 Subject: [PATCH 64/65] finish web servers reading --- reading/web_servers.livemd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reading/web_servers.livemd b/reading/web_servers.livemd index 93f664f15..406af24e8 100644 --- a/reading/web_servers.livemd +++ b/reading/web_servers.livemd @@ -138,7 +138,7 @@ defmodule WebServer do # send response current_time = Time.to_string(Time.utc_now()) - response = "HTTP/1.1 200\r\nContent-Type: text/html\r\n\r\n It is #{current_time}" + response = "HTTP/1.1 200\r\nContent-Type: text/html\r\n\r\n

It is #{current_time}

" :gen_tcp.send(connection, response) # close connection From df20e429dc166f49a9616075fb41bbe40bb792b2 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 14 Mar 2023 13:59:21 -0500 Subject: [PATCH 65/65] finish tailwind reading --- phoenix-1.6/counter/.formatter.exs | 4 + phoenix-1.6/counter/.gitignore | 34 + phoenix-1.6/counter/README.md | 18 + phoenix-1.6/counter/assets/css/app.css | 120 +++ phoenix-1.6/counter/assets/css/phoenix.css | 101 +++ phoenix-1.6/counter/assets/js/app.js | 45 ++ phoenix-1.6/counter/assets/vendor/topbar.js | 157 ++++ phoenix-1.6/counter/config/config.exs | 49 ++ phoenix-1.6/counter/config/dev.exs | 65 ++ phoenix-1.6/counter/config/prod.exs | 49 ++ phoenix-1.6/counter/config/runtime.exs | 68 ++ phoenix-1.6/counter/config/test.exs | 18 + phoenix-1.6/counter/lib/counter.ex | 36 + .../counter/lib/counter/application.ex | 34 + phoenix-1.6/counter/lib/counter/mailer.ex | 3 + phoenix-1.6/counter/lib/counter_web.ex | 110 +++ .../controllers/count_controller.ex | 7 + .../controllers/page_controller.ex | 7 + .../counter/lib/counter_web/endpoint.ex | 49 ++ .../counter/lib/counter_web/gettext.ex | 24 + phoenix-1.6/counter/lib/counter_web/router.ex | 57 ++ .../counter/lib/counter_web/telemetry.ex | 48 ++ .../templates/count/count.html.heex | 2 + .../templates/layout/app.html.heex | 5 + .../templates/layout/live.html.heex | 11 + .../templates/layout/root.html.heex | 30 + .../templates/page/index.html.heex | 41 ++ .../lib/counter_web/views/count_view.ex | 3 + .../lib/counter_web/views/error_helpers.ex | 47 ++ .../lib/counter_web/views/error_view.ex | 16 + .../lib/counter_web/views/layout_view.ex | 7 + .../lib/counter_web/views/page_view.ex | 3 + phoenix-1.6/counter/mix.exs | 64 ++ phoenix-1.6/counter/mix.lock | 29 + .../priv/gettext/en/LC_MESSAGES/errors.po | 11 + phoenix-1.6/counter/priv/gettext/errors.pot | 10 + phoenix-1.6/counter/priv/static/favicon.ico | Bin 0 -> 1258 bytes .../counter/priv/static/images/phoenix.png | Bin 0 -> 13900 bytes phoenix-1.6/counter/priv/static/robots.txt | 5 + .../controllers/page_controller_test.exs | 8 + .../counter_web/views/error_view_test.exs | 14 + .../counter_web/views/layout_view_test.exs | 8 + .../test/counter_web/views/page_view_test.exs | 3 + phoenix-1.6/counter/test/support/conn_case.ex | 37 + phoenix-1.6/counter/test/test_helper.exs | 1 + phoenix-1.6/hello_world/.formatter.exs | 4 + phoenix-1.6/hello_world/.gitignore | 34 + phoenix-1.6/hello_world/README.md | 18 + phoenix-1.6/hello_world/assets/css/app.css | 120 +++ .../hello_world/assets/css/phoenix.css | 101 +++ phoenix-1.6/hello_world/assets/js/app.js | 45 ++ .../hello_world/assets/vendor/topbar.js | 157 ++++ phoenix-1.6/hello_world/config/config.exs | 49 ++ phoenix-1.6/hello_world/config/dev.exs | 65 ++ phoenix-1.6/hello_world/config/prod.exs | 49 ++ phoenix-1.6/hello_world/config/runtime.exs | 68 ++ phoenix-1.6/hello_world/config/test.exs | 18 + phoenix-1.6/hello_world/lib/hello_world.ex | 9 + .../lib/hello_world/application.ex | 34 + .../hello_world/lib/hello_world/mailer.ex | 3 + .../hello_world/lib/hello_world_web.ex | 110 +++ .../controllers/page_controller.ex | 7 + .../lib/hello_world_web/endpoint.ex | 49 ++ .../lib/hello_world_web/gettext.ex | 24 + .../hello_world/lib/hello_world_web/router.ex | 56 ++ .../lib/hello_world_web/telemetry.ex | 48 ++ .../templates/layout/app.html.heex | 5 + .../templates/layout/live.html.heex | 11 + .../templates/layout/root.html.heex | 30 + .../templates/page/index.html.heex | 41 ++ .../hello_world_web/views/error_helpers.ex | 47 ++ .../lib/hello_world_web/views/error_view.ex | 16 + .../lib/hello_world_web/views/layout_view.ex | 7 + .../lib/hello_world_web/views/page_view.ex | 3 + phoenix-1.6/hello_world/mix.exs | 64 ++ phoenix-1.6/hello_world/mix.lock | 29 + .../priv/gettext/en/LC_MESSAGES/errors.po | 11 + .../hello_world/priv/gettext/errors.pot | 10 + .../hello_world/priv/static/favicon.ico | Bin 0 -> 1258 bytes .../priv/static/images/phoenix.png | Bin 0 -> 13900 bytes .../hello_world/priv/static/robots.txt | 5 + .../controllers/page_controller_test.exs | 8 + .../hello_world_web/views/error_view_test.exs | 14 + .../views/layout_view_test.exs | 8 + .../hello_world_web/views/page_view_test.exs | 3 + .../hello_world/test/support/conn_case.ex | 37 + phoenix-1.6/hello_world/test/test_helper.exs | 1 + phoenix-1.6/navigation/.formatter.exs | 4 + phoenix-1.6/navigation/.gitignore | 34 + phoenix-1.6/navigation/README.md | 18 + phoenix-1.6/navigation/assets/css/app.css | 120 +++ phoenix-1.6/navigation/assets/css/phoenix.css | 101 +++ phoenix-1.6/navigation/assets/js/app.js | 45 ++ .../navigation/assets/vendor/topbar.js | 157 ++++ phoenix-1.6/navigation/config/config.exs | 49 ++ phoenix-1.6/navigation/config/dev.exs | 65 ++ phoenix-1.6/navigation/config/prod.exs | 49 ++ phoenix-1.6/navigation/config/runtime.exs | 68 ++ phoenix-1.6/navigation/config/test.exs | 18 + phoenix-1.6/navigation/lib/navigation.ex | 9 + .../navigation/lib/navigation/application.ex | 34 + .../navigation/lib/navigation/mailer.ex | 3 + phoenix-1.6/navigation/lib/navigation_web.ex | 110 +++ .../controllers/about_controller.ex | 7 + .../controllers/home_controller.ex | 7 + .../controllers/page_controller.ex | 7 + .../controllers/projects_controller.ex | 7 + .../navigation/lib/navigation_web/endpoint.ex | 49 ++ .../navigation/lib/navigation_web/gettext.ex | 24 + .../navigation/lib/navigation_web/router.ex | 59 ++ .../lib/navigation_web/telemetry.ex | 48 ++ .../templates/about/about.html.heex | 1 + .../templates/home/home.html.heex | 1 + .../templates/layout/app.html.heex | 5 + .../templates/layout/live.html.heex | 11 + .../templates/layout/root.html.heex | 39 + .../templates/page/home/home.html.heex | 1 + .../templates/page/index.html.heex | 41 ++ .../page/projects/projects.html.heex | 1 + .../templates/projects/projects.html.heex | 1 + .../lib/navigation_web/views/about_view.ex | 3 + .../lib/navigation_web/views/error_helpers.ex | 47 ++ .../lib/navigation_web/views/error_view.ex | 16 + .../lib/navigation_web/views/home_view.ex | 3 + .../lib/navigation_web/views/layout_view.ex | 7 + .../lib/navigation_web/views/page_view.ex | 3 + .../lib/navigation_web/views/projects_view.ex | 3 + phoenix-1.6/navigation/mix.exs | 64 ++ phoenix-1.6/navigation/mix.lock | 29 + .../priv/gettext/en/LC_MESSAGES/errors.po | 11 + .../navigation/priv/gettext/errors.pot | 10 + .../navigation/priv/static/favicon.ico | Bin 0 -> 1258 bytes .../navigation/priv/static/images/phoenix.png | Bin 0 -> 13900 bytes phoenix-1.6/navigation/priv/static/robots.txt | 5 + .../controllers/page_controller_test.exs | 8 + .../navigation_web/views/error_view_test.exs | 14 + .../navigation_web/views/layout_view_test.exs | 8 + .../navigation_web/views/page_view_test.exs | 3 + .../navigation/test/support/conn_case.ex | 37 + phoenix-1.6/navigation/test/test_helper.exs | 1 + phoenix-1.6/random_number/.formatter.exs | 4 + phoenix-1.6/random_number/.gitignore | 34 + phoenix-1.6/random_number/README.md | 18 + phoenix-1.6/random_number/assets/css/app.css | 120 +++ .../random_number/assets/css/phoenix.css | 101 +++ phoenix-1.6/random_number/assets/js/app.js | 45 ++ .../random_number/assets/vendor/topbar.js | 157 ++++ phoenix-1.6/random_number/config/config.exs | 49 ++ phoenix-1.6/random_number/config/dev.exs | 65 ++ phoenix-1.6/random_number/config/prod.exs | 49 ++ phoenix-1.6/random_number/config/runtime.exs | 68 ++ phoenix-1.6/random_number/config/test.exs | 18 + .../random_number/lib/random_number.ex | 14 + .../lib/random_number/application.ex | 34 + .../random_number/lib/random_number/mailer.ex | 3 + .../random_number/lib/random_number_web.ex | 110 +++ .../controllers/page_controller.ex | 8 + .../controllers/random_number_controller.ex | 7 + .../lib/random_number_web/endpoint.ex | 49 ++ .../lib/random_number_web/gettext.ex | 24 + .../lib/random_number_web/router.ex | 58 ++ .../lib/random_number_web/telemetry.ex | 48 ++ .../templates/layout/app.html.heex | 5 + .../templates/layout/live.html.heex | 11 + .../templates/layout/root.html.heex | 30 + .../templates/page/index.html.heex | 41 ++ .../random_number/random_number.html.heex | 1 + .../random_number_web/views/error_helpers.ex | 47 ++ .../lib/random_number_web/views/error_view.ex | 16 + .../random_number_web/views/layout_view.ex | 7 + .../lib/random_number_web/views/page_view.ex | 3 + .../views/random_number_view.ex | 3 + phoenix-1.6/random_number/mix.exs | 64 ++ phoenix-1.6/random_number/mix.lock | 29 + .../priv/gettext/en/LC_MESSAGES/errors.po | 11 + .../random_number/priv/gettext/errors.pot | 10 + .../random_number/priv/static/favicon.ico | Bin 0 -> 1258 bytes .../priv/static/images/phoenix.png | Bin 0 -> 13900 bytes .../random_number/priv/static/robots.txt | 5 + .../controllers/page_controller_test.exs | 8 + .../views/error_view_test.exs | 14 + .../views/layout_view_test.exs | 8 + .../views/page_view_test.exs | 3 + .../random_number/test/support/conn_case.ex | 37 + .../random_number/test/test_helper.exs | 1 + phoenix-1.7/counter/.formatter.exs | 5 + phoenix-1.7/counter/.gitignore | 37 + phoenix-1.7/counter/README.md | 18 + phoenix-1.7/counter/assets/css/app.css | 5 + phoenix-1.7/counter/assets/js/app.js | 41 ++ phoenix-1.7/counter/assets/tailwind.config.js | 67 ++ phoenix-1.7/counter/assets/vendor/topbar.js | 165 +++++ phoenix-1.7/counter/config/config.exs | 61 ++ phoenix-1.7/counter/config/dev.exs | 69 ++ phoenix-1.7/counter/config/prod.exs | 21 + phoenix-1.7/counter/config/runtime.exs | 100 +++ phoenix-1.7/counter/config/test.exs | 21 + phoenix-1.7/counter/lib/counter.ex | 9 + .../counter/lib/counter/application.ex | 36 + phoenix-1.7/counter/lib/counter/mailer.ex | 3 + phoenix-1.7/counter/lib/counter_web.ex | 113 +++ .../counter_web/components/core_components.ex | 689 ++++++++++++++++++ .../lib/counter_web/components/layouts.ex | 5 + .../components/layouts/app.html.heex | 43 ++ .../components/layouts/root.html.heex | 17 + .../lib/counter_web/controllers/error_html.ex | 19 + .../lib/counter_web/controllers/error_json.ex | 15 + .../controllers/page_controller.ex | 9 + .../lib/counter_web/controllers/page_html.ex | 5 + .../controllers/page_html/home.html.heex | 237 ++++++ .../counter/lib/counter_web/endpoint.ex | 50 ++ .../counter/lib/counter_web/gettext.ex | 24 + phoenix-1.7/counter/lib/counter_web/router.ex | 44 ++ .../counter/lib/counter_web/telemetry.ex | 69 ++ phoenix-1.7/counter/mix.exs | 67 ++ phoenix-1.7/counter/mix.lock | 36 + .../priv/gettext/en/LC_MESSAGES/errors.po | 11 + phoenix-1.7/counter/priv/gettext/errors.pot | 10 + .../counter/priv/hero_icons/LICENSE.md | 21 + .../counter/priv/hero_icons/UPGRADE.md | 7 + .../optimized/20/solid/academic-cap.svg | 3 + .../20/solid/adjustments-horizontal.svg | 3 + .../20/solid/adjustments-vertical.svg | 3 + .../20/solid/archive-box-arrow-down.svg | 3 + .../optimized/20/solid/archive-box-x-mark.svg | 4 + .../optimized/20/solid/archive-box.svg | 4 + .../optimized/20/solid/arrow-down-circle.svg | 3 + .../optimized/20/solid/arrow-down-left.svg | 3 + .../20/solid/arrow-down-on-square-stack.svg | 3 + .../20/solid/arrow-down-on-square.svg | 3 + .../optimized/20/solid/arrow-down-right.svg | 3 + .../optimized/20/solid/arrow-down-tray.svg | 4 + .../optimized/20/solid/arrow-down.svg | 3 + .../optimized/20/solid/arrow-left-circle.svg | 10 + .../20/solid/arrow-left-on-rectangle.svg | 4 + .../optimized/20/solid/arrow-left.svg | 3 + .../optimized/20/solid/arrow-long-down.svg | 3 + .../optimized/20/solid/arrow-long-left.svg | 3 + .../optimized/20/solid/arrow-long-right.svg | 3 + .../optimized/20/solid/arrow-long-up.svg | 3 + .../20/solid/arrow-path-rounded-square.svg | 3 + .../optimized/20/solid/arrow-path.svg | 3 + .../optimized/20/solid/arrow-right-circle.svg | 3 + .../20/solid/arrow-right-on-rectangle.svg | 4 + .../optimized/20/solid/arrow-right.svg | 3 + .../optimized/20/solid/arrow-small-down.svg | 3 + .../optimized/20/solid/arrow-small-left.svg | 3 + .../optimized/20/solid/arrow-small-right.svg | 3 + .../optimized/20/solid/arrow-small-up.svg | 3 + .../20/solid/arrow-top-right-on-square.svg | 4 + .../20/solid/arrow-trending-down.svg | 3 + .../optimized/20/solid/arrow-trending-up.svg | 3 + .../optimized/20/solid/arrow-up-circle.svg | 3 + .../optimized/20/solid/arrow-up-left.svg | 3 + .../20/solid/arrow-up-on-square-stack.svg | 3 + .../optimized/20/solid/arrow-up-on-square.svg | 3 + .../optimized/20/solid/arrow-up-right.svg | 3 + .../optimized/20/solid/arrow-up-tray.svg | 4 + .../optimized/20/solid/arrow-up.svg | 3 + .../optimized/20/solid/arrow-uturn-down.svg | 3 + .../optimized/20/solid/arrow-uturn-left.svg | 3 + .../optimized/20/solid/arrow-uturn-right.svg | 3 + .../optimized/20/solid/arrow-uturn-up.svg | 3 + .../optimized/20/solid/arrows-pointing-in.svg | 3 + .../20/solid/arrows-pointing-out.svg | 3 + .../optimized/20/solid/arrows-right-left.svg | 3 + .../optimized/20/solid/arrows-up-down.svg | 3 + .../optimized/20/solid/at-symbol.svg | 3 + .../optimized/20/solid/backspace.svg | 3 + .../optimized/20/solid/backward.svg | 3 + .../optimized/20/solid/banknotes.svg | 3 + .../hero_icons/optimized/20/solid/bars-2.svg | 3 + .../optimized/20/solid/bars-3-bottom-left.svg | 3 + .../20/solid/bars-3-bottom-right.svg | 3 + .../optimized/20/solid/bars-3-center-left.svg | 3 + .../hero_icons/optimized/20/solid/bars-3.svg | 3 + .../hero_icons/optimized/20/solid/bars-4.svg | 3 + .../optimized/20/solid/bars-arrow-down.svg | 3 + .../optimized/20/solid/bars-arrow-up.svg | 3 + .../optimized/20/solid/battery-0.svg | 3 + .../optimized/20/solid/battery-100.svg | 4 + .../optimized/20/solid/battery-50.svg | 4 + .../hero_icons/optimized/20/solid/beaker.svg | 3 + .../optimized/20/solid/bell-alert.svg | 4 + .../optimized/20/solid/bell-slash.svg | 3 + .../optimized/20/solid/bell-snooze.svg | 3 + .../hero_icons/optimized/20/solid/bell.svg | 3 + .../optimized/20/solid/bolt-slash.svg | 4 + .../hero_icons/optimized/20/solid/bolt.svg | 3 + .../optimized/20/solid/book-open.svg | 3 + .../optimized/20/solid/bookmark-slash.svg | 3 + .../optimized/20/solid/bookmark-square.svg | 3 + .../optimized/20/solid/bookmark.svg | 3 + .../optimized/20/solid/briefcase.svg | 4 + .../hero_icons/optimized/20/solid/bug-ant.svg | 3 + .../optimized/20/solid/building-library.svg | 3 + .../optimized/20/solid/building-office-2.svg | 3 + .../optimized/20/solid/building-office.svg | 3 + .../20/solid/building-storefront.svg | 3 + .../hero_icons/optimized/20/solid/cake.svg | 3 + .../optimized/20/solid/calculator.svg | 3 + .../optimized/20/solid/calendar-days.svg | 4 + .../optimized/20/solid/calendar.svg | 3 + .../hero_icons/optimized/20/solid/camera.svg | 3 + .../optimized/20/solid/chart-bar-square.svg | 3 + .../optimized/20/solid/chart-bar.svg | 3 + .../optimized/20/solid/chart-pie.svg | 4 + .../solid/chat-bubble-bottom-center-text.svg | 3 + .../20/solid/chat-bubble-bottom-center.svg | 3 + .../20/solid/chat-bubble-left-ellipsis.svg | 3 + .../20/solid/chat-bubble-left-right.svg | 4 + .../optimized/20/solid/chat-bubble-left.svg | 3 + .../solid/chat-bubble-oval-left-ellipsis.svg | 3 + .../20/solid/chat-bubble-oval-left.svg | 3 + .../optimized/20/solid/check-badge.svg | 3 + .../optimized/20/solid/check-circle.svg | 3 + .../hero_icons/optimized/20/solid/check.svg | 3 + .../20/solid/chevron-double-down.svg | 3 + .../20/solid/chevron-double-left.svg | 3 + .../20/solid/chevron-double-right.svg | 4 + .../optimized/20/solid/chevron-double-up.svg | 3 + .../optimized/20/solid/chevron-down.svg | 3 + .../optimized/20/solid/chevron-left.svg | 3 + .../optimized/20/solid/chevron-right.svg | 3 + .../optimized/20/solid/chevron-up-down.svg | 3 + .../optimized/20/solid/chevron-up.svg | 3 + .../optimized/20/solid/circle-stack.svg | 3 + .../20/solid/clipboard-document-check.svg | 4 + .../20/solid/clipboard-document-list.svg | 4 + .../optimized/20/solid/clipboard-document.svg | 4 + .../optimized/20/solid/clipboard.svg | 3 + .../hero_icons/optimized/20/solid/clock.svg | 3 + .../optimized/20/solid/cloud-arrow-down.svg | 3 + .../optimized/20/solid/cloud-arrow-up.svg | 3 + .../hero_icons/optimized/20/solid/cloud.svg | 3 + .../20/solid/code-bracket-square.svg | 3 + .../optimized/20/solid/code-bracket.svg | 3 + .../optimized/20/solid/cog-6-tooth.svg | 3 + .../optimized/20/solid/cog-8-tooth.svg | 3 + .../hero_icons/optimized/20/solid/cog.svg | 4 + .../optimized/20/solid/command-line.svg | 3 + .../optimized/20/solid/computer-desktop.svg | 3 + .../optimized/20/solid/cpu-chip.svg | 4 + .../optimized/20/solid/credit-card.svg | 3 + .../optimized/20/solid/cube-transparent.svg | 3 + .../hero_icons/optimized/20/solid/cube.svg | 3 + .../20/solid/currency-bangladeshi.svg | 3 + .../optimized/20/solid/currency-dollar.svg | 4 + .../optimized/20/solid/currency-euro.svg | 3 + .../optimized/20/solid/currency-pound.svg | 3 + .../optimized/20/solid/currency-rupee.svg | 3 + .../optimized/20/solid/currency-yen.svg | 3 + .../optimized/20/solid/cursor-arrow-rays.svg | 3 + .../20/solid/cursor-arrow-ripple.svg | 3 + .../20/solid/device-phone-mobile.svg | 4 + .../optimized/20/solid/device-tablet.svg | 3 + .../20/solid/document-arrow-down.svg | 3 + .../optimized/20/solid/document-arrow-up.svg | 3 + .../optimized/20/solid/document-chart-bar.svg | 3 + .../optimized/20/solid/document-check.svg | 3 + .../optimized/20/solid/document-duplicate.svg | 4 + .../20/solid/document-magnifying-glass.svg | 4 + .../optimized/20/solid/document-minus.svg | 3 + .../optimized/20/solid/document-plus.svg | 3 + .../optimized/20/solid/document-text.svg | 3 + .../optimized/20/solid/document.svg | 3 + .../20/solid/ellipsis-horizontal-circle.svg | 3 + .../20/solid/ellipsis-horizontal.svg | 3 + .../optimized/20/solid/ellipsis-vertical.svg | 3 + .../optimized/20/solid/envelope-open.svg | 3 + .../optimized/20/solid/envelope.svg | 4 + .../optimized/20/solid/exclamation-circle.svg | 3 + .../20/solid/exclamation-triangle.svg | 3 + .../optimized/20/solid/eye-dropper.svg | 3 + .../optimized/20/solid/eye-slash.svg | 4 + .../hero_icons/optimized/20/solid/eye.svg | 4 + .../optimized/20/solid/face-frown.svg | 3 + .../optimized/20/solid/face-smile.svg | 3 + .../hero_icons/optimized/20/solid/film.svg | 3 + .../optimized/20/solid/finger-print.svg | 3 + .../hero_icons/optimized/20/solid/fire.svg | 3 + .../hero_icons/optimized/20/solid/flag.svg | 3 + .../optimized/20/solid/folder-arrow-down.svg | 3 + .../optimized/20/solid/folder-minus.svg | 3 + .../optimized/20/solid/folder-open.svg | 3 + .../optimized/20/solid/folder-plus.svg | 3 + .../hero_icons/optimized/20/solid/folder.svg | 3 + .../hero_icons/optimized/20/solid/forward.svg | 3 + .../hero_icons/optimized/20/solid/funnel.svg | 3 + .../hero_icons/optimized/20/solid/gif.svg | 3 + .../optimized/20/solid/gift-top.svg | 3 + .../hero_icons/optimized/20/solid/gift.svg | 4 + .../optimized/20/solid/globe-alt.svg | 3 + .../optimized/20/solid/globe-americas.svg | 3 + .../20/solid/globe-asia-australia.svg | 3 + .../20/solid/globe-europe-africa.svg | 3 + .../optimized/20/solid/hand-raised.svg | 3 + .../optimized/20/solid/hand-thumb-down.svg | 3 + .../optimized/20/solid/hand-thumb-up.svg | 3 + .../hero_icons/optimized/20/solid/hashtag.svg | 3 + .../hero_icons/optimized/20/solid/heart.svg | 3 + .../optimized/20/solid/home-modern.svg | 3 + .../hero_icons/optimized/20/solid/home.svg | 3 + .../optimized/20/solid/identification.svg | 3 + .../optimized/20/solid/inbox-arrow-down.svg | 4 + .../optimized/20/solid/inbox-stack.svg | 4 + .../hero_icons/optimized/20/solid/inbox.svg | 3 + .../optimized/20/solid/information-circle.svg | 3 + .../hero_icons/optimized/20/solid/key.svg | 3 + .../optimized/20/solid/language.svg | 4 + .../optimized/20/solid/lifebuoy.svg | 3 + .../optimized/20/solid/light-bulb.svg | 3 + .../hero_icons/optimized/20/solid/link.svg | 4 + .../optimized/20/solid/list-bullet.svg | 3 + .../optimized/20/solid/lock-closed.svg | 3 + .../optimized/20/solid/lock-open.svg | 3 + .../20/solid/magnifying-glass-circle.svg | 4 + .../20/solid/magnifying-glass-minus.svg | 4 + .../20/solid/magnifying-glass-plus.svg | 4 + .../optimized/20/solid/magnifying-glass.svg | 3 + .../hero_icons/optimized/20/solid/map-pin.svg | 3 + .../hero_icons/optimized/20/solid/map.svg | 3 + .../optimized/20/solid/megaphone.svg | 3 + .../optimized/20/solid/microphone.svg | 4 + .../optimized/20/solid/minus-circle.svg | 3 + .../optimized/20/solid/minus-small.svg | 3 + .../hero_icons/optimized/20/solid/minus.svg | 3 + .../hero_icons/optimized/20/solid/moon.svg | 3 + .../optimized/20/solid/musical-note.svg | 3 + .../optimized/20/solid/newspaper.svg | 4 + .../optimized/20/solid/no-symbol.svg | 3 + .../optimized/20/solid/paint-brush.svg | 3 + .../optimized/20/solid/paper-airplane.svg | 3 + .../optimized/20/solid/paper-clip.svg | 3 + .../optimized/20/solid/pause-circle.svg | 3 + .../hero_icons/optimized/20/solid/pause.svg | 3 + .../optimized/20/solid/pencil-square.svg | 4 + .../hero_icons/optimized/20/solid/pencil.svg | 3 + .../20/solid/phone-arrow-down-left.svg | 3 + .../20/solid/phone-arrow-up-right.svg | 3 + .../optimized/20/solid/phone-x-mark.svg | 3 + .../hero_icons/optimized/20/solid/phone.svg | 3 + .../hero_icons/optimized/20/solid/photo.svg | 3 + .../optimized/20/solid/play-circle.svg | 3 + .../optimized/20/solid/play-pause.svg | 3 + .../hero_icons/optimized/20/solid/play.svg | 3 + .../optimized/20/solid/plus-circle.svg | 3 + .../optimized/20/solid/plus-small.svg | 3 + .../hero_icons/optimized/20/solid/plus.svg | 3 + .../hero_icons/optimized/20/solid/power.svg | 3 + .../20/solid/presentation-chart-bar.svg | 3 + .../20/solid/presentation-chart-line.svg | 3 + .../hero_icons/optimized/20/solid/printer.svg | 3 + .../optimized/20/solid/puzzle-piece.svg | 3 + .../hero_icons/optimized/20/solid/qr-code.svg | 3 + .../20/solid/question-mark-circle.svg | 3 + .../optimized/20/solid/queue-list.svg | 3 + .../hero_icons/optimized/20/solid/radio.svg | 3 + .../optimized/20/solid/receipt-percent.svg | 3 + .../optimized/20/solid/receipt-refund.svg | 3 + .../optimized/20/solid/rectangle-group.svg | 3 + .../optimized/20/solid/rectangle-stack.svg | 3 + .../optimized/20/solid/rocket-launch.svg | 4 + .../hero_icons/optimized/20/solid/rss.svg | 4 + .../hero_icons/optimized/20/solid/scale.svg | 3 + .../optimized/20/solid/scissors.svg | 4 + .../optimized/20/solid/server-stack.svg | 4 + .../hero_icons/optimized/20/solid/server.svg | 4 + .../hero_icons/optimized/20/solid/share.svg | 3 + .../optimized/20/solid/shield-check.svg | 3 + .../optimized/20/solid/shield-exclamation.svg | 3 + .../optimized/20/solid/shopping-bag.svg | 3 + .../optimized/20/solid/shopping-cart.svg | 3 + .../optimized/20/solid/signal-slash.svg | 3 + .../hero_icons/optimized/20/solid/signal.svg | 4 + .../optimized/20/solid/sparkles.svg | 3 + .../optimized/20/solid/speaker-wave.svg | 4 + .../optimized/20/solid/speaker-x-mark.svg | 3 + .../optimized/20/solid/square-2-stack.svg | 4 + .../optimized/20/solid/square-3-stack-3d.svg | 5 + .../optimized/20/solid/squares-2x2.svg | 3 + .../optimized/20/solid/squares-plus.svg | 3 + .../hero_icons/optimized/20/solid/star.svg | 3 + .../optimized/20/solid/stop-circle.svg | 3 + .../hero_icons/optimized/20/solid/stop.svg | 3 + .../hero_icons/optimized/20/solid/sun.svg | 3 + .../hero_icons/optimized/20/solid/swatch.svg | 3 + .../optimized/20/solid/table-cells.svg | 3 + .../hero_icons/optimized/20/solid/tag.svg | 3 + .../hero_icons/optimized/20/solid/ticket.svg | 3 + .../hero_icons/optimized/20/solid/trash.svg | 3 + .../hero_icons/optimized/20/solid/trophy.svg | 3 + .../hero_icons/optimized/20/solid/truck.svg | 4 + .../priv/hero_icons/optimized/20/solid/tv.svg | 4 + .../optimized/20/solid/user-circle.svg | 3 + .../optimized/20/solid/user-group.svg | 3 + .../optimized/20/solid/user-minus.svg | 3 + .../optimized/20/solid/user-plus.svg | 3 + .../hero_icons/optimized/20/solid/user.svg | 3 + .../hero_icons/optimized/20/solid/users.svg | 3 + .../optimized/20/solid/variable.svg | 3 + .../optimized/20/solid/video-camera-slash.svg | 3 + .../optimized/20/solid/video-camera.svg | 3 + .../optimized/20/solid/view-columns.svg | 3 + .../optimized/20/solid/viewfinder-circle.svg | 3 + .../hero_icons/optimized/20/solid/wallet.svg | 3 + .../hero_icons/optimized/20/solid/wifi.svg | 3 + .../hero_icons/optimized/20/solid/window.svg | 3 + .../optimized/20/solid/wrench-screwdriver.svg | 4 + .../hero_icons/optimized/20/solid/wrench.svg | 3 + .../optimized/20/solid/x-circle.svg | 3 + .../hero_icons/optimized/20/solid/x-mark.svg | 3 + .../optimized/24/outline/academic-cap.svg | 3 + .../24/outline/adjustments-horizontal.svg | 3 + .../24/outline/adjustments-vertical.svg | 3 + .../24/outline/archive-box-arrow-down.svg | 3 + .../24/outline/archive-box-x-mark.svg | 3 + .../optimized/24/outline/archive-box.svg | 3 + .../24/outline/arrow-down-circle.svg | 3 + .../optimized/24/outline/arrow-down-left.svg | 3 + .../24/outline/arrow-down-on-square-stack.svg | 3 + .../24/outline/arrow-down-on-square.svg | 3 + .../optimized/24/outline/arrow-down-right.svg | 3 + .../optimized/24/outline/arrow-down-tray.svg | 3 + .../optimized/24/outline/arrow-down.svg | 3 + .../24/outline/arrow-left-circle.svg | 3 + .../24/outline/arrow-left-on-rectangle.svg | 3 + .../optimized/24/outline/arrow-left.svg | 3 + .../optimized/24/outline/arrow-long-down.svg | 3 + .../optimized/24/outline/arrow-long-left.svg | 3 + .../optimized/24/outline/arrow-long-right.svg | 3 + .../optimized/24/outline/arrow-long-up.svg | 3 + .../24/outline/arrow-path-rounded-square.svg | 3 + .../optimized/24/outline/arrow-path.svg | 3 + .../24/outline/arrow-right-circle.svg | 3 + .../24/outline/arrow-right-on-rectangle.svg | 3 + .../optimized/24/outline/arrow-right.svg | 3 + .../optimized/24/outline/arrow-small-down.svg | 3 + .../optimized/24/outline/arrow-small-left.svg | 3 + .../24/outline/arrow-small-right.svg | 3 + .../optimized/24/outline/arrow-small-up.svg | 3 + .../24/outline/arrow-top-right-on-square.svg | 3 + .../24/outline/arrow-trending-down.svg | 3 + .../24/outline/arrow-trending-up.svg | 3 + .../optimized/24/outline/arrow-up-circle.svg | 3 + .../optimized/24/outline/arrow-up-left.svg | 3 + .../24/outline/arrow-up-on-square-stack.svg | 3 + .../24/outline/arrow-up-on-square.svg | 3 + .../optimized/24/outline/arrow-up-right.svg | 3 + .../optimized/24/outline/arrow-up-tray.svg | 3 + .../optimized/24/outline/arrow-up.svg | 3 + .../optimized/24/outline/arrow-uturn-down.svg | 3 + .../optimized/24/outline/arrow-uturn-left.svg | 3 + .../24/outline/arrow-uturn-right.svg | 3 + .../optimized/24/outline/arrow-uturn-up.svg | 3 + .../24/outline/arrows-pointing-in.svg | 3 + .../24/outline/arrows-pointing-out.svg | 3 + .../24/outline/arrows-right-left.svg | 3 + .../optimized/24/outline/arrows-up-down.svg | 3 + .../optimized/24/outline/at-symbol.svg | 3 + .../optimized/24/outline/backspace.svg | 3 + .../optimized/24/outline/backward.svg | 3 + .../optimized/24/outline/banknotes.svg | 3 + .../optimized/24/outline/bars-2.svg | 3 + .../24/outline/bars-3-bottom-left.svg | 3 + .../24/outline/bars-3-bottom-right.svg | 3 + .../24/outline/bars-3-center-left.svg | 3 + .../optimized/24/outline/bars-3.svg | 3 + .../optimized/24/outline/bars-4.svg | 3 + .../optimized/24/outline/bars-arrow-down.svg | 3 + .../optimized/24/outline/bars-arrow-up.svg | 3 + .../optimized/24/outline/battery-0.svg | 3 + .../optimized/24/outline/battery-100.svg | 3 + .../optimized/24/outline/battery-50.svg | 3 + .../optimized/24/outline/beaker.svg | 3 + .../optimized/24/outline/bell-alert.svg | 3 + .../optimized/24/outline/bell-slash.svg | 3 + .../optimized/24/outline/bell-snooze.svg | 3 + .../hero_icons/optimized/24/outline/bell.svg | 3 + .../optimized/24/outline/bolt-slash.svg | 3 + .../hero_icons/optimized/24/outline/bolt.svg | 3 + .../optimized/24/outline/book-open.svg | 3 + .../optimized/24/outline/bookmark-slash.svg | 3 + .../optimized/24/outline/bookmark-square.svg | 3 + .../optimized/24/outline/bookmark.svg | 3 + .../optimized/24/outline/briefcase.svg | 3 + .../optimized/24/outline/bug-ant.svg | 3 + .../optimized/24/outline/building-library.svg | 3 + .../24/outline/building-office-2.svg | 3 + .../optimized/24/outline/building-office.svg | 3 + .../24/outline/building-storefront.svg | 3 + .../hero_icons/optimized/24/outline/cake.svg | 3 + .../optimized/24/outline/calculator.svg | 3 + .../optimized/24/outline/calendar-days.svg | 3 + .../optimized/24/outline/calendar.svg | 3 + .../optimized/24/outline/camera.svg | 4 + .../optimized/24/outline/chart-bar-square.svg | 3 + .../optimized/24/outline/chart-bar.svg | 3 + .../optimized/24/outline/chart-pie.svg | 4 + .../chat-bubble-bottom-center-text.svg | 3 + .../24/outline/chat-bubble-bottom-center.svg | 3 + .../24/outline/chat-bubble-left-ellipsis.svg | 3 + .../24/outline/chat-bubble-left-right.svg | 3 + .../optimized/24/outline/chat-bubble-left.svg | 3 + .../chat-bubble-oval-left-ellipsis.svg | 3 + .../24/outline/chat-bubble-oval-left.svg | 3 + .../optimized/24/outline/check-badge.svg | 3 + .../optimized/24/outline/check-circle.svg | 3 + .../hero_icons/optimized/24/outline/check.svg | 3 + .../24/outline/chevron-double-down.svg | 3 + .../24/outline/chevron-double-left.svg | 3 + .../24/outline/chevron-double-right.svg | 3 + .../24/outline/chevron-double-up.svg | 3 + .../optimized/24/outline/chevron-down.svg | 3 + .../optimized/24/outline/chevron-left.svg | 3 + .../optimized/24/outline/chevron-right.svg | 3 + .../optimized/24/outline/chevron-up-down.svg | 3 + .../optimized/24/outline/chevron-up.svg | 3 + .../optimized/24/outline/circle-stack.svg | 3 + .../24/outline/clipboard-document-check.svg | 3 + .../24/outline/clipboard-document-list.svg | 3 + .../24/outline/clipboard-document.svg | 3 + .../optimized/24/outline/clipboard.svg | 3 + .../hero_icons/optimized/24/outline/clock.svg | 3 + .../optimized/24/outline/cloud-arrow-down.svg | 3 + .../optimized/24/outline/cloud-arrow-up.svg | 3 + .../hero_icons/optimized/24/outline/cloud.svg | 3 + .../24/outline/code-bracket-square.svg | 3 + .../optimized/24/outline/code-bracket.svg | 3 + .../optimized/24/outline/cog-6-tooth.svg | 4 + .../optimized/24/outline/cog-8-tooth.svg | 4 + .../hero_icons/optimized/24/outline/cog.svg | 3 + .../optimized/24/outline/command-line.svg | 3 + .../optimized/24/outline/computer-desktop.svg | 3 + .../optimized/24/outline/cpu-chip.svg | 3 + .../optimized/24/outline/credit-card.svg | 3 + .../optimized/24/outline/cube-transparent.svg | 3 + .../hero_icons/optimized/24/outline/cube.svg | 3 + .../24/outline/currency-bangladeshi.svg | 3 + .../optimized/24/outline/currency-dollar.svg | 3 + .../optimized/24/outline/currency-euro.svg | 3 + .../optimized/24/outline/currency-pound.svg | 3 + .../optimized/24/outline/currency-rupee.svg | 3 + .../optimized/24/outline/currency-yen.svg | 3 + .../24/outline/cursor-arrow-rays.svg | 3 + .../24/outline/cursor-arrow-ripple.svg | 3 + .../24/outline/device-phone-mobile.svg | 3 + .../optimized/24/outline/device-tablet.svg | 3 + .../24/outline/document-arrow-down.svg | 3 + .../24/outline/document-arrow-up.svg | 3 + .../24/outline/document-chart-bar.svg | 3 + .../optimized/24/outline/document-check.svg | 3 + .../24/outline/document-duplicate.svg | 3 + .../24/outline/document-magnifying-glass.svg | 3 + .../optimized/24/outline/document-minus.svg | 3 + .../optimized/24/outline/document-plus.svg | 3 + .../optimized/24/outline/document-text.svg | 3 + .../optimized/24/outline/document.svg | 3 + .../24/outline/ellipsis-horizontal-circle.svg | 3 + .../24/outline/ellipsis-horizontal.svg | 3 + .../24/outline/ellipsis-vertical.svg | 3 + .../optimized/24/outline/envelope-open.svg | 3 + .../optimized/24/outline/envelope.svg | 3 + .../24/outline/exclamation-circle.svg | 3 + .../24/outline/exclamation-triangle.svg | 3 + .../optimized/24/outline/eye-dropper.svg | 3 + .../optimized/24/outline/eye-slash.svg | 3 + .../hero_icons/optimized/24/outline/eye.svg | 4 + .../optimized/24/outline/face-frown.svg | 3 + .../optimized/24/outline/face-smile.svg | 3 + .../hero_icons/optimized/24/outline/film.svg | 3 + .../optimized/24/outline/finger-print.svg | 3 + .../hero_icons/optimized/24/outline/fire.svg | 4 + .../hero_icons/optimized/24/outline/flag.svg | 3 + .../24/outline/folder-arrow-down.svg | 3 + .../optimized/24/outline/folder-minus.svg | 3 + .../optimized/24/outline/folder-open.svg | 3 + .../optimized/24/outline/folder-plus.svg | 3 + .../optimized/24/outline/folder.svg | 3 + .../optimized/24/outline/forward.svg | 3 + .../optimized/24/outline/funnel.svg | 3 + .../hero_icons/optimized/24/outline/gif.svg | 3 + .../optimized/24/outline/gift-top.svg | 3 + .../hero_icons/optimized/24/outline/gift.svg | 3 + .../optimized/24/outline/globe-alt.svg | 3 + .../optimized/24/outline/globe-americas.svg | 3 + .../24/outline/globe-asia-australia.svg | 3 + .../24/outline/globe-europe-africa.svg | 3 + .../optimized/24/outline/hand-raised.svg | 3 + .../optimized/24/outline/hand-thumb-down.svg | 3 + .../optimized/24/outline/hand-thumb-up.svg | 3 + .../optimized/24/outline/hashtag.svg | 3 + .../hero_icons/optimized/24/outline/heart.svg | 3 + .../optimized/24/outline/home-modern.svg | 3 + .../hero_icons/optimized/24/outline/home.svg | 3 + .../optimized/24/outline/identification.svg | 3 + .../optimized/24/outline/inbox-arrow-down.svg | 3 + .../optimized/24/outline/inbox-stack.svg | 3 + .../hero_icons/optimized/24/outline/inbox.svg | 3 + .../24/outline/information-circle.svg | 3 + .../hero_icons/optimized/24/outline/key.svg | 3 + .../optimized/24/outline/language.svg | 3 + .../optimized/24/outline/lifebuoy.svg | 3 + .../optimized/24/outline/light-bulb.svg | 3 + .../hero_icons/optimized/24/outline/link.svg | 3 + .../optimized/24/outline/list-bullet.svg | 3 + .../optimized/24/outline/lock-closed.svg | 3 + .../optimized/24/outline/lock-open.svg | 3 + .../24/outline/magnifying-glass-circle.svg | 3 + .../24/outline/magnifying-glass-minus.svg | 3 + .../24/outline/magnifying-glass-plus.svg | 3 + .../optimized/24/outline/magnifying-glass.svg | 3 + .../optimized/24/outline/map-pin.svg | 4 + .../hero_icons/optimized/24/outline/map.svg | 3 + .../optimized/24/outline/megaphone.svg | 3 + .../optimized/24/outline/microphone.svg | 3 + .../optimized/24/outline/minus-circle.svg | 3 + .../optimized/24/outline/minus-small.svg | 3 + .../hero_icons/optimized/24/outline/minus.svg | 3 + .../hero_icons/optimized/24/outline/moon.svg | 3 + .../optimized/24/outline/musical-note.svg | 3 + .../optimized/24/outline/newspaper.svg | 3 + .../optimized/24/outline/no-symbol.svg | 3 + .../optimized/24/outline/paint-brush.svg | 3 + .../optimized/24/outline/paper-airplane.svg | 3 + .../optimized/24/outline/paper-clip.svg | 3 + .../optimized/24/outline/pause-circle.svg | 3 + .../hero_icons/optimized/24/outline/pause.svg | 3 + .../optimized/24/outline/pencil-square.svg | 3 + .../optimized/24/outline/pencil.svg | 3 + .../24/outline/phone-arrow-down-left.svg | 3 + .../24/outline/phone-arrow-up-right.svg | 3 + .../optimized/24/outline/phone-x-mark.svg | 3 + .../hero_icons/optimized/24/outline/phone.svg | 3 + .../hero_icons/optimized/24/outline/photo.svg | 3 + .../optimized/24/outline/play-circle.svg | 4 + .../optimized/24/outline/play-pause.svg | 3 + .../hero_icons/optimized/24/outline/play.svg | 3 + .../optimized/24/outline/plus-circle.svg | 3 + .../optimized/24/outline/plus-small.svg | 3 + .../hero_icons/optimized/24/outline/plus.svg | 3 + .../hero_icons/optimized/24/outline/power.svg | 3 + .../24/outline/presentation-chart-bar.svg | 3 + .../24/outline/presentation-chart-line.svg | 3 + .../optimized/24/outline/printer.svg | 3 + .../optimized/24/outline/puzzle-piece.svg | 3 + .../optimized/24/outline/qr-code.svg | 4 + .../24/outline/question-mark-circle.svg | 3 + .../optimized/24/outline/queue-list.svg | 3 + .../hero_icons/optimized/24/outline/radio.svg | 3 + .../optimized/24/outline/receipt-percent.svg | 3 + .../optimized/24/outline/receipt-refund.svg | 3 + .../optimized/24/outline/rectangle-group.svg | 3 + .../optimized/24/outline/rectangle-stack.svg | 3 + .../optimized/24/outline/rocket-launch.svg | 3 + .../hero_icons/optimized/24/outline/rss.svg | 3 + .../hero_icons/optimized/24/outline/scale.svg | 3 + .../optimized/24/outline/scissors.svg | 3 + .../optimized/24/outline/server-stack.svg | 3 + .../optimized/24/outline/server.svg | 3 + .../hero_icons/optimized/24/outline/share.svg | 3 + .../optimized/24/outline/shield-check.svg | 3 + .../24/outline/shield-exclamation.svg | 3 + .../optimized/24/outline/shopping-bag.svg | 3 + .../optimized/24/outline/shopping-cart.svg | 3 + .../optimized/24/outline/signal-slash.svg | 3 + .../optimized/24/outline/signal.svg | 3 + .../optimized/24/outline/sparkles.svg | 3 + .../optimized/24/outline/speaker-wave.svg | 3 + .../optimized/24/outline/speaker-x-mark.svg | 3 + .../optimized/24/outline/square-2-stack.svg | 3 + .../24/outline/square-3-stack-3d.svg | 3 + .../optimized/24/outline/squares-2x2.svg | 3 + .../optimized/24/outline/squares-plus.svg | 3 + .../hero_icons/optimized/24/outline/star.svg | 3 + .../optimized/24/outline/stop-circle.svg | 4 + .../hero_icons/optimized/24/outline/stop.svg | 3 + .../hero_icons/optimized/24/outline/sun.svg | 3 + .../optimized/24/outline/swatch.svg | 3 + .../optimized/24/outline/table-cells.svg | 3 + .../hero_icons/optimized/24/outline/tag.svg | 4 + .../optimized/24/outline/ticket.svg | 3 + .../hero_icons/optimized/24/outline/trash.svg | 3 + .../optimized/24/outline/trophy.svg | 3 + .../hero_icons/optimized/24/outline/truck.svg | 3 + .../hero_icons/optimized/24/outline/tv.svg | 3 + .../optimized/24/outline/user-circle.svg | 3 + .../optimized/24/outline/user-group.svg | 3 + .../optimized/24/outline/user-minus.svg | 3 + .../optimized/24/outline/user-plus.svg | 3 + .../hero_icons/optimized/24/outline/user.svg | 3 + .../hero_icons/optimized/24/outline/users.svg | 3 + .../optimized/24/outline/variable.svg | 3 + .../24/outline/video-camera-slash.svg | 3 + .../optimized/24/outline/video-camera.svg | 3 + .../optimized/24/outline/view-columns.svg | 3 + .../24/outline/viewfinder-circle.svg | 3 + .../optimized/24/outline/wallet.svg | 3 + .../hero_icons/optimized/24/outline/wifi.svg | 3 + .../optimized/24/outline/window.svg | 3 + .../24/outline/wrench-screwdriver.svg | 3 + .../optimized/24/outline/wrench.svg | 4 + .../optimized/24/outline/x-circle.svg | 3 + .../optimized/24/outline/x-mark.svg | 3 + .../optimized/24/solid/academic-cap.svg | 5 + .../24/solid/adjustments-horizontal.svg | 3 + .../24/solid/adjustments-vertical.svg | 3 + .../24/solid/archive-box-arrow-down.svg | 4 + .../optimized/24/solid/archive-box-x-mark.svg | 4 + .../optimized/24/solid/archive-box.svg | 4 + .../optimized/24/solid/arrow-down-circle.svg | 3 + .../optimized/24/solid/arrow-down-left.svg | 3 + .../24/solid/arrow-down-on-square-stack.svg | 4 + .../24/solid/arrow-down-on-square.svg | 3 + .../optimized/24/solid/arrow-down-right.svg | 3 + .../optimized/24/solid/arrow-down-tray.svg | 3 + .../optimized/24/solid/arrow-down.svg | 3 + .../optimized/24/solid/arrow-left-circle.svg | 3 + .../24/solid/arrow-left-on-rectangle.svg | 3 + .../optimized/24/solid/arrow-left.svg | 3 + .../optimized/24/solid/arrow-long-down.svg | 3 + .../optimized/24/solid/arrow-long-left.svg | 3 + .../optimized/24/solid/arrow-long-right.svg | 3 + .../optimized/24/solid/arrow-long-up.svg | 3 + .../24/solid/arrow-path-rounded-square.svg | 3 + .../optimized/24/solid/arrow-path.svg | 3 + .../optimized/24/solid/arrow-right-circle.svg | 3 + .../24/solid/arrow-right-on-rectangle.svg | 3 + .../optimized/24/solid/arrow-right.svg | 3 + .../optimized/24/solid/arrow-small-down.svg | 3 + .../optimized/24/solid/arrow-small-left.svg | 3 + .../optimized/24/solid/arrow-small-right.svg | 3 + .../optimized/24/solid/arrow-small-up.svg | 3 + .../24/solid/arrow-top-right-on-square.svg | 3 + .../24/solid/arrow-trending-down.svg | 3 + .../optimized/24/solid/arrow-trending-up.svg | 3 + .../optimized/24/solid/arrow-up-circle.svg | 3 + .../optimized/24/solid/arrow-up-left.svg | 3 + .../24/solid/arrow-up-on-square-stack.svg | 4 + .../optimized/24/solid/arrow-up-on-square.svg | 3 + .../optimized/24/solid/arrow-up-right.svg | 3 + .../optimized/24/solid/arrow-up-tray.svg | 3 + .../optimized/24/solid/arrow-up.svg | 3 + .../optimized/24/solid/arrow-uturn-down.svg | 3 + .../optimized/24/solid/arrow-uturn-left.svg | 3 + .../optimized/24/solid/arrow-uturn-right.svg | 3 + .../optimized/24/solid/arrow-uturn-up.svg | 3 + .../optimized/24/solid/arrows-pointing-in.svg | 3 + .../24/solid/arrows-pointing-out.svg | 3 + .../optimized/24/solid/arrows-right-left.svg | 3 + .../optimized/24/solid/arrows-up-down.svg | 3 + .../optimized/24/solid/at-symbol.svg | 3 + .../optimized/24/solid/backspace.svg | 3 + .../optimized/24/solid/backward.svg | 3 + .../optimized/24/solid/banknotes.svg | 5 + .../hero_icons/optimized/24/solid/bars-2.svg | 3 + .../optimized/24/solid/bars-3-bottom-left.svg | 3 + .../24/solid/bars-3-bottom-right.svg | 3 + .../optimized/24/solid/bars-3-center-left.svg | 3 + .../hero_icons/optimized/24/solid/bars-3.svg | 3 + .../hero_icons/optimized/24/solid/bars-4.svg | 3 + .../optimized/24/solid/bars-arrow-down.svg | 3 + .../optimized/24/solid/bars-arrow-up.svg | 3 + .../optimized/24/solid/battery-0.svg | 3 + .../optimized/24/solid/battery-100.svg | 3 + .../optimized/24/solid/battery-50.svg | 4 + .../hero_icons/optimized/24/solid/beaker.svg | 3 + .../optimized/24/solid/bell-alert.svg | 4 + .../optimized/24/solid/bell-slash.svg | 4 + .../optimized/24/solid/bell-snooze.svg | 3 + .../hero_icons/optimized/24/solid/bell.svg | 3 + .../optimized/24/solid/bolt-slash.svg | 3 + .../hero_icons/optimized/24/solid/bolt.svg | 3 + .../optimized/24/solid/book-open.svg | 3 + .../optimized/24/solid/bookmark-slash.svg | 3 + .../optimized/24/solid/bookmark-square.svg | 3 + .../optimized/24/solid/bookmark.svg | 3 + .../optimized/24/solid/briefcase.svg | 4 + .../hero_icons/optimized/24/solid/bug-ant.svg | 3 + .../optimized/24/solid/building-library.svg | 5 + .../optimized/24/solid/building-office-2.svg | 3 + .../optimized/24/solid/building-office.svg | 3 + .../24/solid/building-storefront.svg | 4 + .../hero_icons/optimized/24/solid/cake.svg | 3 + .../optimized/24/solid/calculator.svg | 3 + .../optimized/24/solid/calendar-days.svg | 4 + .../optimized/24/solid/calendar.svg | 3 + .../hero_icons/optimized/24/solid/camera.svg | 4 + .../optimized/24/solid/chart-bar-square.svg | 3 + .../optimized/24/solid/chart-bar.svg | 3 + .../optimized/24/solid/chart-pie.svg | 4 + .../solid/chat-bubble-bottom-center-text.svg | 3 + .../24/solid/chat-bubble-bottom-center.svg | 3 + .../24/solid/chat-bubble-left-ellipsis.svg | 3 + .../24/solid/chat-bubble-left-right.svg | 4 + .../optimized/24/solid/chat-bubble-left.svg | 3 + .../solid/chat-bubble-oval-left-ellipsis.svg | 3 + .../24/solid/chat-bubble-oval-left.svg | 3 + .../optimized/24/solid/check-badge.svg | 3 + .../optimized/24/solid/check-circle.svg | 3 + .../hero_icons/optimized/24/solid/check.svg | 3 + .../24/solid/chevron-double-down.svg | 3 + .../24/solid/chevron-double-left.svg | 3 + .../24/solid/chevron-double-right.svg | 3 + .../optimized/24/solid/chevron-double-up.svg | 3 + .../optimized/24/solid/chevron-down.svg | 3 + .../optimized/24/solid/chevron-left.svg | 3 + .../optimized/24/solid/chevron-right.svg | 3 + .../optimized/24/solid/chevron-up-down.svg | 3 + .../optimized/24/solid/chevron-up.svg | 3 + .../optimized/24/solid/circle-stack.svg | 6 + .../24/solid/clipboard-document-check.svg | 4 + .../24/solid/clipboard-document-list.svg | 4 + .../optimized/24/solid/clipboard-document.svg | 5 + .../optimized/24/solid/clipboard.svg | 3 + .../hero_icons/optimized/24/solid/clock.svg | 3 + .../optimized/24/solid/cloud-arrow-down.svg | 3 + .../optimized/24/solid/cloud-arrow-up.svg | 3 + .../hero_icons/optimized/24/solid/cloud.svg | 3 + .../24/solid/code-bracket-square.svg | 3 + .../optimized/24/solid/code-bracket.svg | 3 + .../optimized/24/solid/cog-6-tooth.svg | 3 + .../optimized/24/solid/cog-8-tooth.svg | 3 + .../hero_icons/optimized/24/solid/cog.svg | 4 + .../optimized/24/solid/command-line.svg | 3 + .../optimized/24/solid/computer-desktop.svg | 3 + .../optimized/24/solid/cpu-chip.svg | 4 + .../optimized/24/solid/credit-card.svg | 4 + .../optimized/24/solid/cube-transparent.svg | 3 + .../hero_icons/optimized/24/solid/cube.svg | 3 + .../24/solid/currency-bangladeshi.svg | 3 + .../optimized/24/solid/currency-dollar.svg | 4 + .../optimized/24/solid/currency-euro.svg | 3 + .../optimized/24/solid/currency-pound.svg | 3 + .../optimized/24/solid/currency-rupee.svg | 3 + .../optimized/24/solid/currency-yen.svg | 3 + .../optimized/24/solid/cursor-arrow-rays.svg | 3 + .../24/solid/cursor-arrow-ripple.svg | 3 + .../24/solid/device-phone-mobile.svg | 4 + .../optimized/24/solid/device-tablet.svg | 4 + .../24/solid/document-arrow-down.svg | 4 + .../optimized/24/solid/document-arrow-up.svg | 4 + .../optimized/24/solid/document-chart-bar.svg | 4 + .../optimized/24/solid/document-check.svg | 4 + .../optimized/24/solid/document-duplicate.svg | 4 + .../24/solid/document-magnifying-glass.svg | 5 + .../optimized/24/solid/document-minus.svg | 4 + .../optimized/24/solid/document-plus.svg | 4 + .../optimized/24/solid/document-text.svg | 4 + .../optimized/24/solid/document.svg | 4 + .../24/solid/ellipsis-horizontal-circle.svg | 3 + .../24/solid/ellipsis-horizontal.svg | 3 + .../optimized/24/solid/ellipsis-vertical.svg | 3 + .../optimized/24/solid/envelope-open.svg | 4 + .../optimized/24/solid/envelope.svg | 4 + .../optimized/24/solid/exclamation-circle.svg | 3 + .../24/solid/exclamation-triangle.svg | 3 + .../optimized/24/solid/eye-dropper.svg | 3 + .../optimized/24/solid/eye-slash.svg | 5 + .../hero_icons/optimized/24/solid/eye.svg | 4 + .../optimized/24/solid/face-frown.svg | 3 + .../optimized/24/solid/face-smile.svg | 3 + .../hero_icons/optimized/24/solid/film.svg | 3 + .../optimized/24/solid/finger-print.svg | 3 + .../hero_icons/optimized/24/solid/fire.svg | 3 + .../hero_icons/optimized/24/solid/flag.svg | 3 + .../optimized/24/solid/folder-arrow-down.svg | 3 + .../optimized/24/solid/folder-minus.svg | 3 + .../optimized/24/solid/folder-open.svg | 3 + .../optimized/24/solid/folder-plus.svg | 3 + .../hero_icons/optimized/24/solid/folder.svg | 3 + .../hero_icons/optimized/24/solid/forward.svg | 3 + .../hero_icons/optimized/24/solid/funnel.svg | 3 + .../hero_icons/optimized/24/solid/gif.svg | 3 + .../optimized/24/solid/gift-top.svg | 4 + .../hero_icons/optimized/24/solid/gift.svg | 3 + .../optimized/24/solid/globe-alt.svg | 3 + .../optimized/24/solid/globe-americas.svg | 3 + .../24/solid/globe-asia-australia.svg | 4 + .../24/solid/globe-europe-africa.svg | 3 + .../optimized/24/solid/hand-raised.svg | 3 + .../optimized/24/solid/hand-thumb-down.svg | 3 + .../optimized/24/solid/hand-thumb-up.svg | 3 + .../hero_icons/optimized/24/solid/hashtag.svg | 3 + .../hero_icons/optimized/24/solid/heart.svg | 3 + .../optimized/24/solid/home-modern.svg | 4 + .../hero_icons/optimized/24/solid/home.svg | 4 + .../optimized/24/solid/identification.svg | 3 + .../optimized/24/solid/inbox-arrow-down.svg | 4 + .../optimized/24/solid/inbox-stack.svg | 4 + .../hero_icons/optimized/24/solid/inbox.svg | 3 + .../optimized/24/solid/information-circle.svg | 3 + .../hero_icons/optimized/24/solid/key.svg | 3 + .../optimized/24/solid/language.svg | 3 + .../optimized/24/solid/lifebuoy.svg | 3 + .../optimized/24/solid/light-bulb.svg | 4 + .../hero_icons/optimized/24/solid/link.svg | 3 + .../optimized/24/solid/list-bullet.svg | 3 + .../optimized/24/solid/lock-closed.svg | 3 + .../optimized/24/solid/lock-open.svg | 3 + .../24/solid/magnifying-glass-circle.svg | 4 + .../24/solid/magnifying-glass-minus.svg | 3 + .../24/solid/magnifying-glass-plus.svg | 3 + .../optimized/24/solid/magnifying-glass.svg | 3 + .../hero_icons/optimized/24/solid/map-pin.svg | 3 + .../hero_icons/optimized/24/solid/map.svg | 3 + .../optimized/24/solid/megaphone.svg | 3 + .../optimized/24/solid/microphone.svg | 4 + .../optimized/24/solid/minus-circle.svg | 3 + .../optimized/24/solid/minus-small.svg | 3 + .../hero_icons/optimized/24/solid/minus.svg | 3 + .../hero_icons/optimized/24/solid/moon.svg | 3 + .../optimized/24/solid/musical-note.svg | 3 + .../optimized/24/solid/newspaper.svg | 4 + .../optimized/24/solid/no-symbol.svg | 3 + .../optimized/24/solid/paint-brush.svg | 3 + .../optimized/24/solid/paper-airplane.svg | 3 + .../optimized/24/solid/paper-clip.svg | 3 + .../optimized/24/solid/pause-circle.svg | 3 + .../hero_icons/optimized/24/solid/pause.svg | 3 + .../optimized/24/solid/pencil-square.svg | 4 + .../hero_icons/optimized/24/solid/pencil.svg | 3 + .../24/solid/phone-arrow-down-left.svg | 4 + .../24/solid/phone-arrow-up-right.svg | 4 + .../optimized/24/solid/phone-x-mark.svg | 3 + .../hero_icons/optimized/24/solid/phone.svg | 3 + .../hero_icons/optimized/24/solid/photo.svg | 3 + .../optimized/24/solid/play-circle.svg | 3 + .../optimized/24/solid/play-pause.svg | 3 + .../hero_icons/optimized/24/solid/play.svg | 3 + .../optimized/24/solid/plus-circle.svg | 3 + .../optimized/24/solid/plus-small.svg | 3 + .../hero_icons/optimized/24/solid/plus.svg | 3 + .../hero_icons/optimized/24/solid/power.svg | 3 + .../24/solid/presentation-chart-bar.svg | 3 + .../24/solid/presentation-chart-line.svg | 3 + .../hero_icons/optimized/24/solid/printer.svg | 3 + .../optimized/24/solid/puzzle-piece.svg | 3 + .../hero_icons/optimized/24/solid/qr-code.svg | 3 + .../24/solid/question-mark-circle.svg | 3 + .../optimized/24/solid/queue-list.svg | 3 + .../hero_icons/optimized/24/solid/radio.svg | 3 + .../optimized/24/solid/receipt-percent.svg | 3 + .../optimized/24/solid/receipt-refund.svg | 3 + .../optimized/24/solid/rectangle-group.svg | 3 + .../optimized/24/solid/rectangle-stack.svg | 3 + .../optimized/24/solid/rocket-launch.svg | 4 + .../hero_icons/optimized/24/solid/rss.svg | 3 + .../hero_icons/optimized/24/solid/scale.svg | 3 + .../optimized/24/solid/scissors.svg | 4 + .../optimized/24/solid/server-stack.svg | 4 + .../hero_icons/optimized/24/solid/server.svg | 4 + .../hero_icons/optimized/24/solid/share.svg | 3 + .../optimized/24/solid/shield-check.svg | 3 + .../optimized/24/solid/shield-exclamation.svg | 3 + .../optimized/24/solid/shopping-bag.svg | 3 + .../optimized/24/solid/shopping-cart.svg | 3 + .../optimized/24/solid/signal-slash.svg | 3 + .../hero_icons/optimized/24/solid/signal.svg | 3 + .../optimized/24/solid/sparkles.svg | 3 + .../optimized/24/solid/speaker-wave.svg | 4 + .../optimized/24/solid/speaker-x-mark.svg | 3 + .../optimized/24/solid/square-2-stack.svg | 4 + .../optimized/24/solid/square-3-stack-3d.svg | 5 + .../optimized/24/solid/squares-2x2.svg | 3 + .../optimized/24/solid/squares-plus.svg | 3 + .../hero_icons/optimized/24/solid/star.svg | 3 + .../optimized/24/solid/stop-circle.svg | 3 + .../hero_icons/optimized/24/solid/stop.svg | 3 + .../hero_icons/optimized/24/solid/sun.svg | 3 + .../hero_icons/optimized/24/solid/swatch.svg | 4 + .../optimized/24/solid/table-cells.svg | 3 + .../hero_icons/optimized/24/solid/tag.svg | 3 + .../hero_icons/optimized/24/solid/ticket.svg | 3 + .../hero_icons/optimized/24/solid/trash.svg | 3 + .../hero_icons/optimized/24/solid/trophy.svg | 3 + .../hero_icons/optimized/24/solid/truck.svg | 5 + .../priv/hero_icons/optimized/24/solid/tv.svg | 4 + .../optimized/24/solid/user-circle.svg | 3 + .../optimized/24/solid/user-group.svg | 4 + .../optimized/24/solid/user-minus.svg | 3 + .../optimized/24/solid/user-plus.svg | 3 + .../hero_icons/optimized/24/solid/user.svg | 3 + .../hero_icons/optimized/24/solid/users.svg | 3 + .../optimized/24/solid/variable.svg | 3 + .../optimized/24/solid/video-camera-slash.svg | 3 + .../optimized/24/solid/video-camera.svg | 3 + .../optimized/24/solid/view-columns.svg | 3 + .../optimized/24/solid/viewfinder-circle.svg | 3 + .../hero_icons/optimized/24/solid/wallet.svg | 3 + .../hero_icons/optimized/24/solid/wifi.svg | 3 + .../hero_icons/optimized/24/solid/window.svg | 3 + .../optimized/24/solid/wrench-screwdriver.svg | 5 + .../hero_icons/optimized/24/solid/wrench.svg | 3 + .../optimized/24/solid/x-circle.svg | 3 + .../hero_icons/optimized/24/solid/x-mark.svg | 3 + phoenix-1.7/counter/priv/static/favicon.ico | Bin 0 -> 1258 bytes phoenix-1.7/counter/priv/static/robots.txt | 5 + .../controllers/error_html_test.exs | 14 + .../controllers/error_json_test.exs | 12 + .../controllers/page_controller_test.exs | 8 + phoenix-1.7/counter/test/support/conn_case.ex | 37 + phoenix-1.7/counter/test/test_helper.exs | 1 + progress.json | 2 +- 1104 files changed, 10781 insertions(+), 1 deletion(-) create mode 100644 phoenix-1.6/counter/.formatter.exs create mode 100644 phoenix-1.6/counter/.gitignore create mode 100644 phoenix-1.6/counter/README.md create mode 100644 phoenix-1.6/counter/assets/css/app.css create mode 100644 phoenix-1.6/counter/assets/css/phoenix.css create mode 100644 phoenix-1.6/counter/assets/js/app.js create mode 100644 phoenix-1.6/counter/assets/vendor/topbar.js create mode 100644 phoenix-1.6/counter/config/config.exs create mode 100644 phoenix-1.6/counter/config/dev.exs create mode 100644 phoenix-1.6/counter/config/prod.exs create mode 100644 phoenix-1.6/counter/config/runtime.exs create mode 100644 phoenix-1.6/counter/config/test.exs create mode 100644 phoenix-1.6/counter/lib/counter.ex create mode 100644 phoenix-1.6/counter/lib/counter/application.ex create mode 100644 phoenix-1.6/counter/lib/counter/mailer.ex create mode 100644 phoenix-1.6/counter/lib/counter_web.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/controllers/count_controller.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/controllers/page_controller.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/endpoint.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/gettext.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/router.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/telemetry.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/templates/count/count.html.heex create mode 100644 phoenix-1.6/counter/lib/counter_web/templates/layout/app.html.heex create mode 100644 phoenix-1.6/counter/lib/counter_web/templates/layout/live.html.heex create mode 100644 phoenix-1.6/counter/lib/counter_web/templates/layout/root.html.heex create mode 100644 phoenix-1.6/counter/lib/counter_web/templates/page/index.html.heex create mode 100644 phoenix-1.6/counter/lib/counter_web/views/count_view.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/views/error_helpers.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/views/error_view.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/views/layout_view.ex create mode 100644 phoenix-1.6/counter/lib/counter_web/views/page_view.ex create mode 100644 phoenix-1.6/counter/mix.exs create mode 100644 phoenix-1.6/counter/mix.lock create mode 100644 phoenix-1.6/counter/priv/gettext/en/LC_MESSAGES/errors.po create mode 100644 phoenix-1.6/counter/priv/gettext/errors.pot create mode 100644 phoenix-1.6/counter/priv/static/favicon.ico create mode 100644 phoenix-1.6/counter/priv/static/images/phoenix.png create mode 100644 phoenix-1.6/counter/priv/static/robots.txt create mode 100644 phoenix-1.6/counter/test/counter_web/controllers/page_controller_test.exs create mode 100644 phoenix-1.6/counter/test/counter_web/views/error_view_test.exs create mode 100644 phoenix-1.6/counter/test/counter_web/views/layout_view_test.exs create mode 100644 phoenix-1.6/counter/test/counter_web/views/page_view_test.exs create mode 100644 phoenix-1.6/counter/test/support/conn_case.ex create mode 100644 phoenix-1.6/counter/test/test_helper.exs create mode 100644 phoenix-1.6/hello_world/.formatter.exs create mode 100644 phoenix-1.6/hello_world/.gitignore create mode 100644 phoenix-1.6/hello_world/README.md create mode 100644 phoenix-1.6/hello_world/assets/css/app.css create mode 100644 phoenix-1.6/hello_world/assets/css/phoenix.css create mode 100644 phoenix-1.6/hello_world/assets/js/app.js create mode 100644 phoenix-1.6/hello_world/assets/vendor/topbar.js create mode 100644 phoenix-1.6/hello_world/config/config.exs create mode 100644 phoenix-1.6/hello_world/config/dev.exs create mode 100644 phoenix-1.6/hello_world/config/prod.exs create mode 100644 phoenix-1.6/hello_world/config/runtime.exs create mode 100644 phoenix-1.6/hello_world/config/test.exs create mode 100644 phoenix-1.6/hello_world/lib/hello_world.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world/application.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world/mailer.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/controllers/page_controller.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/endpoint.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/gettext.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/router.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/telemetry.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/app.html.heex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/live.html.heex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/root.html.heex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/templates/page/index.html.heex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/views/error_helpers.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/views/error_view.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/views/layout_view.ex create mode 100644 phoenix-1.6/hello_world/lib/hello_world_web/views/page_view.ex create mode 100644 phoenix-1.6/hello_world/mix.exs create mode 100644 phoenix-1.6/hello_world/mix.lock create mode 100644 phoenix-1.6/hello_world/priv/gettext/en/LC_MESSAGES/errors.po create mode 100644 phoenix-1.6/hello_world/priv/gettext/errors.pot create mode 100644 phoenix-1.6/hello_world/priv/static/favicon.ico create mode 100644 phoenix-1.6/hello_world/priv/static/images/phoenix.png create mode 100644 phoenix-1.6/hello_world/priv/static/robots.txt create mode 100644 phoenix-1.6/hello_world/test/hello_world_web/controllers/page_controller_test.exs create mode 100644 phoenix-1.6/hello_world/test/hello_world_web/views/error_view_test.exs create mode 100644 phoenix-1.6/hello_world/test/hello_world_web/views/layout_view_test.exs create mode 100644 phoenix-1.6/hello_world/test/hello_world_web/views/page_view_test.exs create mode 100644 phoenix-1.6/hello_world/test/support/conn_case.ex create mode 100644 phoenix-1.6/hello_world/test/test_helper.exs create mode 100644 phoenix-1.6/navigation/.formatter.exs create mode 100644 phoenix-1.6/navigation/.gitignore create mode 100644 phoenix-1.6/navigation/README.md create mode 100644 phoenix-1.6/navigation/assets/css/app.css create mode 100644 phoenix-1.6/navigation/assets/css/phoenix.css create mode 100644 phoenix-1.6/navigation/assets/js/app.js create mode 100644 phoenix-1.6/navigation/assets/vendor/topbar.js create mode 100644 phoenix-1.6/navigation/config/config.exs create mode 100644 phoenix-1.6/navigation/config/dev.exs create mode 100644 phoenix-1.6/navigation/config/prod.exs create mode 100644 phoenix-1.6/navigation/config/runtime.exs create mode 100644 phoenix-1.6/navigation/config/test.exs create mode 100644 phoenix-1.6/navigation/lib/navigation.ex create mode 100644 phoenix-1.6/navigation/lib/navigation/application.ex create mode 100644 phoenix-1.6/navigation/lib/navigation/mailer.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/controllers/about_controller.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/controllers/home_controller.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/controllers/page_controller.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/controllers/projects_controller.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/endpoint.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/gettext.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/router.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/telemetry.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/about/about.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/home/home.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/layout/app.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/layout/live.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/layout/root.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/page/home/home.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/page/index.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/page/projects/projects.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/templates/projects/projects.html.heex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/views/about_view.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/views/error_helpers.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/views/error_view.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/views/home_view.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/views/layout_view.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/views/page_view.ex create mode 100644 phoenix-1.6/navigation/lib/navigation_web/views/projects_view.ex create mode 100644 phoenix-1.6/navigation/mix.exs create mode 100644 phoenix-1.6/navigation/mix.lock create mode 100644 phoenix-1.6/navigation/priv/gettext/en/LC_MESSAGES/errors.po create mode 100644 phoenix-1.6/navigation/priv/gettext/errors.pot create mode 100644 phoenix-1.6/navigation/priv/static/favicon.ico create mode 100644 phoenix-1.6/navigation/priv/static/images/phoenix.png create mode 100644 phoenix-1.6/navigation/priv/static/robots.txt create mode 100644 phoenix-1.6/navigation/test/navigation_web/controllers/page_controller_test.exs create mode 100644 phoenix-1.6/navigation/test/navigation_web/views/error_view_test.exs create mode 100644 phoenix-1.6/navigation/test/navigation_web/views/layout_view_test.exs create mode 100644 phoenix-1.6/navigation/test/navigation_web/views/page_view_test.exs create mode 100644 phoenix-1.6/navigation/test/support/conn_case.ex create mode 100644 phoenix-1.6/navigation/test/test_helper.exs create mode 100644 phoenix-1.6/random_number/.formatter.exs create mode 100644 phoenix-1.6/random_number/.gitignore create mode 100644 phoenix-1.6/random_number/README.md create mode 100644 phoenix-1.6/random_number/assets/css/app.css create mode 100644 phoenix-1.6/random_number/assets/css/phoenix.css create mode 100644 phoenix-1.6/random_number/assets/js/app.js create mode 100644 phoenix-1.6/random_number/assets/vendor/topbar.js create mode 100644 phoenix-1.6/random_number/config/config.exs create mode 100644 phoenix-1.6/random_number/config/dev.exs create mode 100644 phoenix-1.6/random_number/config/prod.exs create mode 100644 phoenix-1.6/random_number/config/runtime.exs create mode 100644 phoenix-1.6/random_number/config/test.exs create mode 100644 phoenix-1.6/random_number/lib/random_number.ex create mode 100644 phoenix-1.6/random_number/lib/random_number/application.ex create mode 100644 phoenix-1.6/random_number/lib/random_number/mailer.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/controllers/page_controller.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/controllers/random_number_controller.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/endpoint.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/gettext.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/router.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/telemetry.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/templates/layout/app.html.heex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/templates/layout/live.html.heex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/templates/layout/root.html.heex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/templates/page/index.html.heex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/templates/random_number/random_number.html.heex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/views/error_helpers.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/views/error_view.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/views/layout_view.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/views/page_view.ex create mode 100644 phoenix-1.6/random_number/lib/random_number_web/views/random_number_view.ex create mode 100644 phoenix-1.6/random_number/mix.exs create mode 100644 phoenix-1.6/random_number/mix.lock create mode 100644 phoenix-1.6/random_number/priv/gettext/en/LC_MESSAGES/errors.po create mode 100644 phoenix-1.6/random_number/priv/gettext/errors.pot create mode 100644 phoenix-1.6/random_number/priv/static/favicon.ico create mode 100644 phoenix-1.6/random_number/priv/static/images/phoenix.png create mode 100644 phoenix-1.6/random_number/priv/static/robots.txt create mode 100644 phoenix-1.6/random_number/test/random_number_web/controllers/page_controller_test.exs create mode 100644 phoenix-1.6/random_number/test/random_number_web/views/error_view_test.exs create mode 100644 phoenix-1.6/random_number/test/random_number_web/views/layout_view_test.exs create mode 100644 phoenix-1.6/random_number/test/random_number_web/views/page_view_test.exs create mode 100644 phoenix-1.6/random_number/test/support/conn_case.ex create mode 100644 phoenix-1.6/random_number/test/test_helper.exs create mode 100644 phoenix-1.7/counter/.formatter.exs create mode 100644 phoenix-1.7/counter/.gitignore create mode 100644 phoenix-1.7/counter/README.md create mode 100644 phoenix-1.7/counter/assets/css/app.css create mode 100644 phoenix-1.7/counter/assets/js/app.js create mode 100644 phoenix-1.7/counter/assets/tailwind.config.js create mode 100644 phoenix-1.7/counter/assets/vendor/topbar.js create mode 100644 phoenix-1.7/counter/config/config.exs create mode 100644 phoenix-1.7/counter/config/dev.exs create mode 100644 phoenix-1.7/counter/config/prod.exs create mode 100644 phoenix-1.7/counter/config/runtime.exs create mode 100644 phoenix-1.7/counter/config/test.exs create mode 100644 phoenix-1.7/counter/lib/counter.ex create mode 100644 phoenix-1.7/counter/lib/counter/application.ex create mode 100644 phoenix-1.7/counter/lib/counter/mailer.ex create mode 100644 phoenix-1.7/counter/lib/counter_web.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/components/core_components.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/components/layouts.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/components/layouts/app.html.heex create mode 100644 phoenix-1.7/counter/lib/counter_web/components/layouts/root.html.heex create mode 100644 phoenix-1.7/counter/lib/counter_web/controllers/error_html.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/controllers/error_json.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/controllers/page_controller.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/controllers/page_html.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/controllers/page_html/home.html.heex create mode 100644 phoenix-1.7/counter/lib/counter_web/endpoint.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/gettext.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/router.ex create mode 100644 phoenix-1.7/counter/lib/counter_web/telemetry.ex create mode 100644 phoenix-1.7/counter/mix.exs create mode 100644 phoenix-1.7/counter/mix.lock create mode 100644 phoenix-1.7/counter/priv/gettext/en/LC_MESSAGES/errors.po create mode 100644 phoenix-1.7/counter/priv/gettext/errors.pot create mode 100644 phoenix-1.7/counter/priv/hero_icons/LICENSE.md create mode 100644 phoenix-1.7/counter/priv/hero_icons/UPGRADE.md create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/academic-cap.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/adjustments-horizontal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/adjustments-vertical.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/archive-box-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/archive-box-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/archive-box.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-down-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-down-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-down-on-square-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-down-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-down-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-down-tray.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-left-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-left-on-rectangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-long-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-long-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-long-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-long-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-path-rounded-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-path.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-right-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-right-on-rectangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-small-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-small-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-small-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-small-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-top-right-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-trending-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-trending-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-up-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-up-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-up-on-square-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-up-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-up-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-up-tray.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-uturn-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-uturn-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-uturn-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrow-uturn-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrows-pointing-in.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrows-pointing-out.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrows-right-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/arrows-up-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/at-symbol.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/backspace.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/backward.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/banknotes.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-3-bottom-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-3-bottom-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-3-center-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-3.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-4.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bars-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/battery-0.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/battery-100.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/battery-50.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/beaker.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bell-alert.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bell-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bell-snooze.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bell.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bolt-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bolt.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/book-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bookmark-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bookmark-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bookmark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/briefcase.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/bug-ant.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/building-library.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/building-office-2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/building-office.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/building-storefront.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cake.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/calculator.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/calendar-days.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/calendar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/camera.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chart-bar-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chart-pie.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chat-bubble-bottom-center-text.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chat-bubble-bottom-center.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chat-bubble-left-ellipsis.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chat-bubble-left-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chat-bubble-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chat-bubble-oval-left-ellipsis.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chat-bubble-oval-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/check-badge.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/check-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-double-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-double-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-double-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-double-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-up-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/chevron-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/circle-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/clipboard-document-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/clipboard-document-list.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/clipboard-document.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/clipboard.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/clock.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cloud-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cloud-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cloud.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/code-bracket-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/code-bracket.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cog-6-tooth.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cog-8-tooth.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cog.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/command-line.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/computer-desktop.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cpu-chip.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/credit-card.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cube-transparent.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cube.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/currency-bangladeshi.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/currency-dollar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/currency-euro.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/currency-pound.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/currency-rupee.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/currency-yen.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cursor-arrow-rays.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/cursor-arrow-ripple.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/device-phone-mobile.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/device-tablet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-duplicate.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-magnifying-glass.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document-text.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/document.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/ellipsis-horizontal-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/ellipsis-horizontal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/ellipsis-vertical.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/envelope-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/envelope.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/exclamation-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/exclamation-triangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/eye-dropper.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/eye-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/eye.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/face-frown.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/face-smile.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/film.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/finger-print.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/fire.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/flag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/folder-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/folder-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/folder-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/folder-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/folder.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/forward.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/funnel.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/gif.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/gift-top.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/gift.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/globe-alt.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/globe-americas.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/globe-asia-australia.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/globe-europe-africa.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/hand-raised.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/hand-thumb-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/hand-thumb-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/hashtag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/heart.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/home-modern.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/home.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/identification.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/inbox-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/inbox-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/inbox.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/information-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/key.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/language.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/lifebuoy.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/light-bulb.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/link.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/list-bullet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/lock-closed.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/lock-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/magnifying-glass-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/magnifying-glass-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/magnifying-glass-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/magnifying-glass.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/map-pin.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/map.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/megaphone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/microphone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/minus-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/minus-small.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/moon.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/musical-note.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/newspaper.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/no-symbol.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/paint-brush.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/paper-airplane.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/paper-clip.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/pause-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/pause.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/pencil-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/pencil.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/phone-arrow-down-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/phone-arrow-up-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/phone-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/phone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/photo.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/play-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/play-pause.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/play.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/plus-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/plus-small.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/power.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/presentation-chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/presentation-chart-line.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/printer.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/puzzle-piece.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/qr-code.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/question-mark-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/queue-list.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/radio.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/receipt-percent.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/receipt-refund.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/rectangle-group.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/rectangle-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/rocket-launch.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/rss.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/scale.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/scissors.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/server-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/server.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/share.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/shield-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/shield-exclamation.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/shopping-bag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/shopping-cart.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/signal-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/signal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/sparkles.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/speaker-wave.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/speaker-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/square-2-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/square-3-stack-3d.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/squares-2x2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/squares-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/star.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/stop-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/stop.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/sun.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/swatch.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/table-cells.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/tag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/ticket.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/trash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/trophy.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/truck.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/tv.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/user-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/user-group.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/user-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/user-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/user.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/users.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/variable.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/video-camera-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/video-camera.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/view-columns.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/viewfinder-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/wallet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/wifi.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/window.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/wrench-screwdriver.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/wrench.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/x-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/20/solid/x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/academic-cap.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/adjustments-horizontal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/adjustments-vertical.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/archive-box-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/archive-box-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/archive-box.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-down-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-down-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-down-on-square-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-down-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-down-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-down-tray.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-left-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-left-on-rectangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-long-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-long-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-long-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-long-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-path-rounded-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-path.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-right-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-right-on-rectangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-small-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-small-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-small-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-small-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-top-right-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-trending-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-trending-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-up-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-up-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-up-on-square-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-up-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-up-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-up-tray.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-uturn-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-uturn-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-uturn-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrow-uturn-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrows-pointing-in.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrows-pointing-out.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrows-right-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/arrows-up-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/at-symbol.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/backspace.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/backward.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/banknotes.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-3-bottom-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-3-bottom-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-3-center-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-3.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-4.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bars-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/battery-0.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/battery-100.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/battery-50.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/beaker.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bell-alert.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bell-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bell-snooze.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bell.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bolt-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bolt.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/book-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bookmark-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bookmark-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bookmark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/briefcase.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/bug-ant.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/building-library.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/building-office-2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/building-office.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/building-storefront.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cake.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/calculator.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/calendar-days.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/calendar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/camera.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chart-bar-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chart-pie.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chat-bubble-bottom-center-text.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chat-bubble-bottom-center.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chat-bubble-left-ellipsis.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chat-bubble-left-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chat-bubble-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chat-bubble-oval-left-ellipsis.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chat-bubble-oval-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/check-badge.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/check-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-double-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-double-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-double-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-double-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-up-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/chevron-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/circle-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/clipboard-document-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/clipboard-document-list.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/clipboard-document.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/clipboard.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/clock.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cloud-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cloud-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cloud.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/code-bracket-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/code-bracket.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cog-6-tooth.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cog-8-tooth.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cog.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/command-line.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/computer-desktop.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cpu-chip.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/credit-card.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cube-transparent.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cube.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/currency-bangladeshi.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/currency-dollar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/currency-euro.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/currency-pound.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/currency-rupee.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/currency-yen.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cursor-arrow-rays.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/cursor-arrow-ripple.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/device-phone-mobile.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/device-tablet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-duplicate.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-magnifying-glass.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document-text.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/document.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/ellipsis-horizontal-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/ellipsis-horizontal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/ellipsis-vertical.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/envelope-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/envelope.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/exclamation-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/exclamation-triangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/eye-dropper.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/eye-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/eye.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/face-frown.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/face-smile.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/film.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/finger-print.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/fire.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/flag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/folder-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/folder-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/folder-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/folder-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/folder.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/forward.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/funnel.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/gif.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/gift-top.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/gift.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/globe-alt.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/globe-americas.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/globe-asia-australia.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/globe-europe-africa.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/hand-raised.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/hand-thumb-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/hand-thumb-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/hashtag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/heart.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/home-modern.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/home.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/identification.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/inbox-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/inbox-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/inbox.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/information-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/key.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/language.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/lifebuoy.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/light-bulb.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/link.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/list-bullet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/lock-closed.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/lock-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/magnifying-glass-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/magnifying-glass-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/magnifying-glass-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/magnifying-glass.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/map-pin.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/map.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/megaphone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/microphone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/minus-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/minus-small.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/moon.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/musical-note.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/newspaper.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/no-symbol.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/paint-brush.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/paper-airplane.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/paper-clip.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/pause-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/pause.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/pencil-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/pencil.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/phone-arrow-down-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/phone-arrow-up-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/phone-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/phone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/photo.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/play-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/play-pause.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/play.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/plus-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/plus-small.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/power.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/presentation-chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/presentation-chart-line.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/printer.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/puzzle-piece.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/qr-code.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/question-mark-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/queue-list.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/radio.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/receipt-percent.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/receipt-refund.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/rectangle-group.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/rectangle-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/rocket-launch.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/rss.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/scale.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/scissors.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/server-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/server.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/share.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/shield-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/shield-exclamation.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/shopping-bag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/shopping-cart.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/signal-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/signal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/sparkles.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/speaker-wave.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/speaker-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/square-2-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/square-3-stack-3d.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/squares-2x2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/squares-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/star.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/stop-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/stop.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/sun.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/swatch.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/table-cells.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/tag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/ticket.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/trash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/trophy.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/truck.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/tv.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/user-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/user-group.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/user-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/user-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/user.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/users.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/variable.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/video-camera-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/video-camera.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/view-columns.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/viewfinder-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/wallet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/wifi.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/window.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/wrench-screwdriver.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/wrench.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/x-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/outline/x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/academic-cap.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/adjustments-horizontal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/adjustments-vertical.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/archive-box-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/archive-box-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/archive-box.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-down-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-down-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-down-on-square-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-down-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-down-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-down-tray.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-left-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-left-on-rectangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-long-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-long-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-long-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-long-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-path-rounded-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-path.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-right-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-right-on-rectangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-small-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-small-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-small-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-small-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-top-right-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-trending-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-trending-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-up-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-up-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-up-on-square-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-up-on-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-up-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-up-tray.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-uturn-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-uturn-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-uturn-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrow-uturn-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrows-pointing-in.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrows-pointing-out.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrows-right-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/arrows-up-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/at-symbol.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/backspace.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/backward.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/banknotes.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-3-bottom-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-3-bottom-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-3-center-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-3.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-4.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bars-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/battery-0.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/battery-100.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/battery-50.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/beaker.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bell-alert.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bell-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bell-snooze.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bell.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bolt-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bolt.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/book-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bookmark-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bookmark-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bookmark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/briefcase.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/bug-ant.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/building-library.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/building-office-2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/building-office.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/building-storefront.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cake.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/calculator.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/calendar-days.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/calendar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/camera.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chart-bar-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chart-pie.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chat-bubble-bottom-center-text.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chat-bubble-bottom-center.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chat-bubble-left-ellipsis.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chat-bubble-left-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chat-bubble-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chat-bubble-oval-left-ellipsis.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chat-bubble-oval-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/check-badge.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/check-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-double-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-double-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-double-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-double-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-up-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/chevron-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/circle-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/clipboard-document-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/clipboard-document-list.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/clipboard-document.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/clipboard.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/clock.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cloud-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cloud-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cloud.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/code-bracket-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/code-bracket.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cog-6-tooth.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cog-8-tooth.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cog.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/command-line.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/computer-desktop.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cpu-chip.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/credit-card.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cube-transparent.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cube.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/currency-bangladeshi.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/currency-dollar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/currency-euro.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/currency-pound.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/currency-rupee.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/currency-yen.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cursor-arrow-rays.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/cursor-arrow-ripple.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/device-phone-mobile.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/device-tablet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-arrow-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-duplicate.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-magnifying-glass.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document-text.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/document.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/ellipsis-horizontal-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/ellipsis-horizontal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/ellipsis-vertical.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/envelope-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/envelope.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/exclamation-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/exclamation-triangle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/eye-dropper.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/eye-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/eye.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/face-frown.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/face-smile.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/film.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/finger-print.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/fire.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/flag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/folder-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/folder-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/folder-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/folder-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/folder.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/forward.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/funnel.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/gif.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/gift-top.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/gift.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/globe-alt.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/globe-americas.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/globe-asia-australia.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/globe-europe-africa.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/hand-raised.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/hand-thumb-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/hand-thumb-up.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/hashtag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/heart.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/home-modern.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/home.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/identification.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/inbox-arrow-down.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/inbox-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/inbox.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/information-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/key.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/language.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/lifebuoy.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/light-bulb.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/link.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/list-bullet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/lock-closed.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/lock-open.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/magnifying-glass-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/magnifying-glass-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/magnifying-glass-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/magnifying-glass.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/map-pin.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/map.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/megaphone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/microphone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/minus-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/minus-small.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/moon.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/musical-note.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/newspaper.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/no-symbol.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/paint-brush.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/paper-airplane.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/paper-clip.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/pause-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/pause.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/pencil-square.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/pencil.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/phone-arrow-down-left.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/phone-arrow-up-right.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/phone-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/phone.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/photo.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/play-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/play-pause.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/play.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/plus-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/plus-small.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/power.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/presentation-chart-bar.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/presentation-chart-line.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/printer.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/puzzle-piece.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/qr-code.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/question-mark-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/queue-list.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/radio.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/receipt-percent.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/receipt-refund.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/rectangle-group.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/rectangle-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/rocket-launch.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/rss.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/scale.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/scissors.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/server-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/server.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/share.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/shield-check.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/shield-exclamation.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/shopping-bag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/shopping-cart.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/signal-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/signal.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/sparkles.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/speaker-wave.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/speaker-x-mark.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/square-2-stack.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/square-3-stack-3d.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/squares-2x2.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/squares-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/star.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/stop-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/stop.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/sun.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/swatch.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/table-cells.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/tag.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/ticket.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/trash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/trophy.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/truck.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/tv.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/user-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/user-group.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/user-minus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/user-plus.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/user.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/users.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/variable.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/video-camera-slash.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/video-camera.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/view-columns.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/viewfinder-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/wallet.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/wifi.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/window.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/wrench-screwdriver.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/wrench.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/x-circle.svg create mode 100644 phoenix-1.7/counter/priv/hero_icons/optimized/24/solid/x-mark.svg create mode 100644 phoenix-1.7/counter/priv/static/favicon.ico create mode 100644 phoenix-1.7/counter/priv/static/robots.txt create mode 100644 phoenix-1.7/counter/test/counter_web/controllers/error_html_test.exs create mode 100644 phoenix-1.7/counter/test/counter_web/controllers/error_json_test.exs create mode 100644 phoenix-1.7/counter/test/counter_web/controllers/page_controller_test.exs create mode 100644 phoenix-1.7/counter/test/support/conn_case.ex create mode 100644 phoenix-1.7/counter/test/test_helper.exs diff --git a/phoenix-1.6/counter/.formatter.exs b/phoenix-1.6/counter/.formatter.exs new file mode 100644 index 000000000..47616780b --- /dev/null +++ b/phoenix-1.6/counter/.formatter.exs @@ -0,0 +1,4 @@ +[ + import_deps: [:phoenix], + inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/phoenix-1.6/counter/.gitignore b/phoenix-1.6/counter/.gitignore new file mode 100644 index 000000000..80a831f9e --- /dev/null +++ b/phoenix-1.6/counter/.gitignore @@ -0,0 +1,34 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +counter-*.tar + +# Ignore assets that are produced by build tools. +/priv/static/assets/ + +# Ignore digested assets cache. +/priv/static/cache_manifest.json + +# In case you use Node.js/npm, you want to ignore these. +npm-debug.log +/assets/node_modules/ + diff --git a/phoenix-1.6/counter/README.md b/phoenix-1.6/counter/README.md new file mode 100644 index 000000000..e5ab794d8 --- /dev/null +++ b/phoenix-1.6/counter/README.md @@ -0,0 +1,18 @@ +# Counter + +To start your Phoenix server: + + * Install dependencies with `mix deps.get` + * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` + +Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. + +Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). + +## Learn more + + * Official website: https://www.phoenixframework.org/ + * Guides: https://hexdocs.pm/phoenix/overview.html + * Docs: https://hexdocs.pm/phoenix + * Forum: https://elixirforum.com/c/phoenix-forum + * Source: https://github.com/phoenixframework/phoenix diff --git a/phoenix-1.6/counter/assets/css/app.css b/phoenix-1.6/counter/assets/css/app.css new file mode 100644 index 000000000..19c2e51ed --- /dev/null +++ b/phoenix-1.6/counter/assets/css/app.css @@ -0,0 +1,120 @@ +/* This file is for your main application CSS */ +@import "./phoenix.css"; + +/* Alerts and form errors used by phx.new */ +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert p { + margin-bottom: 0; +} +.alert:empty { + display: none; +} +.invalid-feedback { + color: #a94442; + display: block; + margin: -1rem 0 2rem; +} + +/* LiveView specific classes for your customization */ +.phx-no-feedback.invalid-feedback, +.phx-no-feedback .invalid-feedback { + display: none; +} + +.phx-click-loading { + opacity: 0.5; + transition: opacity 1s ease-out; +} + +.phx-loading{ + cursor: wait; +} + +.phx-modal { + opacity: 1!important; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.4); +} + +.phx-modal-content { + background-color: #fefefe; + margin: 15vh auto; + padding: 20px; + border: 1px solid #888; + width: 80%; +} + +.phx-modal-close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.phx-modal-close:hover, +.phx-modal-close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + +.fade-in-scale { + animation: 0.2s ease-in 0s normal forwards 1 fade-in-scale-keys; +} + +.fade-out-scale { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-scale-keys; +} + +.fade-in { + animation: 0.2s ease-out 0s normal forwards 1 fade-in-keys; +} +.fade-out { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-keys; +} + +@keyframes fade-in-scale-keys{ + 0% { scale: 0.95; opacity: 0; } + 100% { scale: 1.0; opacity: 1; } +} + +@keyframes fade-out-scale-keys{ + 0% { scale: 1.0; opacity: 1; } + 100% { scale: 0.95; opacity: 0; } +} + +@keyframes fade-in-keys{ + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@keyframes fade-out-keys{ + 0% { opacity: 1; } + 100% { opacity: 0; } +} diff --git a/phoenix-1.6/counter/assets/css/phoenix.css b/phoenix-1.6/counter/assets/css/phoenix.css new file mode 100644 index 000000000..0d59050f8 --- /dev/null +++ b/phoenix-1.6/counter/assets/css/phoenix.css @@ -0,0 +1,101 @@ +/* Includes some default style for the starter application. + * This can be safely deleted to start fresh. + */ + +/* Milligram v1.4.1 https://milligram.github.io + * Copyright (c) 2020 CJ Patoilo Licensed under the MIT license + */ + +*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#000000;font-family:'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#0069d9;border:0.1rem solid #0069d9;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#0069d9;border-color:#0069d9}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#0069d9}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#0069d9}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#0069d9}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#0069d9}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #0069d9;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='color'],input[type='date'],input[type='datetime'],input[type='datetime-local'],input[type='email'],input[type='month'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='week'],input:not([type]),textarea,select{-webkit-appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem .7rem;width:100%}input[type='color']:focus,input[type='date']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input[type='email']:focus,input[type='month']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='week']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#0069d9;outline:0}select{background:url('data:image/svg+xml;utf8,') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:none;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#0069d9;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;display:block;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media (min-width: 40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} + +/* General style */ +h1{font-size: 3.6rem; line-height: 1.25} +h2{font-size: 2.8rem; line-height: 1.3} +h3{font-size: 2.2rem; letter-spacing: -.08rem; line-height: 1.35} +h4{font-size: 1.8rem; letter-spacing: -.05rem; line-height: 1.5} +h5{font-size: 1.6rem; letter-spacing: 0; line-height: 1.4} +h6{font-size: 1.4rem; letter-spacing: 0; line-height: 1.2} +pre{padding: 1em;} + +.container{ + margin: 0 auto; + max-width: 80.0rem; + padding: 0 2.0rem; + position: relative; + width: 100% +} +select { + width: auto; +} + +/* Phoenix promo and logo */ +.phx-hero { + text-align: center; + border-bottom: 1px solid #e3e3e3; + background: #eee; + border-radius: 6px; + padding: 3em 3em 1em; + margin-bottom: 3rem; + font-weight: 200; + font-size: 120%; +} +.phx-hero input { + background: #ffffff; +} +.phx-logo { + min-width: 300px; + margin: 1rem; + display: block; +} +.phx-logo img { + width: auto; + display: block; +} + +/* Headers */ +header { + width: 100%; + background: #fdfdfd; + border-bottom: 1px solid #eaeaea; + margin-bottom: 2rem; +} +header section { + align-items: center; + display: flex; + flex-direction: column; + justify-content: space-between; +} +header section :first-child { + order: 2; +} +header section :last-child { + order: 1; +} +header nav ul, +header nav li { + margin: 0; + padding: 0; + display: block; + text-align: right; + white-space: nowrap; +} +header nav ul { + margin: 1rem; + margin-top: 0; +} +header nav a { + display: block; +} + +@media (min-width: 40.0rem) { /* Small devices (landscape phones, 576px and up) */ + header section { + flex-direction: row; + } + header nav ul { + margin: 1rem; + } + .phx-logo { + flex-basis: 527px; + margin: 2rem 1rem; + } +} diff --git a/phoenix-1.6/counter/assets/js/app.js b/phoenix-1.6/counter/assets/js/app.js new file mode 100644 index 000000000..2ca06a566 --- /dev/null +++ b/phoenix-1.6/counter/assets/js/app.js @@ -0,0 +1,45 @@ +// We import the CSS which is extracted to its own file by esbuild. +// Remove this line if you add a your own CSS build pipeline (e.g postcss). +import "../css/app.css" + +// If you want to use Phoenix channels, run `mix help phx.gen.channel` +// to get started and then uncomment the line below. +// import "./user_socket.js" + +// You can include dependencies in two ways. +// +// The simplest option is to put them in assets/vendor and +// import them using relative paths: +// +// import "../vendor/some-package.js" +// +// Alternatively, you can `npm install some-package --prefix assets` and import +// them using a path starting with the package name: +// +// import "some-package" +// + +// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. +import "phoenix_html" +// Establish Phoenix Socket and LiveView configuration. +import {Socket} from "phoenix" +import {LiveSocket} from "phoenix_live_view" +import topbar from "../vendor/topbar" + +let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") +let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) + +// Show progress bar on live navigation and form submits +topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) +window.addEventListener("phx:page-loading-start", info => topbar.show()) +window.addEventListener("phx:page-loading-stop", info => topbar.hide()) + +// connect if there are any LiveViews on the page +liveSocket.connect() + +// expose liveSocket on window for web console debug logs and latency simulation: +// >> liveSocket.enableDebug() +// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session +// >> liveSocket.disableLatencySim() +window.liveSocket = liveSocket + diff --git a/phoenix-1.6/counter/assets/vendor/topbar.js b/phoenix-1.6/counter/assets/vendor/topbar.js new file mode 100644 index 000000000..1f6220974 --- /dev/null +++ b/phoenix-1.6/counter/assets/vendor/topbar.js @@ -0,0 +1,157 @@ +/** + * @license MIT + * topbar 1.0.0, 2021-01-06 + * https://buunguyen.github.io/topbar + * Copyright (c) 2021 Buu Nguyen + */ +(function (window, document) { + "use strict"; + + // https://gist.github.com/paulirish/1579671 + (function () { + var lastTime = 0; + var vendors = ["ms", "moz", "webkit", "o"]; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = + window[vendors[x] + "RequestAnimationFrame"]; + window.cancelAnimationFrame = + window[vendors[x] + "CancelAnimationFrame"] || + window[vendors[x] + "CancelRequestAnimationFrame"]; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + })(); + + var canvas, + progressTimerId, + fadeTimerId, + currentProgress, + showing, + addEvent = function (elem, type, handler) { + if (elem.addEventListener) elem.addEventListener(type, handler, false); + else if (elem.attachEvent) elem.attachEvent("on" + type, handler); + else elem["on" + type] = handler; + }, + options = { + autoRun: true, + barThickness: 3, + barColors: { + 0: "rgba(26, 188, 156, .9)", + ".25": "rgba(52, 152, 219, .9)", + ".50": "rgba(241, 196, 15, .9)", + ".75": "rgba(230, 126, 34, .9)", + "1.0": "rgba(211, 84, 0, .9)", + }, + shadowBlur: 10, + shadowColor: "rgba(0, 0, 0, .6)", + className: null, + }, + repaint = function () { + canvas.width = window.innerWidth; + canvas.height = options.barThickness * 5; // need space for shadow + + var ctx = canvas.getContext("2d"); + ctx.shadowBlur = options.shadowBlur; + ctx.shadowColor = options.shadowColor; + + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); + for (var stop in options.barColors) + lineGradient.addColorStop(stop, options.barColors[stop]); + ctx.lineWidth = options.barThickness; + ctx.beginPath(); + ctx.moveTo(0, options.barThickness / 2); + ctx.lineTo( + Math.ceil(currentProgress * canvas.width), + options.barThickness / 2 + ); + ctx.strokeStyle = lineGradient; + ctx.stroke(); + }, + createCanvas = function () { + canvas = document.createElement("canvas"); + var style = canvas.style; + style.position = "fixed"; + style.top = style.left = style.right = style.margin = style.padding = 0; + style.zIndex = 100001; + style.display = "none"; + if (options.className) canvas.classList.add(options.className); + document.body.appendChild(canvas); + addEvent(window, "resize", repaint); + }, + topbar = { + config: function (opts) { + for (var key in opts) + if (options.hasOwnProperty(key)) options[key] = opts[key]; + }, + show: function () { + if (showing) return; + showing = true; + if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); + if (!canvas) createCanvas(); + canvas.style.opacity = 1; + canvas.style.display = "block"; + topbar.progress(0); + if (options.autoRun) { + (function loop() { + progressTimerId = window.requestAnimationFrame(loop); + topbar.progress( + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) + ); + })(); + } + }, + progress: function (to) { + if (typeof to === "undefined") return currentProgress; + if (typeof to === "string") { + to = + (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 + ? currentProgress + : 0) + parseFloat(to); + } + currentProgress = to > 1 ? 1 : to; + repaint(); + return currentProgress; + }, + hide: function () { + if (!showing) return; + showing = false; + if (progressTimerId != null) { + window.cancelAnimationFrame(progressTimerId); + progressTimerId = null; + } + (function loop() { + if (topbar.progress("+.1") >= 1) { + canvas.style.opacity -= 0.05; + if (canvas.style.opacity <= 0.05) { + canvas.style.display = "none"; + fadeTimerId = null; + return; + } + } + fadeTimerId = window.requestAnimationFrame(loop); + })(); + }, + }; + + if (typeof module === "object" && typeof module.exports === "object") { + module.exports = topbar; + } else if (typeof define === "function" && define.amd) { + define(function () { + return topbar; + }); + } else { + this.topbar = topbar; + } +}.call(this, window, document)); diff --git a/phoenix-1.6/counter/config/config.exs b/phoenix-1.6/counter/config/config.exs new file mode 100644 index 000000000..1f394a0da --- /dev/null +++ b/phoenix-1.6/counter/config/config.exs @@ -0,0 +1,49 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Config module. +# +# This configuration file is loaded before any dependency and +# is restricted to this project. + +# General application configuration +import Config + +# Configures the endpoint +config :counter, CounterWeb.Endpoint, + url: [host: "localhost"], + render_errors: [view: CounterWeb.ErrorView, accepts: ~w(html json), layout: false], + pubsub_server: Counter.PubSub, + live_view: [signing_salt: "rKAUFyvf"] + +# Configures the mailer +# +# By default it uses the "Local" adapter which stores the emails +# locally. You can see the emails in your browser, at "/dev/mailbox". +# +# For production it's recommended to configure a different adapter +# at the `config/runtime.exs`. +config :counter, Counter.Mailer, adapter: Swoosh.Adapters.Local + +# Swoosh API client is needed for adapters other than SMTP. +config :swoosh, :api_client, false + +# Configure esbuild (the version is required) +config :esbuild, + version: "0.14.29", + default: [ + args: + ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), + cd: Path.expand("../assets", __DIR__), + env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} + ] + +# Configures Elixir's Logger +config :logger, :console, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id] + +# Use Jason for JSON parsing in Phoenix +config :phoenix, :json_library, Jason + +# Import environment specific config. This must remain at the bottom +# of this file so it overrides the configuration defined above. +import_config "#{config_env()}.exs" diff --git a/phoenix-1.6/counter/config/dev.exs b/phoenix-1.6/counter/config/dev.exs new file mode 100644 index 000000000..205c62996 --- /dev/null +++ b/phoenix-1.6/counter/config/dev.exs @@ -0,0 +1,65 @@ +import Config + +# For development, we disable any cache and enable +# debugging and code reloading. +# +# The watchers configuration can be used to run external +# watchers to your application. For example, we use it +# with esbuild to bundle .js and .css sources. +config :counter, CounterWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. + # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. + http: [ip: {127, 0, 0, 1}, port: 4000], + check_origin: false, + code_reloader: true, + debug_errors: true, + secret_key_base: "KqEXpYgmN4n1J96fDa1WBaYTpLCk2ujKcoFEl9ykCvbPinJZ00n7f9prtjyNPsEK", + watchers: [ + # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args) + esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]} + ] + +# ## SSL Support +# +# In order to use HTTPS in development, a self-signed +# certificate can be generated by running the following +# Mix task: +# +# mix phx.gen.cert +# +# Note that this task requires Erlang/OTP 20 or later. +# Run `mix help phx.gen.cert` for more information. +# +# The `http:` config above can be replaced with: +# +# https: [ +# port: 4001, +# cipher_suite: :strong, +# keyfile: "priv/cert/selfsigned_key.pem", +# certfile: "priv/cert/selfsigned.pem" +# ], +# +# If desired, both `http:` and `https:` keys can be +# configured to run both http and https servers on +# different ports. + +# Watch static and templates for browser reloading. +config :counter, CounterWeb.Endpoint, + live_reload: [ + patterns: [ + ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", + ~r"priv/gettext/.*(po)$", + ~r"lib/counter_web/(live|views)/.*(ex)$", + ~r"lib/counter_web/templates/.*(eex)$" + ] + ] + +# Do not include metadata nor timestamps in development logs +config :logger, :console, format: "[$level] $message\n" + +# Set a higher stacktrace during development. Avoid configuring such +# in production as building large stacktraces may be expensive. +config :phoenix, :stacktrace_depth, 20 + +# Initialize plugs at runtime for faster development compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/counter/config/prod.exs b/phoenix-1.6/counter/config/prod.exs new file mode 100644 index 000000000..ceab72203 --- /dev/null +++ b/phoenix-1.6/counter/config/prod.exs @@ -0,0 +1,49 @@ +import Config + +# For production, don't forget to configure the url host +# to something meaningful, Phoenix uses this information +# when generating URLs. +# +# Note we also include the path to a cache manifest +# containing the digested version of static files. This +# manifest is generated by the `mix phx.digest` task, +# which you should run after static files are built and +# before starting your production server. +config :counter, CounterWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" + +# Do not print debug messages in production +config :logger, level: :info + +# ## SSL Support +# +# To get SSL working, you will need to add the `https` key +# to the previous section and set your `:url` port to 443: +# +# config :counter, CounterWeb.Endpoint, +# ..., +# url: [host: "example.com", port: 443], +# https: [ +# ..., +# port: 443, +# cipher_suite: :strong, +# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), +# certfile: System.get_env("SOME_APP_SSL_CERT_PATH") +# ] +# +# The `cipher_suite` is set to `:strong` to support only the +# latest and more secure SSL ciphers. This means old browsers +# and clients may not be supported. You can set it to +# `:compatible` for wider support. +# +# `:keyfile` and `:certfile` expect an absolute path to the key +# and cert in disk or a relative path inside priv, for example +# "priv/ssl/server.key". For all supported SSL configuration +# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 +# +# We also recommend setting `force_ssl` in your endpoint, ensuring +# no data is ever sent via http, always redirecting to https: +# +# config :counter, CounterWeb.Endpoint, +# force_ssl: [hsts: true] +# +# Check `Plug.SSL` for all available options in `force_ssl`. diff --git a/phoenix-1.6/counter/config/runtime.exs b/phoenix-1.6/counter/config/runtime.exs new file mode 100644 index 000000000..5bb04b9be --- /dev/null +++ b/phoenix-1.6/counter/config/runtime.exs @@ -0,0 +1,68 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/counter start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :counter, CounterWeb.Endpoint, server: true +end + +if config_env() == :prod do + # The secret key base is used to sign/encrypt cookies and other secrets. + # A default value is used in config/dev.exs and config/test.exs but you + # want to use a different value for prod and you most likely don't want + # to check this value into version control, so we use an environment + # variable instead. + secret_key_base = + System.get_env("SECRET_KEY_BASE") || + raise """ + environment variable SECRET_KEY_BASE is missing. + You can generate one by calling: mix phx.gen.secret + """ + + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + + config :counter, CounterWeb.Endpoint, + url: [host: host, port: 443, scheme: "https"], + http: [ + # Enable IPv6 and bind on all interfaces. + # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. + # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html + # for details about using IPv6 vs IPv4 and loopback vs public addresses. + ip: {0, 0, 0, 0, 0, 0, 0, 0}, + port: port + ], + secret_key_base: secret_key_base + + # ## Configuring the mailer + # + # In production you need to configure the mailer to use a different adapter. + # Also, you may need to configure the Swoosh API client of your choice if you + # are not using SMTP. Here is an example of the configuration: + # + # config :counter, Counter.Mailer, + # adapter: Swoosh.Adapters.Mailgun, + # api_key: System.get_env("MAILGUN_API_KEY"), + # domain: System.get_env("MAILGUN_DOMAIN") + # + # For this example you need include a HTTP client required by Swoosh API client. + # Swoosh supports Hackney and Finch out of the box: + # + # config :swoosh, :api_client, Swoosh.ApiClient.Hackney + # + # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. +end diff --git a/phoenix-1.6/counter/config/test.exs b/phoenix-1.6/counter/config/test.exs new file mode 100644 index 000000000..8ea329711 --- /dev/null +++ b/phoenix-1.6/counter/config/test.exs @@ -0,0 +1,18 @@ +import Config + +# We don't run a server during test. If one is required, +# you can enable the server option below. +config :counter, CounterWeb.Endpoint, + http: [ip: {127, 0, 0, 1}, port: 4002], + secret_key_base: "fRABlWiExUUFpX89Pgs1MNiWNvtvAmXWRfDUf0RuV0nq05DqfFjkw0Kf7nwBHmXS", + server: false + +# In test we don't send emails. +config :counter, Counter.Mailer, + adapter: Swoosh.Adapters.Test + +# Print only warnings and errors during test +config :logger, level: :warn + +# Initialize plugs at runtime for faster test compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/counter/lib/counter.ex b/phoenix-1.6/counter/lib/counter.ex new file mode 100644 index 000000000..9151b8a24 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter.ex @@ -0,0 +1,36 @@ +defmodule Counter do + @moduledoc """ + Counter keeps the contexts that define your domain + and business logic. + + Contexts are also responsible for managing your data, regardless + if it comes from the database, an external API or others. + """ + + use GenServer + + ##### CLIENT ##### + + def start_link(opts) do + GenServer.start_link(__MODULE__, opts) + end + + def increment(pid) do + GenServer.call(pid, :increment) + end + + + ##### SERVER ##### + + @impl true + def init(init_args) do + {:ok, init_args} + end + + @impl true + def handle_call(:increment, _from, state) do + response = state + 1 + {:reply, response, state} + end + +end diff --git a/phoenix-1.6/counter/lib/counter/application.ex b/phoenix-1.6/counter/lib/counter/application.ex new file mode 100644 index 000000000..2dc9e0dc6 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter/application.ex @@ -0,0 +1,34 @@ +defmodule Counter.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + children = [ + # Start the Telemetry supervisor + CounterWeb.Telemetry, + # Start the PubSub system + {Phoenix.PubSub, name: Counter.PubSub}, + # Start the Endpoint (http/https) + CounterWeb.Endpoint, + # Start a worker by calling: Counter.Worker.start_link(arg) + # {Counter.Worker, arg} + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: Counter.Supervisor] + Supervisor.start_link(children, opts) + end + + # Tell Phoenix to update the endpoint configuration + # whenever the application is updated. + @impl true + def config_change(changed, _new, removed) do + CounterWeb.Endpoint.config_change(changed, removed) + :ok + end +end diff --git a/phoenix-1.6/counter/lib/counter/mailer.ex b/phoenix-1.6/counter/lib/counter/mailer.ex new file mode 100644 index 000000000..fa6f9cda4 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter/mailer.ex @@ -0,0 +1,3 @@ +defmodule Counter.Mailer do + use Swoosh.Mailer, otp_app: :counter +end diff --git a/phoenix-1.6/counter/lib/counter_web.ex b/phoenix-1.6/counter/lib/counter_web.ex new file mode 100644 index 000000000..4717d1a01 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web.ex @@ -0,0 +1,110 @@ +defmodule CounterWeb do + @moduledoc """ + The entrypoint for defining your web interface, such + as controllers, views, channels and so on. + + This can be used in your application as: + + use CounterWeb, :controller + use CounterWeb, :view + + The definitions below will be executed for every view, + controller, etc, so keep them short and clean, focused + on imports, uses and aliases. + + Do NOT define functions inside the quoted expressions + below. Instead, define any helper function in modules + and import those modules here. + """ + + def controller do + quote do + use Phoenix.Controller, namespace: CounterWeb + + import Plug.Conn + import CounterWeb.Gettext + alias CounterWeb.Router.Helpers, as: Routes + end + end + + def view do + quote do + use Phoenix.View, + root: "lib/counter_web/templates", + namespace: CounterWeb + + # Import convenience functions from controllers + import Phoenix.Controller, + only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1] + + # Include shared imports and aliases for views + unquote(view_helpers()) + end + end + + def live_view do + quote do + use Phoenix.LiveView, + layout: {CounterWeb.LayoutView, "live.html"} + + unquote(view_helpers()) + end + end + + def live_component do + quote do + use Phoenix.LiveComponent + + unquote(view_helpers()) + end + end + + def component do + quote do + use Phoenix.Component + + unquote(view_helpers()) + end + end + + def router do + quote do + use Phoenix.Router + + import Plug.Conn + import Phoenix.Controller + import Phoenix.LiveView.Router + end + end + + def channel do + quote do + use Phoenix.Channel + import CounterWeb.Gettext + end + end + + defp view_helpers do + quote do + # Use all HTML functionality (forms, tags, etc) + use Phoenix.HTML + + # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc) + import Phoenix.LiveView.Helpers + + # Import basic rendering functionality (render, render_layout, etc) + import Phoenix.View + + import CounterWeb.ErrorHelpers + import CounterWeb.Gettext + alias CounterWeb.Router.Helpers, as: Routes + end + end + + @doc """ + When used, dispatch to the appropriate controller/view/etc. + """ + defmacro __using__(which) when is_atom(which) do + apply(__MODULE__, which, []) + end +end diff --git a/phoenix-1.6/counter/lib/counter_web/controllers/count_controller.ex b/phoenix-1.6/counter/lib/counter_web/controllers/count_controller.ex new file mode 100644 index 000000000..22ed1e013 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/controllers/count_controller.ex @@ -0,0 +1,7 @@ +defmodule CounterWeb.CountController do + use CounterWeb, :controller + + def count(conn, _params) do + render(conn, "count.html") + end +end diff --git a/phoenix-1.6/counter/lib/counter_web/controllers/page_controller.ex b/phoenix-1.6/counter/lib/counter_web/controllers/page_controller.ex new file mode 100644 index 000000000..da318d019 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/controllers/page_controller.ex @@ -0,0 +1,7 @@ +defmodule CounterWeb.PageController do + use CounterWeb, :controller + + def index(conn, _params) do + render(conn, "index.html") + end +end diff --git a/phoenix-1.6/counter/lib/counter_web/endpoint.ex b/phoenix-1.6/counter/lib/counter_web/endpoint.ex new file mode 100644 index 000000000..86eb5acce --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/endpoint.ex @@ -0,0 +1,49 @@ +defmodule CounterWeb.Endpoint do + use Phoenix.Endpoint, otp_app: :counter + + # The session will be stored in the cookie and signed, + # this means its contents can be read but not tampered with. + # Set :encryption_salt if you would also like to encrypt it. + @session_options [ + store: :cookie, + key: "_counter_key", + signing_salt: "ZPVJIBdR" + ] + + socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] + + # Serve at "/" the static files from "priv/static" directory. + # + # You should set gzip to true if you are running phx.digest + # when deploying your static files in production. + plug Plug.Static, + at: "/", + from: :counter, + gzip: false, + only: ~w(assets fonts images favicon.ico robots.txt) + + # Code reloading can be explicitly enabled under the + # :code_reloader configuration of your endpoint. + if code_reloading? do + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + plug Phoenix.LiveReloader + plug Phoenix.CodeReloader + end + + plug Phoenix.LiveDashboard.RequestLogger, + param_key: "request_logger", + cookie_key: "request_logger" + + plug Plug.RequestId + plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] + + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Phoenix.json_library() + + plug Plug.MethodOverride + plug Plug.Head + plug Plug.Session, @session_options + plug CounterWeb.Router +end diff --git a/phoenix-1.6/counter/lib/counter_web/gettext.ex b/phoenix-1.6/counter/lib/counter_web/gettext.ex new file mode 100644 index 000000000..041b3cf02 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/gettext.ex @@ -0,0 +1,24 @@ +defmodule CounterWeb.Gettext do + @moduledoc """ + A module providing Internationalization with a gettext-based API. + + By using [Gettext](https://hexdocs.pm/gettext), + your module gains a set of macros for translations, for example: + + import CounterWeb.Gettext + + # Simple translation + gettext("Here is the string to translate") + + # Plural translation + ngettext("Here is the string to translate", + "Here are the strings to translate", + 3) + + # Domain-based translation + dgettext("errors", "Here is the error message to translate") + + See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. + """ + use Gettext, otp_app: :counter +end diff --git a/phoenix-1.6/counter/lib/counter_web/router.ex b/phoenix-1.6/counter/lib/counter_web/router.ex new file mode 100644 index 000000000..8c7acc537 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/router.ex @@ -0,0 +1,57 @@ +defmodule CounterWeb.Router do + use CounterWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_live_flash + plug :put_root_layout, {CounterWeb.LayoutView, :root} + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + scope "/", CounterWeb do + pipe_through :browser + + get "/", PageController, :index + get "/count", CountController, :count + end + + # Other scopes may use custom stacks. + # scope "/api", CounterWeb do + # pipe_through :api + # end + + # Enables LiveDashboard only for development + # + # If you want to use the LiveDashboard in production, you should put + # it behind authentication and allow only admins to access it. + # If your application does not have an admins-only section yet, + # you can use Plug.BasicAuth to set up some basic authentication + # as long as you are also using SSL (which you should anyway). + if Mix.env() in [:dev, :test] do + import Phoenix.LiveDashboard.Router + + scope "/" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: CounterWeb.Telemetry + end + end + + # Enables the Swoosh mailbox preview in development. + # + # Note that preview only shows emails that were sent by the same + # node running the Phoenix server. + if Mix.env() == :dev do + scope "/dev" do + pipe_through :browser + + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end +end diff --git a/phoenix-1.6/counter/lib/counter_web/telemetry.ex b/phoenix-1.6/counter/lib/counter_web/telemetry.ex new file mode 100644 index 000000000..3157ba46c --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/telemetry.ex @@ -0,0 +1,48 @@ +defmodule CounterWeb.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp periodic_measurements do + [ + # A module, function and arguments to be invoked periodically. + # This function must call :telemetry.execute/3 and a metric must be added above. + # {CounterWeb, :count_users, []} + ] + end +end diff --git a/phoenix-1.6/counter/lib/counter_web/templates/count/count.html.heex b/phoenix-1.6/counter/lib/counter_web/templates/count/count.html.heex new file mode 100644 index 000000000..a3c5dce3a --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/templates/count/count.html.heex @@ -0,0 +1,2 @@ +Hello World +

Hello World

diff --git a/phoenix-1.6/counter/lib/counter_web/templates/layout/app.html.heex b/phoenix-1.6/counter/lib/counter_web/templates/layout/app.html.heex new file mode 100644 index 000000000..169aed956 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/templates/layout/app.html.heex @@ -0,0 +1,5 @@ +
+ + + <%= @inner_content %> +
diff --git a/phoenix-1.6/counter/lib/counter_web/templates/layout/live.html.heex b/phoenix-1.6/counter/lib/counter_web/templates/layout/live.html.heex new file mode 100644 index 000000000..a29d60448 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/templates/layout/live.html.heex @@ -0,0 +1,11 @@ +
+ + + + + <%= @inner_content %> +
diff --git a/phoenix-1.6/counter/lib/counter_web/templates/layout/root.html.heex b/phoenix-1.6/counter/lib/counter_web/templates/layout/root.html.heex new file mode 100644 index 000000000..bf8fd0ca3 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/templates/layout/root.html.heex @@ -0,0 +1,30 @@ + + + + + + + + <%= live_title_tag assigns[:page_title] || "Counter", suffix: " · Phoenix Framework" %> + + + + +
+
+ + +
+
+ <%= @inner_content %> + + diff --git a/phoenix-1.6/counter/lib/counter_web/templates/page/index.html.heex b/phoenix-1.6/counter/lib/counter_web/templates/page/index.html.heex new file mode 100644 index 000000000..f844bd8d7 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/templates/page/index.html.heex @@ -0,0 +1,41 @@ +
+

<%= gettext "Welcome to %{name}!", name: "Phoenix" %>

+

Peace of mind from prototype to production

+
+ +
+ + +
diff --git a/phoenix-1.6/counter/lib/counter_web/views/count_view.ex b/phoenix-1.6/counter/lib/counter_web/views/count_view.ex new file mode 100644 index 000000000..e927b250c --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/views/count_view.ex @@ -0,0 +1,3 @@ +defmodule CounterWeb.CountView do + use CounterWeb, :view +end diff --git a/phoenix-1.6/counter/lib/counter_web/views/error_helpers.ex b/phoenix-1.6/counter/lib/counter_web/views/error_helpers.ex new file mode 100644 index 000000000..036693f3c --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/views/error_helpers.ex @@ -0,0 +1,47 @@ +defmodule CounterWeb.ErrorHelpers do + @moduledoc """ + Conveniences for translating and building error messages. + """ + + use Phoenix.HTML + + @doc """ + Generates tag for inlined form input errors. + """ + def error_tag(form, field) do + Enum.map(Keyword.get_values(form.errors, field), fn error -> + content_tag(:span, translate_error(error), + class: "invalid-feedback", + phx_feedback_for: input_name(form, field) + ) + end) + end + + @doc """ + Translates an error message using gettext. + """ + def translate_error({msg, opts}) do + # When using gettext, we typically pass the strings we want + # to translate as a static argument: + # + # # Translate "is invalid" in the "errors" domain + # dgettext("errors", "is invalid") + # + # # Translate the number of files with plural rules + # dngettext("errors", "1 file", "%{count} files", count) + # + # Because the error messages we show in our forms and APIs + # are defined inside Ecto, we need to translate them dynamically. + # This requires us to call the Gettext module passing our gettext + # backend as first argument. + # + # Note we use the "errors" domain, which means translations + # should be written to the errors.po file. The :count option is + # set by Ecto and indicates we should also apply plural rules. + if count = opts[:count] do + Gettext.dngettext(CounterWeb.Gettext, "errors", msg, msg, count, opts) + else + Gettext.dgettext(CounterWeb.Gettext, "errors", msg, opts) + end + end +end diff --git a/phoenix-1.6/counter/lib/counter_web/views/error_view.ex b/phoenix-1.6/counter/lib/counter_web/views/error_view.ex new file mode 100644 index 000000000..b3bc98a18 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/views/error_view.ex @@ -0,0 +1,16 @@ +defmodule CounterWeb.ErrorView do + use CounterWeb, :view + + # If you want to customize a particular status code + # for a certain format, you may uncomment below. + # def render("500.html", _assigns) do + # "Internal Server Error" + # end + + # By default, Phoenix returns the status message from + # the template name. For example, "404.html" becomes + # "Not Found". + def template_not_found(template, _assigns) do + Phoenix.Controller.status_message_from_template(template) + end +end diff --git a/phoenix-1.6/counter/lib/counter_web/views/layout_view.ex b/phoenix-1.6/counter/lib/counter_web/views/layout_view.ex new file mode 100644 index 000000000..1b84888b9 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/views/layout_view.ex @@ -0,0 +1,7 @@ +defmodule CounterWeb.LayoutView do + use CounterWeb, :view + + # Phoenix LiveDashboard is available only in development by default, + # so we instruct Elixir to not warn if the dashboard route is missing. + @compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}} +end diff --git a/phoenix-1.6/counter/lib/counter_web/views/page_view.ex b/phoenix-1.6/counter/lib/counter_web/views/page_view.ex new file mode 100644 index 000000000..cf17b79e2 --- /dev/null +++ b/phoenix-1.6/counter/lib/counter_web/views/page_view.ex @@ -0,0 +1,3 @@ +defmodule CounterWeb.PageView do + use CounterWeb, :view +end diff --git a/phoenix-1.6/counter/mix.exs b/phoenix-1.6/counter/mix.exs new file mode 100644 index 000000000..63a45dbf7 --- /dev/null +++ b/phoenix-1.6/counter/mix.exs @@ -0,0 +1,64 @@ +defmodule Counter.MixProject do + use Mix.Project + + def project do + [ + app: :counter, + version: "0.1.0", + elixir: "~> 1.12", + elixirc_paths: elixirc_paths(Mix.env()), + compilers: [:gettext] ++ Mix.compilers(), + start_permanent: Mix.env() == :prod, + aliases: aliases(), + deps: deps() + ] + end + + # Configuration for the OTP application. + # + # Type `mix help compile.app` for more information. + def application do + [ + mod: {Counter.Application, []}, + extra_applications: [:logger, :runtime_tools] + ] + end + + # Specifies which paths to compile per environment. + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] + + # Specifies your project dependencies. + # + # Type `mix help deps` for examples and options. + defp deps do + [ + {:phoenix, "~> 1.6.15"}, + {:phoenix_html, "~> 3.0"}, + {:phoenix_live_reload, "~> 1.2", only: :dev}, + {:phoenix_live_view, "~> 0.17.5"}, + {:floki, ">= 0.30.0", only: :test}, + {:phoenix_live_dashboard, "~> 0.6"}, + {:esbuild, "~> 0.4", runtime: Mix.env() == :dev}, + {:swoosh, "~> 1.3"}, + {:telemetry_metrics, "~> 0.6"}, + {:telemetry_poller, "~> 1.0"}, + {:gettext, "~> 0.18"}, + {:jason, "~> 1.2"}, + {:plug_cowboy, "~> 2.5"} + ] + end + + # Aliases are shortcuts or tasks specific to the current project. + # For example, to install project dependencies and perform other setup tasks, run: + # + # $ mix setup + # + # See the documentation for `Mix` for more info on aliases. + defp aliases do + [ + setup: ["deps.get"], + "assets.deploy": ["esbuild default --minify", "phx.digest"] + ] + end +end diff --git a/phoenix-1.6/counter/mix.lock b/phoenix-1.6/counter/mix.lock new file mode 100644 index 000000000..47b126398 --- /dev/null +++ b/phoenix-1.6/counter/mix.lock @@ -0,0 +1,29 @@ +%{ + "castore": {:hex, :castore, "1.0.1", "240b9edb4e9e94f8f56ab39d8d2d0a57f49e46c56aced8f873892df8ff64ff5a", [:mix], [], "hexpm", "b4951de93c224d44fac71614beabd88b71932d0b1dea80d2f80fb9044e01bbb3"}, + "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, + "esbuild": {:hex, :esbuild, "0.6.1", "a774bfa7b4512a1211bf15880b462be12a4c48ed753a170c68c63b2c95888150", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "569f7409fb5a932211573fc20e2a930a0d5cf3377c5b4f6506c651b1783a1678"}, + "expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"}, + "gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"}, + "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, + "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, + "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"}, + "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.14", "5ec615d4d61bf9d4755f158bd6c80372b715533fe6d6219e12d74fb5eedbeac1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "afeb6ba43ce329a6f7fc1c9acdfc6d3039995345f025febb7f409a92f6faebd3"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"}, + "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"}, + "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, + "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, +} diff --git a/phoenix-1.6/counter/priv/gettext/en/LC_MESSAGES/errors.po b/phoenix-1.6/counter/priv/gettext/en/LC_MESSAGES/errors.po new file mode 100644 index 000000000..cdec3a113 --- /dev/null +++ b/phoenix-1.6/counter/priv/gettext/en/LC_MESSAGES/errors.po @@ -0,0 +1,11 @@ +## `msgid`s in this file come from POT (.pot) files. +## +## Do not add, change, or remove `msgid`s manually here as +## they're tied to the ones in the corresponding POT file +## (with the same domain). +## +## Use `mix gettext.extract --merge` or `mix gettext.merge` +## to merge POT files into PO files. +msgid "" +msgstr "" +"Language: en\n" diff --git a/phoenix-1.6/counter/priv/gettext/errors.pot b/phoenix-1.6/counter/priv/gettext/errors.pot new file mode 100644 index 000000000..d6f47fa87 --- /dev/null +++ b/phoenix-1.6/counter/priv/gettext/errors.pot @@ -0,0 +1,10 @@ +## This is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here has no +## effect: edit them in PO (`.po`) files instead. + diff --git a/phoenix-1.6/counter/priv/static/favicon.ico b/phoenix-1.6/counter/priv/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..73de524aaadcf60fbe9d32881db0aa86b58b5cb9 GIT binary patch literal 1258 zcmbtUO>fgM7{=qN=;Mz_82;lvPEdVaxv-<-&=sZLwab?3I zBP>U*&(Hv<5n@9ZQ$vhg#|u$Zmtq8BV;+W*7(?jOx-{r?#TE&$Sdq77MbdJjD5`-q zMm_z(jLv3t>5NhzK{%aG(Yudfpjd3AFdKe2U7&zdepTe>^s(@!&0X8TJ`h+-I?84Ml# literal 0 HcmV?d00001 diff --git a/phoenix-1.6/counter/priv/static/images/phoenix.png b/phoenix-1.6/counter/priv/static/images/phoenix.png new file mode 100644 index 0000000000000000000000000000000000000000..9c81075f63d2151e6f40e9aa66f665749a87cc6a GIT binary patch literal 13900 zcmaL8WmsF?7A@RTTCBLc6?b=ccXxso4H~R1?gT4RtT+@6?yiLril%4@T7niU{_*z6 z{eIkY^CMY%XUs9jnrrU0pClu(+L}t3=w#^6o;|}(O%cy#x4LjZZH1q*$X;nePbVE4Ruj~ha0EO zKNwDso99#XvuEN`AWs{Bi@gtxt-YhOy9C{FXD=O%vz-K;k$?ubhNqmple2Q5m%Uz~ zramCh1t4NaCnZTE4ibGLaI^QZp#izMx_gU)Bn$}9dm*VB;%os*A`rzjVfzrR1HKOd)umm?RCh=|BP9K5_7PY4e00Cyi75Qn=r z{eKwb?Y#kB&YnKb9_}>%FxuF9`1(lDJt_Uy6x=-jOY83a?=n3Vj0LBly^W8Dm%fLG z>wl`K?d0L(;qBz%Nh7BxK%-#;aCZOa_%B{VLsZ4x+sDQoV6P%CLHESK>FjJL%Eu=o zC@9Y_#G@c6$it(+FQO9uXOy|HR6B0DRr--F^NOYxjR*h5u*lKds>A z`IK4S-pkp~-cHfW!;R+eltrEYw-$l_$@lMAyZ^04@PEc~J&ED^XJP+;3;mx{Pu=s+ z@V{;QbnxHCw|9T)cCV+l_Rhg0diIRBPeoovAGCCkhmu7!e=!0j%CIc1U{;0rzhnzj zRH%Ot=y$J%$R~ap!UOQPkR*PGC6W<##xjgp8{rXFTPGUhD7@5RKexzmd%We{#b|6i z`?lh2^&{jx)SK#0PhPgi&eUZ0vBcGiH`@-FoRy{i3j{L(leZ-WVvvA2{XVGbnr9s* zG$JW*Sqd>q(BQkwNG{TIu68tN%oQnb6^FFNR~xPl$I zm|>W*j{xhT(g3sl-2z1KY@&qA0a~--8mlbo6MSY3Sy29DZRC=_#b9K&IcW(xbn3qD zali;DIL*NQ2a>E?#=CXQMk;2IJDpfLGR5_w?UEM;`!OQP>sJa904@JRBdgqw<{A-f zPODilVldJY3tG8mjj<9Cq%HNX;km>BP=EQ!_>VT)lC6`dm~$b&B*aCJ*_t6bQD*XIIA zrrq#>z~6ik=?Q&P-|3PvgPI@=_MRFRi5f&qlac?_B_cT$A11<`f;&+p^s(QUcKGMS zNYwS6+Y109HVx5PCw$%fR|2X^WJR_R&T>NOOaXhEOOBl@ACRbf{Q38g%!l_W!fCv{ zyn=GMr7&FEFtoISlT(_%iFGOyAW*%LTFx{?IMb~HaOTxco0(xXa`wb0B-{sjpkZ9F zbnZMIZIc!;=Qqv2^WY_d{p1IDf88Rxts3(SLO{5`#Xi5aUOr5);GFV06(V2G0%QE` zw{cbL@W!uuqA3n1q)>mMxU?wl*Pwndp(E*^iJ@$Hm4EfeJ`y=_@(E_@&+FH@D;5#% z%5izR;P_>FEfS3Nmq*3SI-GpsAP~&&m$citnCRwyK%Fs4!m6qG(fj((-y-2~&7)oQ z4#JKn4nA=SUWP)V&DUvjP#Hz?-yUdXY;@ zNlmhBn0p;i0j^5OqhqN%)6E;;VN5UVdzE$GmIS%ZKVBDViH>uKNOQ&Uq5yG0Dlp-V zTpnO8cV6#UAk z)?vp{kNcLNu9V6yaw#|j*h9p`zNZJMyYcx_9Zx@es61Md4Nc*y09>UV7@wE@EGya!%G<~=$Cg%(LWWrD<&NXYR$#UpU; zl-N8X3auH&u_czz`2@`)@9^Q(Z%i7Hf=u*EDPZM>R2Fk4J#Q=0-x+Y2G~abPx7&Ra z2NL1RzJ6GzOMmMRqU6 z$VT^YqYCg33>3Q}C1=wdL-qO~RY!>-RljOAeEMmD^wu(R)f~VT!$Ug{0mvR$s&%fPY=gWk9kNN8m)<5-VE?(DW&De z_K7#3AU;h7d9k4~t}aji!~JOUAShjMOMAIETdSX?IMsgoD0hRthVvFz_Pv zdB+jF*ZW#({d2~{sX9F*h~py)k>5uVOoN%aFYVn4R`h41lz|0c2VZIB=nppL5y=g> zu!5%WhCXBkP}Z@2N_Vz!AzjR@qHsS0JYuj-#`U;&ZpDXpK_mAhyos?3Q{PNOL0pmg zC+VYZt}AEuYBcotKWk`m>a(=zjXxDB3#5Um zVOPP7@tHWfoJhBge!5gA4xHSVT7cu2&GC^pQ`A)wCChhgTf&%uxo`T!dK!h-3`){W zpvJr6%XD*gpM-&tSGPXMc(X9$3n{M4OiY7A9Xmh?(uP=TgDFkP-egM4nbFfm?^>b$ zOW3Npm^VN^_io|YL=pYnX73Ft-K|c|A1*#YT?(+WskD4SwQN8cBq))xT(;M{@0~D8 zL`ANR>lb0mKLRtNENx&SAp>P7857a%ZP{0S3snYW+tbd!X-*{GL}**b@G};C z)Q3bSoD}bG=Jx$POx1UDzM= z`-IZDl+GJgv`ehIT0``{&WDsH3nEG03F1%AU(!=nGsjuyzcneB{{lp{>#5)ndCUO;OINf(7fpu|jyopb#q zlcAO8B?*00y0gq?{w~Rm#QuV^oj)tPcv!7-@bCr?Zk?hlTDK)}c8r_PG$e2Sxtqkw znT9qczCHX17&fsDl3Vm2V-Aarj3y0gN1oyt+l*_2>We#0j5b%9+SO=cHnf?jhBVL* zc#p)VMKXMa?+hxBt}v^^v`27e&jC%v7U zYKYuMhjG$Ix{NA9pgZ+vM>wy}WFw4vHwJAgeD0=m%D2|9gU5(o73(HHxx~ z$`tS4W>`?peBKOuh2OZWrn>N15K@lt?#^(;0WnTZ?_LtcuN$kZ4>wSZ(5iUWZ$`jTC z_ci7nCc@Rp`ZOBltEe^pK#3|uV{VnV_K305Q3%H-7{5pCjN#f=F$6GY0!$*`&2k!S zIddNLT9i~PSY$C(Vk}fNjSg5anR_qHRGpDH-%`M=-M#Uy)$8I8o`groI|!?V_x3%D z*jIq7JKZ%3t7W0A9=PatJ(#|9PuiW+t}h-&qnBZ5P*GhxNr~gqcYtmMghEcf1;N$b z?-KJjMQTx=;qx4;2QzXIHdtmV{?c(qZn=JMuV7*~^o}L0PZRG-cNY-v$m+tCNWA;qfeK|Ja$ z?dtZ+=kKMyDZQ?#yBJCu@vCPRGRG#W=#Uqy7gWdT#9=CV-aUP``ekX{im2fj$(ICH zrqyj>sx@=@VhTUP^u8#smC#HX@iA!B1&~*#t~u+7Nq74FS*V0Q0?u(R5}(HKHeXU| zaX6UE!_YCc0<@~U?km)OK|HeGDJuLE1en`EE(|f3b_8Kc>^KoR$h}C4y*efcDc79k z)u3b4(j8swz`YC~>rtU}6ui^r7(E_B<4DBV|5_E&6Rp|K-w*sw)y8zPZhwG05z^^w zLRAg*Our%j74=A`>3&;5GjxWvxa*y0L3)y#_vIKsT*HJxThAl=kcG%Qs?J-inZbh@ zq`FJ)@rN?G3!zzcyL6$GtD~<-+L`H#r!{AWlr~}E%2bRDzO|+VWq4@vyEP<&_QmKI7yfHm7c|~ zkdcGa5KJs;WE|^Wm#k^lqqyS>>?&VZTzP8uAppMl3)U|MmG^Sp-h8%HE>eK^IF3|u z6blQxe|+599-P{(w9u$@#Po)>v4I0!Sh_Zp$De)M6#l5 zMLd&@Q!>%r&X>3(dy1Sy?PO++U1`I)&{?M@Uo z%#2bAa3&rk<63k``;b?*UQ=TG&ME|}*pK;D6(8EIW`d64<`Ai~rNBrJ{k%38h0VrZ z)(*?!ceIz6p#l3bgLvo%tKy^07Gr2rg@|ENO0eGhf^tf4;XC)3w)a9%k-CFMjbN)`@oRUehd@f#YrH`!qtJ(}CQ8lR z+MUwQHG!ZjF=2+LRco1w;NA)|e&(F=;@5@~YvQ*}WwH|1 zW{l!fpO$_sGYm*FDc`WXx|&tI;x;P(o+0HlocYS>GuQ0YJ}uF5G$wr!TF%IET{Q4|>d}!k>Q%%+Z{vc^)k{}BmP<=f)KU-84}F(W3?QXO?M&M_+fH%H zP1RGVhy8_TH3xc5er1$IF9!{db){AF1?8D6r6x6UC#X=y=*ObiCe zZ|cKVcuN6?)kxDj?`&dz$0gLFecX{V&Au;2g)e>UH(kt49)MhGU9UX2($=TV6dnKe zCR!eldvubP@OGmDCuf$w`Jo*ml6I!*Z&(Oa{eaWP`8m*aE|7#?ovVrug{PNqINSdu z@u72)Vd`WJ6OYNAB#+hOE$k8B(PtN)wdfZ;ELi6(7IlI>Ir~TU<;xx4Tn0^Lm885k z!2|CbsSv##hl_!eoJ#>wpS`2KtE(5CZ!Hf~l*~7UMiIR+&UO9*juK5%YYJjtkERgP zggP=dxb4%E8W((`2g)%g?g>E+RZW)7*L)HMnl}Lnu;J?<6ODpm3RLPGq6Vl;z|aNp z5*5uzK$K)Bp{dY?A*8crtu--(0(l+bO&*>5!u!KQD+;nt(a~g^`=2T;v-g>ul$x_u zLcQ{AV+YeSFP`@OYqz>QCGH1>^M==xc=@-W?jSBT@vfSWgAluU7WT?eutjJ2$9ZSdl;^rlm2JPtQ%6@Y$l7(6B9 zlqVdq@F&qdugX5%1MkA<3y`rQM$#0zn1``Jaacc^tu(EL=wALU?vJ70Xwx&+^%@ab z;OsbwDLNe;#0Iv-_)%@b(BG3aEi4P?nhDFaEm@06YtqSK88&-%%KNKLjXM)jlt$0d z(q8vr_pCL!w|MrQ((|ceeWT@-V(H#9J;(%sS2B8f8}xNox|N@GD5loR?9+n2fWKZY zc(Y*>gX85*ALqgajeA^)lhbXRioH>St-U3|TRjZd87wh*%kX(J1H3jQhhtV+p3fcPQ>XQUKsF9mm zoH!0Sr&YY;%y1%&bJqhNV_vk;?sx~5__YLXe|G`Bd!GququTI(0J-~}A@a(HCwYmO zWj>cDZ4_FKb}1f&lN4TD2*1zVVhK*wFN*D6oRC-~%)GsE{(N>owOd z%1cRV&^^^z@YP_}sI0j+rz_3|Zk9B;z|^}WEhV^Bpm;=Uf9IpY5Fn6A|FO@j7Z8&B z96ZFHGbnNB^C(Vfa20auH(3;B>~V!Yon}t?kpi_J#_}@sKCrK4uY_Xf`p7hv`XQ=8 zWNp{9H3nF%DY43p1+@_OnTmXtj z%WgVqwJ!5UnSrBy?rhLiXKT?d}y73{iOJdN@mhf#J?H_awxEp#WUbKF{0}s=woC6Y47);j* z8rB1{w*AVT>0NSmFtEae;*67g8T_nxO0c+ov@>{eu5n{@#RGTr>^Bb8=wBEbB;0`7 zz|!xSHUh-AuPL^G!?~=j#GR%GzgKr%icju#i74clZV*{+CP!VXw1lVu78LdOSdw{V z{4*;Lt7ier$fJSEz6+QygOA+}x_4ilo(2pO&gO2#M3YigPU!~HbZzFpPP(m(7_Dq( z6E$iYyBlF8m8$F1Cuz4}csC&yn=cM8WVgfaL&h75{Shd3)~!cR zCrAVcxl!YrKl=V^piF14E39&aLJVb9-eT+g2xImTQ%l7;}SHq_(LSbo^EM-HXXtZ0O zdW3nm2Xc86CsIwEsbP>@Q~2ojkx)cvw^BKDjB5;4cJZr2KyPiMdSz9LK~+wi4%NKr zbN2DsiY=l;nH8!iP250F?V2V~z(9!|pVCyX9mL_@_ zlcc-NP!BZ_1zEf>pRi=1_Kqh(3X+M9b?No%R8SQvDbofi&Fz$Vs(U!_CusVn+==X` z4cUNCy9%^!gq7dHZ(d7yf82(&o(5y7mF`*OIvT28jRocQywzcRqsbN4HuB~hLSmiP z1-e(k^;S23LfRT&ykT>g@~+hOx!lg!Sf~$2v?1w2ja>QgaJtM|?p@SM9&ls$0J<8;>A`IHQY5INUj<+t`aZ}v)4 zTMv2I_QwzEM=Wg(QohmrlBbJ|jcKc6rM(eJ>_{Ce7!j7Wl-87@z;z5`*K8^*wY?^P zXZWbVI~{|7l7A`bsQ034<(8h(+iSK&8}ijuX4p=^0dk;0zaKuYr~S&idu-;u+p3y# zh&LfPIM%YArf&^E-XlY^y8hl$%bp>Gi+MuNLb0pOLODZ47f-(U&F8UH%lFk)H3Pg8 zGX$RR8odn{YWkC>IU_o}?Bgs(hY9Wy8?sIR0}Vgrg%#6#9%R$r^539t@SnujcyONj zpE?(`U`-_m!Nt>6WU8?;PR;ou0f`wuvuj1xX4j}4+M{ZmBHI>~O54)>S3Z}=gNpD= z-B$ESnoSp)Ib~)v6o{j~ZKMpo4IJYIwwCY%v9+$k%2a=ut+ETf&f;R4JYriH_yjfh zcF16FMV7{Bm~xVwCmSeQ>{H^VpmBwKi?xX5tMS?s%PV;WKlk>RF2_ zaQ#KT_9dmokkCTOdHzpHF5DT*Q$Z=`2&Z8*iEw|IL>%}ep?*ArUV@HuU70}fr}vsu z7ct2;mYIn^8+D@M!HHQVZamDm4kufo_&Lv2PQ+;2qON&of3i4Z`6^WdW!GxVHw*o( z9RCu?86CO{>RZqmkKJi#IZw5A|C&P3R7~+e1O|KX>AO!{L~~2Q^j{VcJ?fn1_JtHu zo#68?Z;9QhCQ%>Wl+v*xbCBkOYksQ3ErxKmI#@o+=yEv*{noTagX`J);d!Sqs6~1- z_t3kU4AG&!bh}$vq8bSpCgNXZ%R$m zvOkBz6;t?`*dmP4KpQa6S(Tb1v2UM_yTrv=nIeEr4bEdkEf&tcKxgqz=0#_b6#}=d z<1+YBT8K_dgbVSiDuNBJv!Zzw;~H`1CnOI;NRH;M5O3aN0V4|fV%s{@tfO&#!{~vE zXkC?8J?SKAwT&lDA&ld*Yz*V@55gw}#xX07=)to%1He+@{4HiU*{$`=4_`dDSl!dE zrb@kaTRT7dc#5TRzxH}})^%cZIN6|2;?tLujjh6Ku4c*Pw+2LJ{e43$piypJ3@{zz z{ZyQ_eCg6H#lsA4@F@ubKQ?$Sr!)(1u-g0Y@!Y3D0$d`L8{h{xE*7}P)$8&a||XD*TfFRvL{%LTfbnlB1i z`xZ=4^3YZ0(&j19vpsX0>pdpp@?^hP1Lua|`g^OU4F@JZvt-JBeIhxTzTB`_7Ha(C zXpMKEgjelG#+Z1pH3QN?T{LaXLXs&7drY%!CjC6=jey#;hs!{-|i#z2tEed4Ti=&S3x@^6XZrGR|k} znjEuABs|D(T|wc}%1sHwoY(yB{a6Ys6`5RKt#YYI&kJ0bNGe4P*Uq9}0YZR`s>=o) z$^kQp3e)J59I>B@@PGAi_X6G%Sved~($wM_il`m%ViYFIyuN(JJ|msKAXrNRV#341 z1|2JQNES0Z;*5kT&$YHc%^PE`bnRw~uILz)Jn z)rtYuuV1r^>4a@XS-a!^ETgu|Hbj0rKjU`uCKq2mWUW!kEocyb*qm8%j`6#5FX;H5 zH}?G7Z?<6e>UQ1ZW!lOfGLsiJ6Cmv5nnJCrOjaP?lKh2^41eXWTy*hxjZKwSr_VJ}-~$&#D3 zzhiEKdrOMKKU0O4xvH7-t>i*p@I!2=k5-G?6tO+uraKwk8#JkfX*#Z{*%i}i_x~lXo^+A!ibrcM>WX|z89iEn| zyC2#BpijrGcW&p}+^3j>Wt$A*=Jrvh8ETLM8aKVsi0&;hlS@-###$Xy))F)OMv57; zZdh4t?c_)zrcUIaOVOUk1$;wMCE>D~-O=N0NFI9^e^C}x37OgGLo)!Q zl=io=P5JDB<$lI%4Y+J3XEphD`qO&Kd_8!yc<*ECCAvC#XTpXe+6u_cmTjEJ| znoqk>=_ZZ4uO5-(m)F08ceF!p<}!?TgW`7279=mKmj~~5tj;zg?PgUz-)5VMM%0j%)T?pU<0Uk|D3p5{2e??#5jMB{Y!BJEFH zuWNq7jM!7<2zWCvPQRj%cXAC#;y_}2ul?h8L$gjQfeIy;;;WXDudit7Uv|Z2b;SrX zfetgr<80WRG+xgFc;C!8+A#ako200^e2Q~AmM2ENwvrd`El^q3CVWk8#pR}l6cCg~ zUYS?4ylI87x!WdHAgi(~ry661S05Qi1wbZZh3H*x{Rw|u!|$*brVLWole{Fe)at#5 z&|6f+nmc3oc&?6vkxR;joiAOb9VuypZ0J$RUBbNxlH~&My}W2{rLRnL z_-^!!5*@@mLvLnIN0QiIhGHHqzPd<3m6&`Vvw8X{6CQBzCaG00F|!`5<-vmAC>~F}0=9+5g-X4W2>mQBUE2eh0%g|SqINm6Te;DOFibuJZ*{m1m-=$li zA>OF0B&aPG^YmL#sfV^T*RCPN%5N9BL>0$sDyvtimKQ1W9gBJ=5(@^odQd1zJ)8Lo(zG zeg;Iwc}daKZlFmS1a-tPNNEfJ99rixy+0qS+Sm5iq zL+jh*2DCx)TBOktKeP!XXqS-sX*+N5l;5o1VpaD@M%Pak^Vqbsa_Eo0WNcXh8i zafO?AZFRj;yl(n{r6|&IBA_<(2I?rB(2@jt?Fv>m#>YoLznm1vhc1`weTd-;OKNlU z7eAu`QWzX1>w@I0VgfW#HL`x)yyghsLOaU(#V{i%@fmXs*QfgI)M>KgCz&&%`=PNZ zPu+yGi`h*t8-5KMsj5_yxl+d&O}k-3yJGaH4TJX)ynmlzXsKl%oOgmmFTRO-s`ckV z&u!9meAquxYhwk+gHo^`Q|*lIBH2K=|B*NDyfTf|*+wzNwSNZ2hkhakih?%7j(lPT zD;YT{1@b6F_gc~lu)m$%A9Eb*aK&Q@qrFOd-)-p{v7hkz2lg2jw=-pNt0yOAU(svi zLYL#99x*+EkqXq&U$tR)E{^73j>i*upyP+bN9CfUhi~MgD<%5{I+<#AWsg?a)U-af z&|(T&_pI1K{XL`TB94{Ou)PPi5Y+MbOb^}#nvWufpZWaDcRLGjsu}h_miC|C;Ors| z=3G3ILzSiI!nCg+;$03@KDrVVI`VxANUQz+09hW z{~WkYa@aKYcKD$MeY0x*7Sec0vr5BAj`1Ov&~s(J`O2>w{g%{Jq-lIT_L=68?J+E* zGGTu~fpOk97y&7_Diw3aL;G8#ku@_Hyb)LWa$+&s zEF~rPhKO&PraSlge{A(pz0+TTl9mN_uDi-)@vS9E8zK$1amRo!FM&6Ys)yQdvVSt? zd&vc0p2sNLeK7sJ7^QO9Xkp(Tm$9A!ml{~8K2#1711%(JGl8Eh9QYUDKEx@cv!JHg)>??HhpzbPA3DM&~U< ze~Rf!mHiBTPgT>F;L?v|Ymp&(l9!ZA&Mt9(uv}|zk8-{XfKyu7vYP#;ao1qBoecXG zs7P|7#x6hY;x|`wfR2^)K5ub~0ncUzK+Ybe)UnPC7iajN`lE-k73KK}UD zKzHTYGesC!j*8N598|aVJHKu;Qd&wK$pOh<2p%XS*W6`g#nH`{4mC<`Tm8tWUzn}AWi3+;%dy%2o{JaR5Qy)!>H z%gz0!Cx`4fqYzD`j6j=|L6X8+kHP1A*E0lNx2(ItObT73J3_eKE@=MB4=jMRRrw62 zG<8C+vWR^_5OLT~3Brb~kl1OQ5_pGlWb@Ulbtbkbg~d5y_X_mvTrZdJ`R2u?sF<7U zZv~d(&CJ-A72TvW_u`}1Z=|JAbP7kMUj`&-f$L>F7R;6ggDkC*jsf|P&oalP8U8fK zT_2wdY0JFNakO#`swMjx zM!cT4Z}M9M_60r_9>16xcaX^`A9gqPZ`l_3nb%}8T`Chs482ZkvJhPcGX?jMR}=ah zTZDVQSSASC6SiqO@{GT!Qk?JszB*o9FY#TP6Dko7-f4$6V16IQQ`bDNN^kJC2IR;t zY?SB&z67>8I0W=}iwTS;u3x6J_59+L8+<7^p24|fLiU+*HlGuF3@?Ppk+A-3MnmFl z)qZ;$wA_$w?+0srI|;Kh_%r5`bfl_d$kA>k$+avzku2rs<@<_TvP^;(tTuzj zhE_CzlafJ^=I2x-PY=Nl5R<=t%`qL1pvH4;}21B9;( zkl_bYZ2+YII)|5v`(DLhC^8SK&@Rg;W2>Er#Wa&~W~5#GeHRr{N`OC4&x8mdeH^(Z zSo~{uE-6NJ{V*qLT*hB@@O-Qm!r>wH*J1pN8Ht>Ri`CHLtL;2>NxDqFb41bk*1z+J zhV>B-vfA2MMCt)_#) z3G~quaUUm>*(ov1gX?+|@8-u$!zgCPz9kxLJH$2OO{(l${;)=ie$@*MH+Dtp83U5!%o~k zPQ8KRJ141&WM*HM=`hd+PDS93YX&}Sllg@j-BHpM?!v8!WeV^^4DX@GQ`sea*>H?=b|NHgB}D2V9jt) zJ=prm-}$6M+ZsPel4vwOBmuhqij3Ujz<~(=Z+%`0#*Vm+M8&7Up%ajiBU{{m!_%D9 z1zJjlE#0`HNju{ds8|+m7h{Hj5#iNXfrHNd}8lmEE zQSW{7z*8sq+W$*S6LniEU?Z!#B?GdWkjUeg4$&N$;$N7gqx*-E<^6-zhv(0nSsJz2 UWxWXg`G1#+f~I_}taaG`2PLnS&Hw-a literal 0 HcmV?d00001 diff --git a/phoenix-1.6/counter/priv/static/robots.txt b/phoenix-1.6/counter/priv/static/robots.txt new file mode 100644 index 000000000..26e06b5f1 --- /dev/null +++ b/phoenix-1.6/counter/priv/static/robots.txt @@ -0,0 +1,5 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / diff --git a/phoenix-1.6/counter/test/counter_web/controllers/page_controller_test.exs b/phoenix-1.6/counter/test/counter_web/controllers/page_controller_test.exs new file mode 100644 index 000000000..2165e3ce2 --- /dev/null +++ b/phoenix-1.6/counter/test/counter_web/controllers/page_controller_test.exs @@ -0,0 +1,8 @@ +defmodule CounterWeb.PageControllerTest do + use CounterWeb.ConnCase + + test "GET /", %{conn: conn} do + conn = get(conn, "/") + assert html_response(conn, 200) =~ "Welcome to Phoenix!" + end +end diff --git a/phoenix-1.6/counter/test/counter_web/views/error_view_test.exs b/phoenix-1.6/counter/test/counter_web/views/error_view_test.exs new file mode 100644 index 000000000..3e3c63e65 --- /dev/null +++ b/phoenix-1.6/counter/test/counter_web/views/error_view_test.exs @@ -0,0 +1,14 @@ +defmodule CounterWeb.ErrorViewTest do + use CounterWeb.ConnCase, async: true + + # Bring render/3 and render_to_string/3 for testing custom views + import Phoenix.View + + test "renders 404.html" do + assert render_to_string(CounterWeb.ErrorView, "404.html", []) == "Not Found" + end + + test "renders 500.html" do + assert render_to_string(CounterWeb.ErrorView, "500.html", []) == "Internal Server Error" + end +end diff --git a/phoenix-1.6/counter/test/counter_web/views/layout_view_test.exs b/phoenix-1.6/counter/test/counter_web/views/layout_view_test.exs new file mode 100644 index 000000000..6e10cb911 --- /dev/null +++ b/phoenix-1.6/counter/test/counter_web/views/layout_view_test.exs @@ -0,0 +1,8 @@ +defmodule CounterWeb.LayoutViewTest do + use CounterWeb.ConnCase, async: true + + # When testing helpers, you may want to import Phoenix.HTML and + # use functions such as safe_to_string() to convert the helper + # result into an HTML string. + # import Phoenix.HTML +end diff --git a/phoenix-1.6/counter/test/counter_web/views/page_view_test.exs b/phoenix-1.6/counter/test/counter_web/views/page_view_test.exs new file mode 100644 index 000000000..5e85cd31d --- /dev/null +++ b/phoenix-1.6/counter/test/counter_web/views/page_view_test.exs @@ -0,0 +1,3 @@ +defmodule CounterWeb.PageViewTest do + use CounterWeb.ConnCase, async: true +end diff --git a/phoenix-1.6/counter/test/support/conn_case.ex b/phoenix-1.6/counter/test/support/conn_case.ex new file mode 100644 index 000000000..9fa719c2c --- /dev/null +++ b/phoenix-1.6/counter/test/support/conn_case.ex @@ -0,0 +1,37 @@ +defmodule CounterWeb.ConnCase do + @moduledoc """ + This module defines the test case to be used by + tests that require setting up a connection. + + Such tests rely on `Phoenix.ConnTest` and also + import other functionality to make it easier + to build common data structures and query the data layer. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use CounterWeb.ConnCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + # Import conveniences for testing with connections + import Plug.Conn + import Phoenix.ConnTest + import CounterWeb.ConnCase + + alias CounterWeb.Router.Helpers, as: Routes + + # The default endpoint for testing + @endpoint CounterWeb.Endpoint + end + end + + setup _tags do + {:ok, conn: Phoenix.ConnTest.build_conn()} + end +end diff --git a/phoenix-1.6/counter/test/test_helper.exs b/phoenix-1.6/counter/test/test_helper.exs new file mode 100644 index 000000000..869559e70 --- /dev/null +++ b/phoenix-1.6/counter/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/phoenix-1.6/hello_world/.formatter.exs b/phoenix-1.6/hello_world/.formatter.exs new file mode 100644 index 000000000..47616780b --- /dev/null +++ b/phoenix-1.6/hello_world/.formatter.exs @@ -0,0 +1,4 @@ +[ + import_deps: [:phoenix], + inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/phoenix-1.6/hello_world/.gitignore b/phoenix-1.6/hello_world/.gitignore new file mode 100644 index 000000000..13311e695 --- /dev/null +++ b/phoenix-1.6/hello_world/.gitignore @@ -0,0 +1,34 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +hello_world-*.tar + +# Ignore assets that are produced by build tools. +/priv/static/assets/ + +# Ignore digested assets cache. +/priv/static/cache_manifest.json + +# In case you use Node.js/npm, you want to ignore these. +npm-debug.log +/assets/node_modules/ + diff --git a/phoenix-1.6/hello_world/README.md b/phoenix-1.6/hello_world/README.md new file mode 100644 index 000000000..6f6319189 --- /dev/null +++ b/phoenix-1.6/hello_world/README.md @@ -0,0 +1,18 @@ +# HelloWorld + +To start your Phoenix server: + + * Install dependencies with `mix deps.get` + * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` + +Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. + +Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). + +## Learn more + + * Official website: https://www.phoenixframework.org/ + * Guides: https://hexdocs.pm/phoenix/overview.html + * Docs: https://hexdocs.pm/phoenix + * Forum: https://elixirforum.com/c/phoenix-forum + * Source: https://github.com/phoenixframework/phoenix diff --git a/phoenix-1.6/hello_world/assets/css/app.css b/phoenix-1.6/hello_world/assets/css/app.css new file mode 100644 index 000000000..19c2e51ed --- /dev/null +++ b/phoenix-1.6/hello_world/assets/css/app.css @@ -0,0 +1,120 @@ +/* This file is for your main application CSS */ +@import "./phoenix.css"; + +/* Alerts and form errors used by phx.new */ +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert p { + margin-bottom: 0; +} +.alert:empty { + display: none; +} +.invalid-feedback { + color: #a94442; + display: block; + margin: -1rem 0 2rem; +} + +/* LiveView specific classes for your customization */ +.phx-no-feedback.invalid-feedback, +.phx-no-feedback .invalid-feedback { + display: none; +} + +.phx-click-loading { + opacity: 0.5; + transition: opacity 1s ease-out; +} + +.phx-loading{ + cursor: wait; +} + +.phx-modal { + opacity: 1!important; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.4); +} + +.phx-modal-content { + background-color: #fefefe; + margin: 15vh auto; + padding: 20px; + border: 1px solid #888; + width: 80%; +} + +.phx-modal-close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.phx-modal-close:hover, +.phx-modal-close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + +.fade-in-scale { + animation: 0.2s ease-in 0s normal forwards 1 fade-in-scale-keys; +} + +.fade-out-scale { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-scale-keys; +} + +.fade-in { + animation: 0.2s ease-out 0s normal forwards 1 fade-in-keys; +} +.fade-out { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-keys; +} + +@keyframes fade-in-scale-keys{ + 0% { scale: 0.95; opacity: 0; } + 100% { scale: 1.0; opacity: 1; } +} + +@keyframes fade-out-scale-keys{ + 0% { scale: 1.0; opacity: 1; } + 100% { scale: 0.95; opacity: 0; } +} + +@keyframes fade-in-keys{ + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@keyframes fade-out-keys{ + 0% { opacity: 1; } + 100% { opacity: 0; } +} diff --git a/phoenix-1.6/hello_world/assets/css/phoenix.css b/phoenix-1.6/hello_world/assets/css/phoenix.css new file mode 100644 index 000000000..0d59050f8 --- /dev/null +++ b/phoenix-1.6/hello_world/assets/css/phoenix.css @@ -0,0 +1,101 @@ +/* Includes some default style for the starter application. + * This can be safely deleted to start fresh. + */ + +/* Milligram v1.4.1 https://milligram.github.io + * Copyright (c) 2020 CJ Patoilo Licensed under the MIT license + */ + +*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#000000;font-family:'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#0069d9;border:0.1rem solid #0069d9;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#0069d9;border-color:#0069d9}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#0069d9}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#0069d9}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#0069d9}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#0069d9}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #0069d9;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='color'],input[type='date'],input[type='datetime'],input[type='datetime-local'],input[type='email'],input[type='month'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='week'],input:not([type]),textarea,select{-webkit-appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem .7rem;width:100%}input[type='color']:focus,input[type='date']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input[type='email']:focus,input[type='month']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='week']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#0069d9;outline:0}select{background:url('data:image/svg+xml;utf8,') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:none;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#0069d9;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;display:block;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media (min-width: 40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} + +/* General style */ +h1{font-size: 3.6rem; line-height: 1.25} +h2{font-size: 2.8rem; line-height: 1.3} +h3{font-size: 2.2rem; letter-spacing: -.08rem; line-height: 1.35} +h4{font-size: 1.8rem; letter-spacing: -.05rem; line-height: 1.5} +h5{font-size: 1.6rem; letter-spacing: 0; line-height: 1.4} +h6{font-size: 1.4rem; letter-spacing: 0; line-height: 1.2} +pre{padding: 1em;} + +.container{ + margin: 0 auto; + max-width: 80.0rem; + padding: 0 2.0rem; + position: relative; + width: 100% +} +select { + width: auto; +} + +/* Phoenix promo and logo */ +.phx-hero { + text-align: center; + border-bottom: 1px solid #e3e3e3; + background: #eee; + border-radius: 6px; + padding: 3em 3em 1em; + margin-bottom: 3rem; + font-weight: 200; + font-size: 120%; +} +.phx-hero input { + background: #ffffff; +} +.phx-logo { + min-width: 300px; + margin: 1rem; + display: block; +} +.phx-logo img { + width: auto; + display: block; +} + +/* Headers */ +header { + width: 100%; + background: #fdfdfd; + border-bottom: 1px solid #eaeaea; + margin-bottom: 2rem; +} +header section { + align-items: center; + display: flex; + flex-direction: column; + justify-content: space-between; +} +header section :first-child { + order: 2; +} +header section :last-child { + order: 1; +} +header nav ul, +header nav li { + margin: 0; + padding: 0; + display: block; + text-align: right; + white-space: nowrap; +} +header nav ul { + margin: 1rem; + margin-top: 0; +} +header nav a { + display: block; +} + +@media (min-width: 40.0rem) { /* Small devices (landscape phones, 576px and up) */ + header section { + flex-direction: row; + } + header nav ul { + margin: 1rem; + } + .phx-logo { + flex-basis: 527px; + margin: 2rem 1rem; + } +} diff --git a/phoenix-1.6/hello_world/assets/js/app.js b/phoenix-1.6/hello_world/assets/js/app.js new file mode 100644 index 000000000..2ca06a566 --- /dev/null +++ b/phoenix-1.6/hello_world/assets/js/app.js @@ -0,0 +1,45 @@ +// We import the CSS which is extracted to its own file by esbuild. +// Remove this line if you add a your own CSS build pipeline (e.g postcss). +import "../css/app.css" + +// If you want to use Phoenix channels, run `mix help phx.gen.channel` +// to get started and then uncomment the line below. +// import "./user_socket.js" + +// You can include dependencies in two ways. +// +// The simplest option is to put them in assets/vendor and +// import them using relative paths: +// +// import "../vendor/some-package.js" +// +// Alternatively, you can `npm install some-package --prefix assets` and import +// them using a path starting with the package name: +// +// import "some-package" +// + +// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. +import "phoenix_html" +// Establish Phoenix Socket and LiveView configuration. +import {Socket} from "phoenix" +import {LiveSocket} from "phoenix_live_view" +import topbar from "../vendor/topbar" + +let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") +let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) + +// Show progress bar on live navigation and form submits +topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) +window.addEventListener("phx:page-loading-start", info => topbar.show()) +window.addEventListener("phx:page-loading-stop", info => topbar.hide()) + +// connect if there are any LiveViews on the page +liveSocket.connect() + +// expose liveSocket on window for web console debug logs and latency simulation: +// >> liveSocket.enableDebug() +// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session +// >> liveSocket.disableLatencySim() +window.liveSocket = liveSocket + diff --git a/phoenix-1.6/hello_world/assets/vendor/topbar.js b/phoenix-1.6/hello_world/assets/vendor/topbar.js new file mode 100644 index 000000000..1f6220974 --- /dev/null +++ b/phoenix-1.6/hello_world/assets/vendor/topbar.js @@ -0,0 +1,157 @@ +/** + * @license MIT + * topbar 1.0.0, 2021-01-06 + * https://buunguyen.github.io/topbar + * Copyright (c) 2021 Buu Nguyen + */ +(function (window, document) { + "use strict"; + + // https://gist.github.com/paulirish/1579671 + (function () { + var lastTime = 0; + var vendors = ["ms", "moz", "webkit", "o"]; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = + window[vendors[x] + "RequestAnimationFrame"]; + window.cancelAnimationFrame = + window[vendors[x] + "CancelAnimationFrame"] || + window[vendors[x] + "CancelRequestAnimationFrame"]; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + })(); + + var canvas, + progressTimerId, + fadeTimerId, + currentProgress, + showing, + addEvent = function (elem, type, handler) { + if (elem.addEventListener) elem.addEventListener(type, handler, false); + else if (elem.attachEvent) elem.attachEvent("on" + type, handler); + else elem["on" + type] = handler; + }, + options = { + autoRun: true, + barThickness: 3, + barColors: { + 0: "rgba(26, 188, 156, .9)", + ".25": "rgba(52, 152, 219, .9)", + ".50": "rgba(241, 196, 15, .9)", + ".75": "rgba(230, 126, 34, .9)", + "1.0": "rgba(211, 84, 0, .9)", + }, + shadowBlur: 10, + shadowColor: "rgba(0, 0, 0, .6)", + className: null, + }, + repaint = function () { + canvas.width = window.innerWidth; + canvas.height = options.barThickness * 5; // need space for shadow + + var ctx = canvas.getContext("2d"); + ctx.shadowBlur = options.shadowBlur; + ctx.shadowColor = options.shadowColor; + + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); + for (var stop in options.barColors) + lineGradient.addColorStop(stop, options.barColors[stop]); + ctx.lineWidth = options.barThickness; + ctx.beginPath(); + ctx.moveTo(0, options.barThickness / 2); + ctx.lineTo( + Math.ceil(currentProgress * canvas.width), + options.barThickness / 2 + ); + ctx.strokeStyle = lineGradient; + ctx.stroke(); + }, + createCanvas = function () { + canvas = document.createElement("canvas"); + var style = canvas.style; + style.position = "fixed"; + style.top = style.left = style.right = style.margin = style.padding = 0; + style.zIndex = 100001; + style.display = "none"; + if (options.className) canvas.classList.add(options.className); + document.body.appendChild(canvas); + addEvent(window, "resize", repaint); + }, + topbar = { + config: function (opts) { + for (var key in opts) + if (options.hasOwnProperty(key)) options[key] = opts[key]; + }, + show: function () { + if (showing) return; + showing = true; + if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); + if (!canvas) createCanvas(); + canvas.style.opacity = 1; + canvas.style.display = "block"; + topbar.progress(0); + if (options.autoRun) { + (function loop() { + progressTimerId = window.requestAnimationFrame(loop); + topbar.progress( + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) + ); + })(); + } + }, + progress: function (to) { + if (typeof to === "undefined") return currentProgress; + if (typeof to === "string") { + to = + (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 + ? currentProgress + : 0) + parseFloat(to); + } + currentProgress = to > 1 ? 1 : to; + repaint(); + return currentProgress; + }, + hide: function () { + if (!showing) return; + showing = false; + if (progressTimerId != null) { + window.cancelAnimationFrame(progressTimerId); + progressTimerId = null; + } + (function loop() { + if (topbar.progress("+.1") >= 1) { + canvas.style.opacity -= 0.05; + if (canvas.style.opacity <= 0.05) { + canvas.style.display = "none"; + fadeTimerId = null; + return; + } + } + fadeTimerId = window.requestAnimationFrame(loop); + })(); + }, + }; + + if (typeof module === "object" && typeof module.exports === "object") { + module.exports = topbar; + } else if (typeof define === "function" && define.amd) { + define(function () { + return topbar; + }); + } else { + this.topbar = topbar; + } +}.call(this, window, document)); diff --git a/phoenix-1.6/hello_world/config/config.exs b/phoenix-1.6/hello_world/config/config.exs new file mode 100644 index 000000000..e4f88d7c4 --- /dev/null +++ b/phoenix-1.6/hello_world/config/config.exs @@ -0,0 +1,49 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Config module. +# +# This configuration file is loaded before any dependency and +# is restricted to this project. + +# General application configuration +import Config + +# Configures the endpoint +config :hello_world, HelloWorldWeb.Endpoint, + url: [host: "localhost"], + render_errors: [view: HelloWorldWeb.ErrorView, accepts: ~w(html json), layout: false], + pubsub_server: HelloWorld.PubSub, + live_view: [signing_salt: "MQVUsj5f"] + +# Configures the mailer +# +# By default it uses the "Local" adapter which stores the emails +# locally. You can see the emails in your browser, at "/dev/mailbox". +# +# For production it's recommended to configure a different adapter +# at the `config/runtime.exs`. +config :hello_world, HelloWorld.Mailer, adapter: Swoosh.Adapters.Local + +# Swoosh API client is needed for adapters other than SMTP. +config :swoosh, :api_client, false + +# Configure esbuild (the version is required) +config :esbuild, + version: "0.14.29", + default: [ + args: + ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), + cd: Path.expand("../assets", __DIR__), + env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} + ] + +# Configures Elixir's Logger +config :logger, :console, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id] + +# Use Jason for JSON parsing in Phoenix +config :phoenix, :json_library, Jason + +# Import environment specific config. This must remain at the bottom +# of this file so it overrides the configuration defined above. +import_config "#{config_env()}.exs" diff --git a/phoenix-1.6/hello_world/config/dev.exs b/phoenix-1.6/hello_world/config/dev.exs new file mode 100644 index 000000000..491e9a5ea --- /dev/null +++ b/phoenix-1.6/hello_world/config/dev.exs @@ -0,0 +1,65 @@ +import Config + +# For development, we disable any cache and enable +# debugging and code reloading. +# +# The watchers configuration can be used to run external +# watchers to your application. For example, we use it +# with esbuild to bundle .js and .css sources. +config :hello_world, HelloWorldWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. + # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. + http: [ip: {127, 0, 0, 1}, port: 4000], + check_origin: false, + code_reloader: true, + debug_errors: true, + secret_key_base: "Q5wEsVNF2nz33JqGizo4fN+WW/RrB9n4D5t6hHq0CjMfvp0Kwl4qIaq4iF7Tc5oY", + watchers: [ + # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args) + esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]} + ] + +# ## SSL Support +# +# In order to use HTTPS in development, a self-signed +# certificate can be generated by running the following +# Mix task: +# +# mix phx.gen.cert +# +# Note that this task requires Erlang/OTP 20 or later. +# Run `mix help phx.gen.cert` for more information. +# +# The `http:` config above can be replaced with: +# +# https: [ +# port: 4001, +# cipher_suite: :strong, +# keyfile: "priv/cert/selfsigned_key.pem", +# certfile: "priv/cert/selfsigned.pem" +# ], +# +# If desired, both `http:` and `https:` keys can be +# configured to run both http and https servers on +# different ports. + +# Watch static and templates for browser reloading. +config :hello_world, HelloWorldWeb.Endpoint, + live_reload: [ + patterns: [ + ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", + ~r"priv/gettext/.*(po)$", + ~r"lib/hello_world_web/(live|views)/.*(ex)$", + ~r"lib/hello_world_web/templates/.*(eex)$" + ] + ] + +# Do not include metadata nor timestamps in development logs +config :logger, :console, format: "[$level] $message\n" + +# Set a higher stacktrace during development. Avoid configuring such +# in production as building large stacktraces may be expensive. +config :phoenix, :stacktrace_depth, 20 + +# Initialize plugs at runtime for faster development compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/hello_world/config/prod.exs b/phoenix-1.6/hello_world/config/prod.exs new file mode 100644 index 000000000..1ffa41952 --- /dev/null +++ b/phoenix-1.6/hello_world/config/prod.exs @@ -0,0 +1,49 @@ +import Config + +# For production, don't forget to configure the url host +# to something meaningful, Phoenix uses this information +# when generating URLs. +# +# Note we also include the path to a cache manifest +# containing the digested version of static files. This +# manifest is generated by the `mix phx.digest` task, +# which you should run after static files are built and +# before starting your production server. +config :hello_world, HelloWorldWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" + +# Do not print debug messages in production +config :logger, level: :info + +# ## SSL Support +# +# To get SSL working, you will need to add the `https` key +# to the previous section and set your `:url` port to 443: +# +# config :hello_world, HelloWorldWeb.Endpoint, +# ..., +# url: [host: "example.com", port: 443], +# https: [ +# ..., +# port: 443, +# cipher_suite: :strong, +# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), +# certfile: System.get_env("SOME_APP_SSL_CERT_PATH") +# ] +# +# The `cipher_suite` is set to `:strong` to support only the +# latest and more secure SSL ciphers. This means old browsers +# and clients may not be supported. You can set it to +# `:compatible` for wider support. +# +# `:keyfile` and `:certfile` expect an absolute path to the key +# and cert in disk or a relative path inside priv, for example +# "priv/ssl/server.key". For all supported SSL configuration +# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 +# +# We also recommend setting `force_ssl` in your endpoint, ensuring +# no data is ever sent via http, always redirecting to https: +# +# config :hello_world, HelloWorldWeb.Endpoint, +# force_ssl: [hsts: true] +# +# Check `Plug.SSL` for all available options in `force_ssl`. diff --git a/phoenix-1.6/hello_world/config/runtime.exs b/phoenix-1.6/hello_world/config/runtime.exs new file mode 100644 index 000000000..9498fc0f7 --- /dev/null +++ b/phoenix-1.6/hello_world/config/runtime.exs @@ -0,0 +1,68 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/hello_world start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :hello_world, HelloWorldWeb.Endpoint, server: true +end + +if config_env() == :prod do + # The secret key base is used to sign/encrypt cookies and other secrets. + # A default value is used in config/dev.exs and config/test.exs but you + # want to use a different value for prod and you most likely don't want + # to check this value into version control, so we use an environment + # variable instead. + secret_key_base = + System.get_env("SECRET_KEY_BASE") || + raise """ + environment variable SECRET_KEY_BASE is missing. + You can generate one by calling: mix phx.gen.secret + """ + + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + + config :hello_world, HelloWorldWeb.Endpoint, + url: [host: host, port: 443, scheme: "https"], + http: [ + # Enable IPv6 and bind on all interfaces. + # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. + # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html + # for details about using IPv6 vs IPv4 and loopback vs public addresses. + ip: {0, 0, 0, 0, 0, 0, 0, 0}, + port: port + ], + secret_key_base: secret_key_base + + # ## Configuring the mailer + # + # In production you need to configure the mailer to use a different adapter. + # Also, you may need to configure the Swoosh API client of your choice if you + # are not using SMTP. Here is an example of the configuration: + # + # config :hello_world, HelloWorld.Mailer, + # adapter: Swoosh.Adapters.Mailgun, + # api_key: System.get_env("MAILGUN_API_KEY"), + # domain: System.get_env("MAILGUN_DOMAIN") + # + # For this example you need include a HTTP client required by Swoosh API client. + # Swoosh supports Hackney and Finch out of the box: + # + # config :swoosh, :api_client, Swoosh.ApiClient.Hackney + # + # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. +end diff --git a/phoenix-1.6/hello_world/config/test.exs b/phoenix-1.6/hello_world/config/test.exs new file mode 100644 index 000000000..5eaa121ce --- /dev/null +++ b/phoenix-1.6/hello_world/config/test.exs @@ -0,0 +1,18 @@ +import Config + +# We don't run a server during test. If one is required, +# you can enable the server option below. +config :hello_world, HelloWorldWeb.Endpoint, + http: [ip: {127, 0, 0, 1}, port: 4002], + secret_key_base: "VWT3k+lM0qw5c6ITamiuZSdLKFBV8W6TkPuxF6wq541G+rIPJZNOL9Yh+Du5WUsr", + server: false + +# In test we don't send emails. +config :hello_world, HelloWorld.Mailer, + adapter: Swoosh.Adapters.Test + +# Print only warnings and errors during test +config :logger, level: :warn + +# Initialize plugs at runtime for faster test compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/hello_world/lib/hello_world.ex b/phoenix-1.6/hello_world/lib/hello_world.ex new file mode 100644 index 000000000..944ff14a0 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world.ex @@ -0,0 +1,9 @@ +defmodule HelloWorld do + @moduledoc """ + HelloWorld keeps the contexts that define your domain + and business logic. + + Contexts are also responsible for managing your data, regardless + if it comes from the database, an external API or others. + """ +end diff --git a/phoenix-1.6/hello_world/lib/hello_world/application.ex b/phoenix-1.6/hello_world/lib/hello_world/application.ex new file mode 100644 index 000000000..d9d15329f --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world/application.ex @@ -0,0 +1,34 @@ +defmodule HelloWorld.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + children = [ + # Start the Telemetry supervisor + HelloWorldWeb.Telemetry, + # Start the PubSub system + {Phoenix.PubSub, name: HelloWorld.PubSub}, + # Start the Endpoint (http/https) + HelloWorldWeb.Endpoint + # Start a worker by calling: HelloWorld.Worker.start_link(arg) + # {HelloWorld.Worker, arg} + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: HelloWorld.Supervisor] + Supervisor.start_link(children, opts) + end + + # Tell Phoenix to update the endpoint configuration + # whenever the application is updated. + @impl true + def config_change(changed, _new, removed) do + HelloWorldWeb.Endpoint.config_change(changed, removed) + :ok + end +end diff --git a/phoenix-1.6/hello_world/lib/hello_world/mailer.ex b/phoenix-1.6/hello_world/lib/hello_world/mailer.ex new file mode 100644 index 000000000..847f89ff3 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world/mailer.ex @@ -0,0 +1,3 @@ +defmodule HelloWorld.Mailer do + use Swoosh.Mailer, otp_app: :hello_world +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web.ex b/phoenix-1.6/hello_world/lib/hello_world_web.ex new file mode 100644 index 000000000..3f655ac3e --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web.ex @@ -0,0 +1,110 @@ +defmodule HelloWorldWeb do + @moduledoc """ + The entrypoint for defining your web interface, such + as controllers, views, channels and so on. + + This can be used in your application as: + + use HelloWorldWeb, :controller + use HelloWorldWeb, :view + + The definitions below will be executed for every view, + controller, etc, so keep them short and clean, focused + on imports, uses and aliases. + + Do NOT define functions inside the quoted expressions + below. Instead, define any helper function in modules + and import those modules here. + """ + + def controller do + quote do + use Phoenix.Controller, namespace: HelloWorldWeb + + import Plug.Conn + import HelloWorldWeb.Gettext + alias HelloWorldWeb.Router.Helpers, as: Routes + end + end + + def view do + quote do + use Phoenix.View, + root: "lib/hello_world_web/templates", + namespace: HelloWorldWeb + + # Import convenience functions from controllers + import Phoenix.Controller, + only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1] + + # Include shared imports and aliases for views + unquote(view_helpers()) + end + end + + def live_view do + quote do + use Phoenix.LiveView, + layout: {HelloWorldWeb.LayoutView, "live.html"} + + unquote(view_helpers()) + end + end + + def live_component do + quote do + use Phoenix.LiveComponent + + unquote(view_helpers()) + end + end + + def component do + quote do + use Phoenix.Component + + unquote(view_helpers()) + end + end + + def router do + quote do + use Phoenix.Router + + import Plug.Conn + import Phoenix.Controller + import Phoenix.LiveView.Router + end + end + + def channel do + quote do + use Phoenix.Channel + import HelloWorldWeb.Gettext + end + end + + defp view_helpers do + quote do + # Use all HTML functionality (forms, tags, etc) + use Phoenix.HTML + + # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc) + import Phoenix.LiveView.Helpers + + # Import basic rendering functionality (render, render_layout, etc) + import Phoenix.View + + import HelloWorldWeb.ErrorHelpers + import HelloWorldWeb.Gettext + alias HelloWorldWeb.Router.Helpers, as: Routes + end + end + + @doc """ + When used, dispatch to the appropriate controller/view/etc. + """ + defmacro __using__(which) when is_atom(which) do + apply(__MODULE__, which, []) + end +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/controllers/page_controller.ex b/phoenix-1.6/hello_world/lib/hello_world_web/controllers/page_controller.ex new file mode 100644 index 000000000..d4001c9e7 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/controllers/page_controller.ex @@ -0,0 +1,7 @@ +defmodule HelloWorldWeb.PageController do + use HelloWorldWeb, :controller + + def index(conn, _params) do + render(conn, "index.html") + end +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/endpoint.ex b/phoenix-1.6/hello_world/lib/hello_world_web/endpoint.ex new file mode 100644 index 000000000..5d6356180 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/endpoint.ex @@ -0,0 +1,49 @@ +defmodule HelloWorldWeb.Endpoint do + use Phoenix.Endpoint, otp_app: :hello_world + + # The session will be stored in the cookie and signed, + # this means its contents can be read but not tampered with. + # Set :encryption_salt if you would also like to encrypt it. + @session_options [ + store: :cookie, + key: "_hello_world_key", + signing_salt: "XvoVic4F" + ] + + socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] + + # Serve at "/" the static files from "priv/static" directory. + # + # You should set gzip to true if you are running phx.digest + # when deploying your static files in production. + plug Plug.Static, + at: "/", + from: :hello_world, + gzip: false, + only: ~w(assets fonts images favicon.ico robots.txt) + + # Code reloading can be explicitly enabled under the + # :code_reloader configuration of your endpoint. + if code_reloading? do + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + plug Phoenix.LiveReloader + plug Phoenix.CodeReloader + end + + plug Phoenix.LiveDashboard.RequestLogger, + param_key: "request_logger", + cookie_key: "request_logger" + + plug Plug.RequestId + plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] + + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Phoenix.json_library() + + plug Plug.MethodOverride + plug Plug.Head + plug Plug.Session, @session_options + plug HelloWorldWeb.Router +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/gettext.ex b/phoenix-1.6/hello_world/lib/hello_world_web/gettext.ex new file mode 100644 index 000000000..9c0556fed --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/gettext.ex @@ -0,0 +1,24 @@ +defmodule HelloWorldWeb.Gettext do + @moduledoc """ + A module providing Internationalization with a gettext-based API. + + By using [Gettext](https://hexdocs.pm/gettext), + your module gains a set of macros for translations, for example: + + import HelloWorldWeb.Gettext + + # Simple translation + gettext("Here is the string to translate") + + # Plural translation + ngettext("Here is the string to translate", + "Here are the strings to translate", + 3) + + # Domain-based translation + dgettext("errors", "Here is the error message to translate") + + See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. + """ + use Gettext, otp_app: :hello_world +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/router.ex b/phoenix-1.6/hello_world/lib/hello_world_web/router.ex new file mode 100644 index 000000000..aae690e82 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/router.ex @@ -0,0 +1,56 @@ +defmodule HelloWorldWeb.Router do + use HelloWorldWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_live_flash + plug :put_root_layout, {HelloWorldWeb.LayoutView, :root} + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + scope "/", HelloWorldWeb do + pipe_through :browser + + get "/", PageController, :index + end + + # Other scopes may use custom stacks. + # scope "/api", HelloWorldWeb do + # pipe_through :api + # end + + # Enables LiveDashboard only for development + # + # If you want to use the LiveDashboard in production, you should put + # it behind authentication and allow only admins to access it. + # If your application does not have an admins-only section yet, + # you can use Plug.BasicAuth to set up some basic authentication + # as long as you are also using SSL (which you should anyway). + if Mix.env() in [:dev, :test] do + import Phoenix.LiveDashboard.Router + + scope "/" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: HelloWorldWeb.Telemetry + end + end + + # Enables the Swoosh mailbox preview in development. + # + # Note that preview only shows emails that were sent by the same + # node running the Phoenix server. + if Mix.env() == :dev do + scope "/dev" do + pipe_through :browser + + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/telemetry.ex b/phoenix-1.6/hello_world/lib/hello_world_web/telemetry.ex new file mode 100644 index 000000000..bce99d5b2 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/telemetry.ex @@ -0,0 +1,48 @@ +defmodule HelloWorldWeb.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp periodic_measurements do + [ + # A module, function and arguments to be invoked periodically. + # This function must call :telemetry.execute/3 and a metric must be added above. + # {HelloWorldWeb, :count_users, []} + ] + end +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/app.html.heex b/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/app.html.heex new file mode 100644 index 000000000..169aed956 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/app.html.heex @@ -0,0 +1,5 @@ +
+ + + <%= @inner_content %> +
diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/live.html.heex b/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/live.html.heex new file mode 100644 index 000000000..a29d60448 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/live.html.heex @@ -0,0 +1,11 @@ +
+ + + + + <%= @inner_content %> +
diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/root.html.heex b/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/root.html.heex new file mode 100644 index 000000000..ddf1c1a18 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/templates/layout/root.html.heex @@ -0,0 +1,30 @@ + + + + + + + + <%= live_title_tag assigns[:page_title] || "HelloWorld", suffix: " · Phoenix Framework" %> + + + + +
+
+ + +
+
+ <%= @inner_content %> + + diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/templates/page/index.html.heex b/phoenix-1.6/hello_world/lib/hello_world_web/templates/page/index.html.heex new file mode 100644 index 000000000..7582aee5e --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/templates/page/index.html.heex @@ -0,0 +1,41 @@ +
+

Hello World!

+

Melting minds from prototype to production

+
+ +
+ + +
diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/views/error_helpers.ex b/phoenix-1.6/hello_world/lib/hello_world_web/views/error_helpers.ex new file mode 100644 index 000000000..89f8cf016 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/views/error_helpers.ex @@ -0,0 +1,47 @@ +defmodule HelloWorldWeb.ErrorHelpers do + @moduledoc """ + Conveniences for translating and building error messages. + """ + + use Phoenix.HTML + + @doc """ + Generates tag for inlined form input errors. + """ + def error_tag(form, field) do + Enum.map(Keyword.get_values(form.errors, field), fn error -> + content_tag(:span, translate_error(error), + class: "invalid-feedback", + phx_feedback_for: input_name(form, field) + ) + end) + end + + @doc """ + Translates an error message using gettext. + """ + def translate_error({msg, opts}) do + # When using gettext, we typically pass the strings we want + # to translate as a static argument: + # + # # Translate "is invalid" in the "errors" domain + # dgettext("errors", "is invalid") + # + # # Translate the number of files with plural rules + # dngettext("errors", "1 file", "%{count} files", count) + # + # Because the error messages we show in our forms and APIs + # are defined inside Ecto, we need to translate them dynamically. + # This requires us to call the Gettext module passing our gettext + # backend as first argument. + # + # Note we use the "errors" domain, which means translations + # should be written to the errors.po file. The :count option is + # set by Ecto and indicates we should also apply plural rules. + if count = opts[:count] do + Gettext.dngettext(HelloWorldWeb.Gettext, "errors", msg, msg, count, opts) + else + Gettext.dgettext(HelloWorldWeb.Gettext, "errors", msg, opts) + end + end +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/views/error_view.ex b/phoenix-1.6/hello_world/lib/hello_world_web/views/error_view.ex new file mode 100644 index 000000000..e2314a13f --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/views/error_view.ex @@ -0,0 +1,16 @@ +defmodule HelloWorldWeb.ErrorView do + use HelloWorldWeb, :view + + # If you want to customize a particular status code + # for a certain format, you may uncomment below. + # def render("500.html", _assigns) do + # "Internal Server Error" + # end + + # By default, Phoenix returns the status message from + # the template name. For example, "404.html" becomes + # "Not Found". + def template_not_found(template, _assigns) do + Phoenix.Controller.status_message_from_template(template) + end +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/views/layout_view.ex b/phoenix-1.6/hello_world/lib/hello_world_web/views/layout_view.ex new file mode 100644 index 000000000..09a7cd49a --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/views/layout_view.ex @@ -0,0 +1,7 @@ +defmodule HelloWorldWeb.LayoutView do + use HelloWorldWeb, :view + + # Phoenix LiveDashboard is available only in development by default, + # so we instruct Elixir to not warn if the dashboard route is missing. + @compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}} +end diff --git a/phoenix-1.6/hello_world/lib/hello_world_web/views/page_view.ex b/phoenix-1.6/hello_world/lib/hello_world_web/views/page_view.ex new file mode 100644 index 000000000..ad0f45457 --- /dev/null +++ b/phoenix-1.6/hello_world/lib/hello_world_web/views/page_view.ex @@ -0,0 +1,3 @@ +defmodule HelloWorldWeb.PageView do + use HelloWorldWeb, :view +end diff --git a/phoenix-1.6/hello_world/mix.exs b/phoenix-1.6/hello_world/mix.exs new file mode 100644 index 000000000..c569936c7 --- /dev/null +++ b/phoenix-1.6/hello_world/mix.exs @@ -0,0 +1,64 @@ +defmodule HelloWorld.MixProject do + use Mix.Project + + def project do + [ + app: :hello_world, + version: "0.1.0", + elixir: "~> 1.12", + elixirc_paths: elixirc_paths(Mix.env()), + # compilers: [:gettext] ++ Mix.compilers(), + start_permanent: Mix.env() == :prod, + aliases: aliases(), + deps: deps() + ] + end + + # Configuration for the OTP application. + # + # Type `mix help compile.app` for more information. + def application do + [ + mod: {HelloWorld.Application, []}, + extra_applications: [:logger, :runtime_tools] + ] + end + + # Specifies which paths to compile per environment. + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] + + # Specifies your project dependencies. + # + # Type `mix help deps` for examples and options. + defp deps do + [ + {:phoenix, "~> 1.6.15"}, + {:phoenix_html, "~> 3.0"}, + {:phoenix_live_reload, "~> 1.2", only: :dev}, + {:phoenix_live_view, "~> 0.17.5"}, + {:floki, ">= 0.30.0", only: :test}, + {:phoenix_live_dashboard, "~> 0.6"}, + {:esbuild, "~> 0.4", runtime: Mix.env() == :dev}, + {:swoosh, "~> 1.3"}, + {:telemetry_metrics, "~> 0.6"}, + {:telemetry_poller, "~> 1.0"}, + {:gettext, "~> 0.18"}, + {:jason, "~> 1.2"}, + {:plug_cowboy, "~> 2.5"} + ] + end + + # Aliases are shortcuts or tasks specific to the current project. + # For example, to install project dependencies and perform other setup tasks, run: + # + # $ mix setup + # + # See the documentation for `Mix` for more info on aliases. + defp aliases do + [ + setup: ["deps.get"], + "assets.deploy": ["esbuild default --minify", "phx.digest"] + ] + end +end diff --git a/phoenix-1.6/hello_world/mix.lock b/phoenix-1.6/hello_world/mix.lock new file mode 100644 index 000000000..47b126398 --- /dev/null +++ b/phoenix-1.6/hello_world/mix.lock @@ -0,0 +1,29 @@ +%{ + "castore": {:hex, :castore, "1.0.1", "240b9edb4e9e94f8f56ab39d8d2d0a57f49e46c56aced8f873892df8ff64ff5a", [:mix], [], "hexpm", "b4951de93c224d44fac71614beabd88b71932d0b1dea80d2f80fb9044e01bbb3"}, + "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, + "esbuild": {:hex, :esbuild, "0.6.1", "a774bfa7b4512a1211bf15880b462be12a4c48ed753a170c68c63b2c95888150", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "569f7409fb5a932211573fc20e2a930a0d5cf3377c5b4f6506c651b1783a1678"}, + "expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"}, + "gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"}, + "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, + "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, + "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"}, + "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.14", "5ec615d4d61bf9d4755f158bd6c80372b715533fe6d6219e12d74fb5eedbeac1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "afeb6ba43ce329a6f7fc1c9acdfc6d3039995345f025febb7f409a92f6faebd3"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"}, + "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"}, + "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, + "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, +} diff --git a/phoenix-1.6/hello_world/priv/gettext/en/LC_MESSAGES/errors.po b/phoenix-1.6/hello_world/priv/gettext/en/LC_MESSAGES/errors.po new file mode 100644 index 000000000..cdec3a113 --- /dev/null +++ b/phoenix-1.6/hello_world/priv/gettext/en/LC_MESSAGES/errors.po @@ -0,0 +1,11 @@ +## `msgid`s in this file come from POT (.pot) files. +## +## Do not add, change, or remove `msgid`s manually here as +## they're tied to the ones in the corresponding POT file +## (with the same domain). +## +## Use `mix gettext.extract --merge` or `mix gettext.merge` +## to merge POT files into PO files. +msgid "" +msgstr "" +"Language: en\n" diff --git a/phoenix-1.6/hello_world/priv/gettext/errors.pot b/phoenix-1.6/hello_world/priv/gettext/errors.pot new file mode 100644 index 000000000..d6f47fa87 --- /dev/null +++ b/phoenix-1.6/hello_world/priv/gettext/errors.pot @@ -0,0 +1,10 @@ +## This is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here has no +## effect: edit them in PO (`.po`) files instead. + diff --git a/phoenix-1.6/hello_world/priv/static/favicon.ico b/phoenix-1.6/hello_world/priv/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..73de524aaadcf60fbe9d32881db0aa86b58b5cb9 GIT binary patch literal 1258 zcmbtUO>fgM7{=qN=;Mz_82;lvPEdVaxv-<-&=sZLwab?3I zBP>U*&(Hv<5n@9ZQ$vhg#|u$Zmtq8BV;+W*7(?jOx-{r?#TE&$Sdq77MbdJjD5`-q zMm_z(jLv3t>5NhzK{%aG(Yudfpjd3AFdKe2U7&zdepTe>^s(@!&0X8TJ`h+-I?84Ml# literal 0 HcmV?d00001 diff --git a/phoenix-1.6/hello_world/priv/static/images/phoenix.png b/phoenix-1.6/hello_world/priv/static/images/phoenix.png new file mode 100644 index 0000000000000000000000000000000000000000..9c81075f63d2151e6f40e9aa66f665749a87cc6a GIT binary patch literal 13900 zcmaL8WmsF?7A@RTTCBLc6?b=ccXxso4H~R1?gT4RtT+@6?yiLril%4@T7niU{_*z6 z{eIkY^CMY%XUs9jnrrU0pClu(+L}t3=w#^6o;|}(O%cy#x4LjZZH1q*$X;nePbVE4Ruj~ha0EO zKNwDso99#XvuEN`AWs{Bi@gtxt-YhOy9C{FXD=O%vz-K;k$?ubhNqmple2Q5m%Uz~ zramCh1t4NaCnZTE4ibGLaI^QZp#izMx_gU)Bn$}9dm*VB;%os*A`rzjVfzrR1HKOd)umm?RCh=|BP9K5_7PY4e00Cyi75Qn=r z{eKwb?Y#kB&YnKb9_}>%FxuF9`1(lDJt_Uy6x=-jOY83a?=n3Vj0LBly^W8Dm%fLG z>wl`K?d0L(;qBz%Nh7BxK%-#;aCZOa_%B{VLsZ4x+sDQoV6P%CLHESK>FjJL%Eu=o zC@9Y_#G@c6$it(+FQO9uXOy|HR6B0DRr--F^NOYxjR*h5u*lKds>A z`IK4S-pkp~-cHfW!;R+eltrEYw-$l_$@lMAyZ^04@PEc~J&ED^XJP+;3;mx{Pu=s+ z@V{;QbnxHCw|9T)cCV+l_Rhg0diIRBPeoovAGCCkhmu7!e=!0j%CIc1U{;0rzhnzj zRH%Ot=y$J%$R~ap!UOQPkR*PGC6W<##xjgp8{rXFTPGUhD7@5RKexzmd%We{#b|6i z`?lh2^&{jx)SK#0PhPgi&eUZ0vBcGiH`@-FoRy{i3j{L(leZ-WVvvA2{XVGbnr9s* zG$JW*Sqd>q(BQkwNG{TIu68tN%oQnb6^FFNR~xPl$I zm|>W*j{xhT(g3sl-2z1KY@&qA0a~--8mlbo6MSY3Sy29DZRC=_#b9K&IcW(xbn3qD zali;DIL*NQ2a>E?#=CXQMk;2IJDpfLGR5_w?UEM;`!OQP>sJa904@JRBdgqw<{A-f zPODilVldJY3tG8mjj<9Cq%HNX;km>BP=EQ!_>VT)lC6`dm~$b&B*aCJ*_t6bQD*XIIA zrrq#>z~6ik=?Q&P-|3PvgPI@=_MRFRi5f&qlac?_B_cT$A11<`f;&+p^s(QUcKGMS zNYwS6+Y109HVx5PCw$%fR|2X^WJR_R&T>NOOaXhEOOBl@ACRbf{Q38g%!l_W!fCv{ zyn=GMr7&FEFtoISlT(_%iFGOyAW*%LTFx{?IMb~HaOTxco0(xXa`wb0B-{sjpkZ9F zbnZMIZIc!;=Qqv2^WY_d{p1IDf88Rxts3(SLO{5`#Xi5aUOr5);GFV06(V2G0%QE` zw{cbL@W!uuqA3n1q)>mMxU?wl*Pwndp(E*^iJ@$Hm4EfeJ`y=_@(E_@&+FH@D;5#% z%5izR;P_>FEfS3Nmq*3SI-GpsAP~&&m$citnCRwyK%Fs4!m6qG(fj((-y-2~&7)oQ z4#JKn4nA=SUWP)V&DUvjP#Hz?-yUdXY;@ zNlmhBn0p;i0j^5OqhqN%)6E;;VN5UVdzE$GmIS%ZKVBDViH>uKNOQ&Uq5yG0Dlp-V zTpnO8cV6#UAk z)?vp{kNcLNu9V6yaw#|j*h9p`zNZJMyYcx_9Zx@es61Md4Nc*y09>UV7@wE@EGya!%G<~=$Cg%(LWWrD<&NXYR$#UpU; zl-N8X3auH&u_czz`2@`)@9^Q(Z%i7Hf=u*EDPZM>R2Fk4J#Q=0-x+Y2G~abPx7&Ra z2NL1RzJ6GzOMmMRqU6 z$VT^YqYCg33>3Q}C1=wdL-qO~RY!>-RljOAeEMmD^wu(R)f~VT!$Ug{0mvR$s&%fPY=gWk9kNN8m)<5-VE?(DW&De z_K7#3AU;h7d9k4~t}aji!~JOUAShjMOMAIETdSX?IMsgoD0hRthVvFz_Pv zdB+jF*ZW#({d2~{sX9F*h~py)k>5uVOoN%aFYVn4R`h41lz|0c2VZIB=nppL5y=g> zu!5%WhCXBkP}Z@2N_Vz!AzjR@qHsS0JYuj-#`U;&ZpDXpK_mAhyos?3Q{PNOL0pmg zC+VYZt}AEuYBcotKWk`m>a(=zjXxDB3#5Um zVOPP7@tHWfoJhBge!5gA4xHSVT7cu2&GC^pQ`A)wCChhgTf&%uxo`T!dK!h-3`){W zpvJr6%XD*gpM-&tSGPXMc(X9$3n{M4OiY7A9Xmh?(uP=TgDFkP-egM4nbFfm?^>b$ zOW3Npm^VN^_io|YL=pYnX73Ft-K|c|A1*#YT?(+WskD4SwQN8cBq))xT(;M{@0~D8 zL`ANR>lb0mKLRtNENx&SAp>P7857a%ZP{0S3snYW+tbd!X-*{GL}**b@G};C z)Q3bSoD}bG=Jx$POx1UDzM= z`-IZDl+GJgv`ehIT0``{&WDsH3nEG03F1%AU(!=nGsjuyzcneB{{lp{>#5)ndCUO;OINf(7fpu|jyopb#q zlcAO8B?*00y0gq?{w~Rm#QuV^oj)tPcv!7-@bCr?Zk?hlTDK)}c8r_PG$e2Sxtqkw znT9qczCHX17&fsDl3Vm2V-Aarj3y0gN1oyt+l*_2>We#0j5b%9+SO=cHnf?jhBVL* zc#p)VMKXMa?+hxBt}v^^v`27e&jC%v7U zYKYuMhjG$Ix{NA9pgZ+vM>wy}WFw4vHwJAgeD0=m%D2|9gU5(o73(HHxx~ z$`tS4W>`?peBKOuh2OZWrn>N15K@lt?#^(;0WnTZ?_LtcuN$kZ4>wSZ(5iUWZ$`jTC z_ci7nCc@Rp`ZOBltEe^pK#3|uV{VnV_K305Q3%H-7{5pCjN#f=F$6GY0!$*`&2k!S zIddNLT9i~PSY$C(Vk}fNjSg5anR_qHRGpDH-%`M=-M#Uy)$8I8o`groI|!?V_x3%D z*jIq7JKZ%3t7W0A9=PatJ(#|9PuiW+t}h-&qnBZ5P*GhxNr~gqcYtmMghEcf1;N$b z?-KJjMQTx=;qx4;2QzXIHdtmV{?c(qZn=JMuV7*~^o}L0PZRG-cNY-v$m+tCNWA;qfeK|Ja$ z?dtZ+=kKMyDZQ?#yBJCu@vCPRGRG#W=#Uqy7gWdT#9=CV-aUP``ekX{im2fj$(ICH zrqyj>sx@=@VhTUP^u8#smC#HX@iA!B1&~*#t~u+7Nq74FS*V0Q0?u(R5}(HKHeXU| zaX6UE!_YCc0<@~U?km)OK|HeGDJuLE1en`EE(|f3b_8Kc>^KoR$h}C4y*efcDc79k z)u3b4(j8swz`YC~>rtU}6ui^r7(E_B<4DBV|5_E&6Rp|K-w*sw)y8zPZhwG05z^^w zLRAg*Our%j74=A`>3&;5GjxWvxa*y0L3)y#_vIKsT*HJxThAl=kcG%Qs?J-inZbh@ zq`FJ)@rN?G3!zzcyL6$GtD~<-+L`H#r!{AWlr~}E%2bRDzO|+VWq4@vyEP<&_QmKI7yfHm7c|~ zkdcGa5KJs;WE|^Wm#k^lqqyS>>?&VZTzP8uAppMl3)U|MmG^Sp-h8%HE>eK^IF3|u z6blQxe|+599-P{(w9u$@#Po)>v4I0!Sh_Zp$De)M6#l5 zMLd&@Q!>%r&X>3(dy1Sy?PO++U1`I)&{?M@Uo z%#2bAa3&rk<63k``;b?*UQ=TG&ME|}*pK;D6(8EIW`d64<`Ai~rNBrJ{k%38h0VrZ z)(*?!ceIz6p#l3bgLvo%tKy^07Gr2rg@|ENO0eGhf^tf4;XC)3w)a9%k-CFMjbN)`@oRUehd@f#YrH`!qtJ(}CQ8lR z+MUwQHG!ZjF=2+LRco1w;NA)|e&(F=;@5@~YvQ*}WwH|1 zW{l!fpO$_sGYm*FDc`WXx|&tI;x;P(o+0HlocYS>GuQ0YJ}uF5G$wr!TF%IET{Q4|>d}!k>Q%%+Z{vc^)k{}BmP<=f)KU-84}F(W3?QXO?M&M_+fH%H zP1RGVhy8_TH3xc5er1$IF9!{db){AF1?8D6r6x6UC#X=y=*ObiCe zZ|cKVcuN6?)kxDj?`&dz$0gLFecX{V&Au;2g)e>UH(kt49)MhGU9UX2($=TV6dnKe zCR!eldvubP@OGmDCuf$w`Jo*ml6I!*Z&(Oa{eaWP`8m*aE|7#?ovVrug{PNqINSdu z@u72)Vd`WJ6OYNAB#+hOE$k8B(PtN)wdfZ;ELi6(7IlI>Ir~TU<;xx4Tn0^Lm885k z!2|CbsSv##hl_!eoJ#>wpS`2KtE(5CZ!Hf~l*~7UMiIR+&UO9*juK5%YYJjtkERgP zggP=dxb4%E8W((`2g)%g?g>E+RZW)7*L)HMnl}Lnu;J?<6ODpm3RLPGq6Vl;z|aNp z5*5uzK$K)Bp{dY?A*8crtu--(0(l+bO&*>5!u!KQD+;nt(a~g^`=2T;v-g>ul$x_u zLcQ{AV+YeSFP`@OYqz>QCGH1>^M==xc=@-W?jSBT@vfSWgAluU7WT?eutjJ2$9ZSdl;^rlm2JPtQ%6@Y$l7(6B9 zlqVdq@F&qdugX5%1MkA<3y`rQM$#0zn1``Jaacc^tu(EL=wALU?vJ70Xwx&+^%@ab z;OsbwDLNe;#0Iv-_)%@b(BG3aEi4P?nhDFaEm@06YtqSK88&-%%KNKLjXM)jlt$0d z(q8vr_pCL!w|MrQ((|ceeWT@-V(H#9J;(%sS2B8f8}xNox|N@GD5loR?9+n2fWKZY zc(Y*>gX85*ALqgajeA^)lhbXRioH>St-U3|TRjZd87wh*%kX(J1H3jQhhtV+p3fcPQ>XQUKsF9mm zoH!0Sr&YY;%y1%&bJqhNV_vk;?sx~5__YLXe|G`Bd!GququTI(0J-~}A@a(HCwYmO zWj>cDZ4_FKb}1f&lN4TD2*1zVVhK*wFN*D6oRC-~%)GsE{(N>owOd z%1cRV&^^^z@YP_}sI0j+rz_3|Zk9B;z|^}WEhV^Bpm;=Uf9IpY5Fn6A|FO@j7Z8&B z96ZFHGbnNB^C(Vfa20auH(3;B>~V!Yon}t?kpi_J#_}@sKCrK4uY_Xf`p7hv`XQ=8 zWNp{9H3nF%DY43p1+@_OnTmXtj z%WgVqwJ!5UnSrBy?rhLiXKT?d}y73{iOJdN@mhf#J?H_awxEp#WUbKF{0}s=woC6Y47);j* z8rB1{w*AVT>0NSmFtEae;*67g8T_nxO0c+ov@>{eu5n{@#RGTr>^Bb8=wBEbB;0`7 zz|!xSHUh-AuPL^G!?~=j#GR%GzgKr%icju#i74clZV*{+CP!VXw1lVu78LdOSdw{V z{4*;Lt7ier$fJSEz6+QygOA+}x_4ilo(2pO&gO2#M3YigPU!~HbZzFpPP(m(7_Dq( z6E$iYyBlF8m8$F1Cuz4}csC&yn=cM8WVgfaL&h75{Shd3)~!cR zCrAVcxl!YrKl=V^piF14E39&aLJVb9-eT+g2xImTQ%l7;}SHq_(LSbo^EM-HXXtZ0O zdW3nm2Xc86CsIwEsbP>@Q~2ojkx)cvw^BKDjB5;4cJZr2KyPiMdSz9LK~+wi4%NKr zbN2DsiY=l;nH8!iP250F?V2V~z(9!|pVCyX9mL_@_ zlcc-NP!BZ_1zEf>pRi=1_Kqh(3X+M9b?No%R8SQvDbofi&Fz$Vs(U!_CusVn+==X` z4cUNCy9%^!gq7dHZ(d7yf82(&o(5y7mF`*OIvT28jRocQywzcRqsbN4HuB~hLSmiP z1-e(k^;S23LfRT&ykT>g@~+hOx!lg!Sf~$2v?1w2ja>QgaJtM|?p@SM9&ls$0J<8;>A`IHQY5INUj<+t`aZ}v)4 zTMv2I_QwzEM=Wg(QohmrlBbJ|jcKc6rM(eJ>_{Ce7!j7Wl-87@z;z5`*K8^*wY?^P zXZWbVI~{|7l7A`bsQ034<(8h(+iSK&8}ijuX4p=^0dk;0zaKuYr~S&idu-;u+p3y# zh&LfPIM%YArf&^E-XlY^y8hl$%bp>Gi+MuNLb0pOLODZ47f-(U&F8UH%lFk)H3Pg8 zGX$RR8odn{YWkC>IU_o}?Bgs(hY9Wy8?sIR0}Vgrg%#6#9%R$r^539t@SnujcyONj zpE?(`U`-_m!Nt>6WU8?;PR;ou0f`wuvuj1xX4j}4+M{ZmBHI>~O54)>S3Z}=gNpD= z-B$ESnoSp)Ib~)v6o{j~ZKMpo4IJYIwwCY%v9+$k%2a=ut+ETf&f;R4JYriH_yjfh zcF16FMV7{Bm~xVwCmSeQ>{H^VpmBwKi?xX5tMS?s%PV;WKlk>RF2_ zaQ#KT_9dmokkCTOdHzpHF5DT*Q$Z=`2&Z8*iEw|IL>%}ep?*ArUV@HuU70}fr}vsu z7ct2;mYIn^8+D@M!HHQVZamDm4kufo_&Lv2PQ+;2qON&of3i4Z`6^WdW!GxVHw*o( z9RCu?86CO{>RZqmkKJi#IZw5A|C&P3R7~+e1O|KX>AO!{L~~2Q^j{VcJ?fn1_JtHu zo#68?Z;9QhCQ%>Wl+v*xbCBkOYksQ3ErxKmI#@o+=yEv*{noTagX`J);d!Sqs6~1- z_t3kU4AG&!bh}$vq8bSpCgNXZ%R$m zvOkBz6;t?`*dmP4KpQa6S(Tb1v2UM_yTrv=nIeEr4bEdkEf&tcKxgqz=0#_b6#}=d z<1+YBT8K_dgbVSiDuNBJv!Zzw;~H`1CnOI;NRH;M5O3aN0V4|fV%s{@tfO&#!{~vE zXkC?8J?SKAwT&lDA&ld*Yz*V@55gw}#xX07=)to%1He+@{4HiU*{$`=4_`dDSl!dE zrb@kaTRT7dc#5TRzxH}})^%cZIN6|2;?tLujjh6Ku4c*Pw+2LJ{e43$piypJ3@{zz z{ZyQ_eCg6H#lsA4@F@ubKQ?$Sr!)(1u-g0Y@!Y3D0$d`L8{h{xE*7}P)$8&a||XD*TfFRvL{%LTfbnlB1i z`xZ=4^3YZ0(&j19vpsX0>pdpp@?^hP1Lua|`g^OU4F@JZvt-JBeIhxTzTB`_7Ha(C zXpMKEgjelG#+Z1pH3QN?T{LaXLXs&7drY%!CjC6=jey#;hs!{-|i#z2tEed4Ti=&S3x@^6XZrGR|k} znjEuABs|D(T|wc}%1sHwoY(yB{a6Ys6`5RKt#YYI&kJ0bNGe4P*Uq9}0YZR`s>=o) z$^kQp3e)J59I>B@@PGAi_X6G%Sved~($wM_il`m%ViYFIyuN(JJ|msKAXrNRV#341 z1|2JQNES0Z;*5kT&$YHc%^PE`bnRw~uILz)Jn z)rtYuuV1r^>4a@XS-a!^ETgu|Hbj0rKjU`uCKq2mWUW!kEocyb*qm8%j`6#5FX;H5 zH}?G7Z?<6e>UQ1ZW!lOfGLsiJ6Cmv5nnJCrOjaP?lKh2^41eXWTy*hxjZKwSr_VJ}-~$&#D3 zzhiEKdrOMKKU0O4xvH7-t>i*p@I!2=k5-G?6tO+uraKwk8#JkfX*#Z{*%i}i_x~lXo^+A!ibrcM>WX|z89iEn| zyC2#BpijrGcW&p}+^3j>Wt$A*=Jrvh8ETLM8aKVsi0&;hlS@-###$Xy))F)OMv57; zZdh4t?c_)zrcUIaOVOUk1$;wMCE>D~-O=N0NFI9^e^C}x37OgGLo)!Q zl=io=P5JDB<$lI%4Y+J3XEphD`qO&Kd_8!yc<*ECCAvC#XTpXe+6u_cmTjEJ| znoqk>=_ZZ4uO5-(m)F08ceF!p<}!?TgW`7279=mKmj~~5tj;zg?PgUz-)5VMM%0j%)T?pU<0Uk|D3p5{2e??#5jMB{Y!BJEFH zuWNq7jM!7<2zWCvPQRj%cXAC#;y_}2ul?h8L$gjQfeIy;;;WXDudit7Uv|Z2b;SrX zfetgr<80WRG+xgFc;C!8+A#ako200^e2Q~AmM2ENwvrd`El^q3CVWk8#pR}l6cCg~ zUYS?4ylI87x!WdHAgi(~ry661S05Qi1wbZZh3H*x{Rw|u!|$*brVLWole{Fe)at#5 z&|6f+nmc3oc&?6vkxR;joiAOb9VuypZ0J$RUBbNxlH~&My}W2{rLRnL z_-^!!5*@@mLvLnIN0QiIhGHHqzPd<3m6&`Vvw8X{6CQBzCaG00F|!`5<-vmAC>~F}0=9+5g-X4W2>mQBUE2eh0%g|SqINm6Te;DOFibuJZ*{m1m-=$li zA>OF0B&aPG^YmL#sfV^T*RCPN%5N9BL>0$sDyvtimKQ1W9gBJ=5(@^odQd1zJ)8Lo(zG zeg;Iwc}daKZlFmS1a-tPNNEfJ99rixy+0qS+Sm5iq zL+jh*2DCx)TBOktKeP!XXqS-sX*+N5l;5o1VpaD@M%Pak^Vqbsa_Eo0WNcXh8i zafO?AZFRj;yl(n{r6|&IBA_<(2I?rB(2@jt?Fv>m#>YoLznm1vhc1`weTd-;OKNlU z7eAu`QWzX1>w@I0VgfW#HL`x)yyghsLOaU(#V{i%@fmXs*QfgI)M>KgCz&&%`=PNZ zPu+yGi`h*t8-5KMsj5_yxl+d&O}k-3yJGaH4TJX)ynmlzXsKl%oOgmmFTRO-s`ckV z&u!9meAquxYhwk+gHo^`Q|*lIBH2K=|B*NDyfTf|*+wzNwSNZ2hkhakih?%7j(lPT zD;YT{1@b6F_gc~lu)m$%A9Eb*aK&Q@qrFOd-)-p{v7hkz2lg2jw=-pNt0yOAU(svi zLYL#99x*+EkqXq&U$tR)E{^73j>i*upyP+bN9CfUhi~MgD<%5{I+<#AWsg?a)U-af z&|(T&_pI1K{XL`TB94{Ou)PPi5Y+MbOb^}#nvWufpZWaDcRLGjsu}h_miC|C;Ors| z=3G3ILzSiI!nCg+;$03@KDrVVI`VxANUQz+09hW z{~WkYa@aKYcKD$MeY0x*7Sec0vr5BAj`1Ov&~s(J`O2>w{g%{Jq-lIT_L=68?J+E* zGGTu~fpOk97y&7_Diw3aL;G8#ku@_Hyb)LWa$+&s zEF~rPhKO&PraSlge{A(pz0+TTl9mN_uDi-)@vS9E8zK$1amRo!FM&6Ys)yQdvVSt? zd&vc0p2sNLeK7sJ7^QO9Xkp(Tm$9A!ml{~8K2#1711%(JGl8Eh9QYUDKEx@cv!JHg)>??HhpzbPA3DM&~U< ze~Rf!mHiBTPgT>F;L?v|Ymp&(l9!ZA&Mt9(uv}|zk8-{XfKyu7vYP#;ao1qBoecXG zs7P|7#x6hY;x|`wfR2^)K5ub~0ncUzK+Ybe)UnPC7iajN`lE-k73KK}UD zKzHTYGesC!j*8N598|aVJHKu;Qd&wK$pOh<2p%XS*W6`g#nH`{4mC<`Tm8tWUzn}AWi3+;%dy%2o{JaR5Qy)!>H z%gz0!Cx`4fqYzD`j6j=|L6X8+kHP1A*E0lNx2(ItObT73J3_eKE@=MB4=jMRRrw62 zG<8C+vWR^_5OLT~3Brb~kl1OQ5_pGlWb@Ulbtbkbg~d5y_X_mvTrZdJ`R2u?sF<7U zZv~d(&CJ-A72TvW_u`}1Z=|JAbP7kMUj`&-f$L>F7R;6ggDkC*jsf|P&oalP8U8fK zT_2wdY0JFNakO#`swMjx zM!cT4Z}M9M_60r_9>16xcaX^`A9gqPZ`l_3nb%}8T`Chs482ZkvJhPcGX?jMR}=ah zTZDVQSSASC6SiqO@{GT!Qk?JszB*o9FY#TP6Dko7-f4$6V16IQQ`bDNN^kJC2IR;t zY?SB&z67>8I0W=}iwTS;u3x6J_59+L8+<7^p24|fLiU+*HlGuF3@?Ppk+A-3MnmFl z)qZ;$wA_$w?+0srI|;Kh_%r5`bfl_d$kA>k$+avzku2rs<@<_TvP^;(tTuzj zhE_CzlafJ^=I2x-PY=Nl5R<=t%`qL1pvH4;}21B9;( zkl_bYZ2+YII)|5v`(DLhC^8SK&@Rg;W2>Er#Wa&~W~5#GeHRr{N`OC4&x8mdeH^(Z zSo~{uE-6NJ{V*qLT*hB@@O-Qm!r>wH*J1pN8Ht>Ri`CHLtL;2>NxDqFb41bk*1z+J zhV>B-vfA2MMCt)_#) z3G~quaUUm>*(ov1gX?+|@8-u$!zgCPz9kxLJH$2OO{(l${;)=ie$@*MH+Dtp83U5!%o~k zPQ8KRJ141&WM*HM=`hd+PDS93YX&}Sllg@j-BHpM?!v8!WeV^^4DX@GQ`sea*>H?=b|NHgB}D2V9jt) zJ=prm-}$6M+ZsPel4vwOBmuhqij3Ujz<~(=Z+%`0#*Vm+M8&7Up%ajiBU{{m!_%D9 z1zJjlE#0`HNju{ds8|+m7h{Hj5#iNXfrHNd}8lmEE zQSW{7z*8sq+W$*S6LniEU?Z!#B?GdWkjUeg4$&N$;$N7gqx*-E<^6-zhv(0nSsJz2 UWxWXg`G1#+f~I_}taaG`2PLnS&Hw-a literal 0 HcmV?d00001 diff --git a/phoenix-1.6/hello_world/priv/static/robots.txt b/phoenix-1.6/hello_world/priv/static/robots.txt new file mode 100644 index 000000000..26e06b5f1 --- /dev/null +++ b/phoenix-1.6/hello_world/priv/static/robots.txt @@ -0,0 +1,5 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / diff --git a/phoenix-1.6/hello_world/test/hello_world_web/controllers/page_controller_test.exs b/phoenix-1.6/hello_world/test/hello_world_web/controllers/page_controller_test.exs new file mode 100644 index 000000000..6151e3a7b --- /dev/null +++ b/phoenix-1.6/hello_world/test/hello_world_web/controllers/page_controller_test.exs @@ -0,0 +1,8 @@ +defmodule HelloWorldWeb.PageControllerTest do + use HelloWorldWeb.ConnCase + + test "GET /", %{conn: conn} do + conn = get(conn, "/") + assert html_response(conn, 200) =~ "Welcome to Phoenix!" + end +end diff --git a/phoenix-1.6/hello_world/test/hello_world_web/views/error_view_test.exs b/phoenix-1.6/hello_world/test/hello_world_web/views/error_view_test.exs new file mode 100644 index 000000000..bfad82af6 --- /dev/null +++ b/phoenix-1.6/hello_world/test/hello_world_web/views/error_view_test.exs @@ -0,0 +1,14 @@ +defmodule HelloWorldWeb.ErrorViewTest do + use HelloWorldWeb.ConnCase, async: true + + # Bring render/3 and render_to_string/3 for testing custom views + import Phoenix.View + + test "renders 404.html" do + assert render_to_string(HelloWorldWeb.ErrorView, "404.html", []) == "Not Found" + end + + test "renders 500.html" do + assert render_to_string(HelloWorldWeb.ErrorView, "500.html", []) == "Internal Server Error" + end +end diff --git a/phoenix-1.6/hello_world/test/hello_world_web/views/layout_view_test.exs b/phoenix-1.6/hello_world/test/hello_world_web/views/layout_view_test.exs new file mode 100644 index 000000000..7ded59b49 --- /dev/null +++ b/phoenix-1.6/hello_world/test/hello_world_web/views/layout_view_test.exs @@ -0,0 +1,8 @@ +defmodule HelloWorldWeb.LayoutViewTest do + use HelloWorldWeb.ConnCase, async: true + + # When testing helpers, you may want to import Phoenix.HTML and + # use functions such as safe_to_string() to convert the helper + # result into an HTML string. + # import Phoenix.HTML +end diff --git a/phoenix-1.6/hello_world/test/hello_world_web/views/page_view_test.exs b/phoenix-1.6/hello_world/test/hello_world_web/views/page_view_test.exs new file mode 100644 index 000000000..2af2c100b --- /dev/null +++ b/phoenix-1.6/hello_world/test/hello_world_web/views/page_view_test.exs @@ -0,0 +1,3 @@ +defmodule HelloWorldWeb.PageViewTest do + use HelloWorldWeb.ConnCase, async: true +end diff --git a/phoenix-1.6/hello_world/test/support/conn_case.ex b/phoenix-1.6/hello_world/test/support/conn_case.ex new file mode 100644 index 000000000..7244281c1 --- /dev/null +++ b/phoenix-1.6/hello_world/test/support/conn_case.ex @@ -0,0 +1,37 @@ +defmodule HelloWorldWeb.ConnCase do + @moduledoc """ + This module defines the test case to be used by + tests that require setting up a connection. + + Such tests rely on `Phoenix.ConnTest` and also + import other functionality to make it easier + to build common data structures and query the data layer. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use HelloWorldWeb.ConnCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + # Import conveniences for testing with connections + import Plug.Conn + import Phoenix.ConnTest + import HelloWorldWeb.ConnCase + + alias HelloWorldWeb.Router.Helpers, as: Routes + + # The default endpoint for testing + @endpoint HelloWorldWeb.Endpoint + end + end + + setup _tags do + {:ok, conn: Phoenix.ConnTest.build_conn()} + end +end diff --git a/phoenix-1.6/hello_world/test/test_helper.exs b/phoenix-1.6/hello_world/test/test_helper.exs new file mode 100644 index 000000000..869559e70 --- /dev/null +++ b/phoenix-1.6/hello_world/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/phoenix-1.6/navigation/.formatter.exs b/phoenix-1.6/navigation/.formatter.exs new file mode 100644 index 000000000..47616780b --- /dev/null +++ b/phoenix-1.6/navigation/.formatter.exs @@ -0,0 +1,4 @@ +[ + import_deps: [:phoenix], + inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/phoenix-1.6/navigation/.gitignore b/phoenix-1.6/navigation/.gitignore new file mode 100644 index 000000000..7e90cfa49 --- /dev/null +++ b/phoenix-1.6/navigation/.gitignore @@ -0,0 +1,34 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +navigation-*.tar + +# Ignore assets that are produced by build tools. +/priv/static/assets/ + +# Ignore digested assets cache. +/priv/static/cache_manifest.json + +# In case you use Node.js/npm, you want to ignore these. +npm-debug.log +/assets/node_modules/ + diff --git a/phoenix-1.6/navigation/README.md b/phoenix-1.6/navigation/README.md new file mode 100644 index 000000000..bb774abbb --- /dev/null +++ b/phoenix-1.6/navigation/README.md @@ -0,0 +1,18 @@ +# Navigation + +To start your Phoenix server: + + * Install dependencies with `mix deps.get` + * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` + +Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. + +Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). + +## Learn more + + * Official website: https://www.phoenixframework.org/ + * Guides: https://hexdocs.pm/phoenix/overview.html + * Docs: https://hexdocs.pm/phoenix + * Forum: https://elixirforum.com/c/phoenix-forum + * Source: https://github.com/phoenixframework/phoenix diff --git a/phoenix-1.6/navigation/assets/css/app.css b/phoenix-1.6/navigation/assets/css/app.css new file mode 100644 index 000000000..19c2e51ed --- /dev/null +++ b/phoenix-1.6/navigation/assets/css/app.css @@ -0,0 +1,120 @@ +/* This file is for your main application CSS */ +@import "./phoenix.css"; + +/* Alerts and form errors used by phx.new */ +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert p { + margin-bottom: 0; +} +.alert:empty { + display: none; +} +.invalid-feedback { + color: #a94442; + display: block; + margin: -1rem 0 2rem; +} + +/* LiveView specific classes for your customization */ +.phx-no-feedback.invalid-feedback, +.phx-no-feedback .invalid-feedback { + display: none; +} + +.phx-click-loading { + opacity: 0.5; + transition: opacity 1s ease-out; +} + +.phx-loading{ + cursor: wait; +} + +.phx-modal { + opacity: 1!important; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.4); +} + +.phx-modal-content { + background-color: #fefefe; + margin: 15vh auto; + padding: 20px; + border: 1px solid #888; + width: 80%; +} + +.phx-modal-close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.phx-modal-close:hover, +.phx-modal-close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + +.fade-in-scale { + animation: 0.2s ease-in 0s normal forwards 1 fade-in-scale-keys; +} + +.fade-out-scale { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-scale-keys; +} + +.fade-in { + animation: 0.2s ease-out 0s normal forwards 1 fade-in-keys; +} +.fade-out { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-keys; +} + +@keyframes fade-in-scale-keys{ + 0% { scale: 0.95; opacity: 0; } + 100% { scale: 1.0; opacity: 1; } +} + +@keyframes fade-out-scale-keys{ + 0% { scale: 1.0; opacity: 1; } + 100% { scale: 0.95; opacity: 0; } +} + +@keyframes fade-in-keys{ + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@keyframes fade-out-keys{ + 0% { opacity: 1; } + 100% { opacity: 0; } +} diff --git a/phoenix-1.6/navigation/assets/css/phoenix.css b/phoenix-1.6/navigation/assets/css/phoenix.css new file mode 100644 index 000000000..0d59050f8 --- /dev/null +++ b/phoenix-1.6/navigation/assets/css/phoenix.css @@ -0,0 +1,101 @@ +/* Includes some default style for the starter application. + * This can be safely deleted to start fresh. + */ + +/* Milligram v1.4.1 https://milligram.github.io + * Copyright (c) 2020 CJ Patoilo Licensed under the MIT license + */ + +*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#000000;font-family:'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#0069d9;border:0.1rem solid #0069d9;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#0069d9;border-color:#0069d9}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#0069d9}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#0069d9}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#0069d9}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#0069d9}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #0069d9;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='color'],input[type='date'],input[type='datetime'],input[type='datetime-local'],input[type='email'],input[type='month'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='week'],input:not([type]),textarea,select{-webkit-appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem .7rem;width:100%}input[type='color']:focus,input[type='date']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input[type='email']:focus,input[type='month']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='week']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#0069d9;outline:0}select{background:url('data:image/svg+xml;utf8,') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:none;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#0069d9;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;display:block;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media (min-width: 40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} + +/* General style */ +h1{font-size: 3.6rem; line-height: 1.25} +h2{font-size: 2.8rem; line-height: 1.3} +h3{font-size: 2.2rem; letter-spacing: -.08rem; line-height: 1.35} +h4{font-size: 1.8rem; letter-spacing: -.05rem; line-height: 1.5} +h5{font-size: 1.6rem; letter-spacing: 0; line-height: 1.4} +h6{font-size: 1.4rem; letter-spacing: 0; line-height: 1.2} +pre{padding: 1em;} + +.container{ + margin: 0 auto; + max-width: 80.0rem; + padding: 0 2.0rem; + position: relative; + width: 100% +} +select { + width: auto; +} + +/* Phoenix promo and logo */ +.phx-hero { + text-align: center; + border-bottom: 1px solid #e3e3e3; + background: #eee; + border-radius: 6px; + padding: 3em 3em 1em; + margin-bottom: 3rem; + font-weight: 200; + font-size: 120%; +} +.phx-hero input { + background: #ffffff; +} +.phx-logo { + min-width: 300px; + margin: 1rem; + display: block; +} +.phx-logo img { + width: auto; + display: block; +} + +/* Headers */ +header { + width: 100%; + background: #fdfdfd; + border-bottom: 1px solid #eaeaea; + margin-bottom: 2rem; +} +header section { + align-items: center; + display: flex; + flex-direction: column; + justify-content: space-between; +} +header section :first-child { + order: 2; +} +header section :last-child { + order: 1; +} +header nav ul, +header nav li { + margin: 0; + padding: 0; + display: block; + text-align: right; + white-space: nowrap; +} +header nav ul { + margin: 1rem; + margin-top: 0; +} +header nav a { + display: block; +} + +@media (min-width: 40.0rem) { /* Small devices (landscape phones, 576px and up) */ + header section { + flex-direction: row; + } + header nav ul { + margin: 1rem; + } + .phx-logo { + flex-basis: 527px; + margin: 2rem 1rem; + } +} diff --git a/phoenix-1.6/navigation/assets/js/app.js b/phoenix-1.6/navigation/assets/js/app.js new file mode 100644 index 000000000..2ca06a566 --- /dev/null +++ b/phoenix-1.6/navigation/assets/js/app.js @@ -0,0 +1,45 @@ +// We import the CSS which is extracted to its own file by esbuild. +// Remove this line if you add a your own CSS build pipeline (e.g postcss). +import "../css/app.css" + +// If you want to use Phoenix channels, run `mix help phx.gen.channel` +// to get started and then uncomment the line below. +// import "./user_socket.js" + +// You can include dependencies in two ways. +// +// The simplest option is to put them in assets/vendor and +// import them using relative paths: +// +// import "../vendor/some-package.js" +// +// Alternatively, you can `npm install some-package --prefix assets` and import +// them using a path starting with the package name: +// +// import "some-package" +// + +// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. +import "phoenix_html" +// Establish Phoenix Socket and LiveView configuration. +import {Socket} from "phoenix" +import {LiveSocket} from "phoenix_live_view" +import topbar from "../vendor/topbar" + +let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") +let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) + +// Show progress bar on live navigation and form submits +topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) +window.addEventListener("phx:page-loading-start", info => topbar.show()) +window.addEventListener("phx:page-loading-stop", info => topbar.hide()) + +// connect if there are any LiveViews on the page +liveSocket.connect() + +// expose liveSocket on window for web console debug logs and latency simulation: +// >> liveSocket.enableDebug() +// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session +// >> liveSocket.disableLatencySim() +window.liveSocket = liveSocket + diff --git a/phoenix-1.6/navigation/assets/vendor/topbar.js b/phoenix-1.6/navigation/assets/vendor/topbar.js new file mode 100644 index 000000000..1f6220974 --- /dev/null +++ b/phoenix-1.6/navigation/assets/vendor/topbar.js @@ -0,0 +1,157 @@ +/** + * @license MIT + * topbar 1.0.0, 2021-01-06 + * https://buunguyen.github.io/topbar + * Copyright (c) 2021 Buu Nguyen + */ +(function (window, document) { + "use strict"; + + // https://gist.github.com/paulirish/1579671 + (function () { + var lastTime = 0; + var vendors = ["ms", "moz", "webkit", "o"]; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = + window[vendors[x] + "RequestAnimationFrame"]; + window.cancelAnimationFrame = + window[vendors[x] + "CancelAnimationFrame"] || + window[vendors[x] + "CancelRequestAnimationFrame"]; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + })(); + + var canvas, + progressTimerId, + fadeTimerId, + currentProgress, + showing, + addEvent = function (elem, type, handler) { + if (elem.addEventListener) elem.addEventListener(type, handler, false); + else if (elem.attachEvent) elem.attachEvent("on" + type, handler); + else elem["on" + type] = handler; + }, + options = { + autoRun: true, + barThickness: 3, + barColors: { + 0: "rgba(26, 188, 156, .9)", + ".25": "rgba(52, 152, 219, .9)", + ".50": "rgba(241, 196, 15, .9)", + ".75": "rgba(230, 126, 34, .9)", + "1.0": "rgba(211, 84, 0, .9)", + }, + shadowBlur: 10, + shadowColor: "rgba(0, 0, 0, .6)", + className: null, + }, + repaint = function () { + canvas.width = window.innerWidth; + canvas.height = options.barThickness * 5; // need space for shadow + + var ctx = canvas.getContext("2d"); + ctx.shadowBlur = options.shadowBlur; + ctx.shadowColor = options.shadowColor; + + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); + for (var stop in options.barColors) + lineGradient.addColorStop(stop, options.barColors[stop]); + ctx.lineWidth = options.barThickness; + ctx.beginPath(); + ctx.moveTo(0, options.barThickness / 2); + ctx.lineTo( + Math.ceil(currentProgress * canvas.width), + options.barThickness / 2 + ); + ctx.strokeStyle = lineGradient; + ctx.stroke(); + }, + createCanvas = function () { + canvas = document.createElement("canvas"); + var style = canvas.style; + style.position = "fixed"; + style.top = style.left = style.right = style.margin = style.padding = 0; + style.zIndex = 100001; + style.display = "none"; + if (options.className) canvas.classList.add(options.className); + document.body.appendChild(canvas); + addEvent(window, "resize", repaint); + }, + topbar = { + config: function (opts) { + for (var key in opts) + if (options.hasOwnProperty(key)) options[key] = opts[key]; + }, + show: function () { + if (showing) return; + showing = true; + if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); + if (!canvas) createCanvas(); + canvas.style.opacity = 1; + canvas.style.display = "block"; + topbar.progress(0); + if (options.autoRun) { + (function loop() { + progressTimerId = window.requestAnimationFrame(loop); + topbar.progress( + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) + ); + })(); + } + }, + progress: function (to) { + if (typeof to === "undefined") return currentProgress; + if (typeof to === "string") { + to = + (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 + ? currentProgress + : 0) + parseFloat(to); + } + currentProgress = to > 1 ? 1 : to; + repaint(); + return currentProgress; + }, + hide: function () { + if (!showing) return; + showing = false; + if (progressTimerId != null) { + window.cancelAnimationFrame(progressTimerId); + progressTimerId = null; + } + (function loop() { + if (topbar.progress("+.1") >= 1) { + canvas.style.opacity -= 0.05; + if (canvas.style.opacity <= 0.05) { + canvas.style.display = "none"; + fadeTimerId = null; + return; + } + } + fadeTimerId = window.requestAnimationFrame(loop); + })(); + }, + }; + + if (typeof module === "object" && typeof module.exports === "object") { + module.exports = topbar; + } else if (typeof define === "function" && define.amd) { + define(function () { + return topbar; + }); + } else { + this.topbar = topbar; + } +}.call(this, window, document)); diff --git a/phoenix-1.6/navigation/config/config.exs b/phoenix-1.6/navigation/config/config.exs new file mode 100644 index 000000000..a1fbfdef3 --- /dev/null +++ b/phoenix-1.6/navigation/config/config.exs @@ -0,0 +1,49 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Config module. +# +# This configuration file is loaded before any dependency and +# is restricted to this project. + +# General application configuration +import Config + +# Configures the endpoint +config :navigation, NavigationWeb.Endpoint, + url: [host: "localhost"], + render_errors: [view: NavigationWeb.ErrorView, accepts: ~w(html json), layout: false], + pubsub_server: Navigation.PubSub, + live_view: [signing_salt: "Z2PkgCoo"] + +# Configures the mailer +# +# By default it uses the "Local" adapter which stores the emails +# locally. You can see the emails in your browser, at "/dev/mailbox". +# +# For production it's recommended to configure a different adapter +# at the `config/runtime.exs`. +config :navigation, Navigation.Mailer, adapter: Swoosh.Adapters.Local + +# Swoosh API client is needed for adapters other than SMTP. +config :swoosh, :api_client, false + +# Configure esbuild (the version is required) +config :esbuild, + version: "0.14.29", + default: [ + args: + ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), + cd: Path.expand("../assets", __DIR__), + env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} + ] + +# Configures Elixir's Logger +config :logger, :console, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id] + +# Use Jason for JSON parsing in Phoenix +config :phoenix, :json_library, Jason + +# Import environment specific config. This must remain at the bottom +# of this file so it overrides the configuration defined above. +import_config "#{config_env()}.exs" diff --git a/phoenix-1.6/navigation/config/dev.exs b/phoenix-1.6/navigation/config/dev.exs new file mode 100644 index 000000000..b7e24d5a0 --- /dev/null +++ b/phoenix-1.6/navigation/config/dev.exs @@ -0,0 +1,65 @@ +import Config + +# For development, we disable any cache and enable +# debugging and code reloading. +# +# The watchers configuration can be used to run external +# watchers to your application. For example, we use it +# with esbuild to bundle .js and .css sources. +config :navigation, NavigationWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. + # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. + http: [ip: {127, 0, 0, 1}, port: 4000], + check_origin: false, + code_reloader: true, + debug_errors: true, + secret_key_base: "+4jQCsy5y/0czKzQhRf7uW+RBNXHgpDqe0z5RBTjT+tpKP/EfxeKlw4ckhXccxVt", + watchers: [ + # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args) + esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]} + ] + +# ## SSL Support +# +# In order to use HTTPS in development, a self-signed +# certificate can be generated by running the following +# Mix task: +# +# mix phx.gen.cert +# +# Note that this task requires Erlang/OTP 20 or later. +# Run `mix help phx.gen.cert` for more information. +# +# The `http:` config above can be replaced with: +# +# https: [ +# port: 4001, +# cipher_suite: :strong, +# keyfile: "priv/cert/selfsigned_key.pem", +# certfile: "priv/cert/selfsigned.pem" +# ], +# +# If desired, both `http:` and `https:` keys can be +# configured to run both http and https servers on +# different ports. + +# Watch static and templates for browser reloading. +config :navigation, NavigationWeb.Endpoint, + live_reload: [ + patterns: [ + ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", + ~r"priv/gettext/.*(po)$", + ~r"lib/navigation_web/(live|views)/.*(ex)$", + ~r"lib/navigation_web/templates/.*(eex)$" + ] + ] + +# Do not include metadata nor timestamps in development logs +config :logger, :console, format: "[$level] $message\n" + +# Set a higher stacktrace during development. Avoid configuring such +# in production as building large stacktraces may be expensive. +config :phoenix, :stacktrace_depth, 20 + +# Initialize plugs at runtime for faster development compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/navigation/config/prod.exs b/phoenix-1.6/navigation/config/prod.exs new file mode 100644 index 000000000..ffbc34948 --- /dev/null +++ b/phoenix-1.6/navigation/config/prod.exs @@ -0,0 +1,49 @@ +import Config + +# For production, don't forget to configure the url host +# to something meaningful, Phoenix uses this information +# when generating URLs. +# +# Note we also include the path to a cache manifest +# containing the digested version of static files. This +# manifest is generated by the `mix phx.digest` task, +# which you should run after static files are built and +# before starting your production server. +config :navigation, NavigationWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" + +# Do not print debug messages in production +config :logger, level: :info + +# ## SSL Support +# +# To get SSL working, you will need to add the `https` key +# to the previous section and set your `:url` port to 443: +# +# config :navigation, NavigationWeb.Endpoint, +# ..., +# url: [host: "example.com", port: 443], +# https: [ +# ..., +# port: 443, +# cipher_suite: :strong, +# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), +# certfile: System.get_env("SOME_APP_SSL_CERT_PATH") +# ] +# +# The `cipher_suite` is set to `:strong` to support only the +# latest and more secure SSL ciphers. This means old browsers +# and clients may not be supported. You can set it to +# `:compatible` for wider support. +# +# `:keyfile` and `:certfile` expect an absolute path to the key +# and cert in disk or a relative path inside priv, for example +# "priv/ssl/server.key". For all supported SSL configuration +# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 +# +# We also recommend setting `force_ssl` in your endpoint, ensuring +# no data is ever sent via http, always redirecting to https: +# +# config :navigation, NavigationWeb.Endpoint, +# force_ssl: [hsts: true] +# +# Check `Plug.SSL` for all available options in `force_ssl`. diff --git a/phoenix-1.6/navigation/config/runtime.exs b/phoenix-1.6/navigation/config/runtime.exs new file mode 100644 index 000000000..80cbb1ac4 --- /dev/null +++ b/phoenix-1.6/navigation/config/runtime.exs @@ -0,0 +1,68 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/navigation start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :navigation, NavigationWeb.Endpoint, server: true +end + +if config_env() == :prod do + # The secret key base is used to sign/encrypt cookies and other secrets. + # A default value is used in config/dev.exs and config/test.exs but you + # want to use a different value for prod and you most likely don't want + # to check this value into version control, so we use an environment + # variable instead. + secret_key_base = + System.get_env("SECRET_KEY_BASE") || + raise """ + environment variable SECRET_KEY_BASE is missing. + You can generate one by calling: mix phx.gen.secret + """ + + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + + config :navigation, NavigationWeb.Endpoint, + url: [host: host, port: 443, scheme: "https"], + http: [ + # Enable IPv6 and bind on all interfaces. + # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. + # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html + # for details about using IPv6 vs IPv4 and loopback vs public addresses. + ip: {0, 0, 0, 0, 0, 0, 0, 0}, + port: port + ], + secret_key_base: secret_key_base + + # ## Configuring the mailer + # + # In production you need to configure the mailer to use a different adapter. + # Also, you may need to configure the Swoosh API client of your choice if you + # are not using SMTP. Here is an example of the configuration: + # + # config :navigation, Navigation.Mailer, + # adapter: Swoosh.Adapters.Mailgun, + # api_key: System.get_env("MAILGUN_API_KEY"), + # domain: System.get_env("MAILGUN_DOMAIN") + # + # For this example you need include a HTTP client required by Swoosh API client. + # Swoosh supports Hackney and Finch out of the box: + # + # config :swoosh, :api_client, Swoosh.ApiClient.Hackney + # + # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. +end diff --git a/phoenix-1.6/navigation/config/test.exs b/phoenix-1.6/navigation/config/test.exs new file mode 100644 index 000000000..36ed75023 --- /dev/null +++ b/phoenix-1.6/navigation/config/test.exs @@ -0,0 +1,18 @@ +import Config + +# We don't run a server during test. If one is required, +# you can enable the server option below. +config :navigation, NavigationWeb.Endpoint, + http: [ip: {127, 0, 0, 1}, port: 4002], + secret_key_base: "Cz8ERwLtloX4VXl5agl0hv3JFCG3HOiodGhg9MarTf6IPXOuGT42tC+S2hltZojZ", + server: false + +# In test we don't send emails. +config :navigation, Navigation.Mailer, + adapter: Swoosh.Adapters.Test + +# Print only warnings and errors during test +config :logger, level: :warn + +# Initialize plugs at runtime for faster test compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/navigation/lib/navigation.ex b/phoenix-1.6/navigation/lib/navigation.ex new file mode 100644 index 000000000..e2a385585 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation.ex @@ -0,0 +1,9 @@ +defmodule Navigation do + @moduledoc """ + Navigation keeps the contexts that define your domain + and business logic. + + Contexts are also responsible for managing your data, regardless + if it comes from the database, an external API or others. + """ +end diff --git a/phoenix-1.6/navigation/lib/navigation/application.ex b/phoenix-1.6/navigation/lib/navigation/application.ex new file mode 100644 index 000000000..6f9c51bc5 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation/application.ex @@ -0,0 +1,34 @@ +defmodule Navigation.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + children = [ + # Start the Telemetry supervisor + NavigationWeb.Telemetry, + # Start the PubSub system + {Phoenix.PubSub, name: Navigation.PubSub}, + # Start the Endpoint (http/https) + NavigationWeb.Endpoint + # Start a worker by calling: Navigation.Worker.start_link(arg) + # {Navigation.Worker, arg} + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: Navigation.Supervisor] + Supervisor.start_link(children, opts) + end + + # Tell Phoenix to update the endpoint configuration + # whenever the application is updated. + @impl true + def config_change(changed, _new, removed) do + NavigationWeb.Endpoint.config_change(changed, removed) + :ok + end +end diff --git a/phoenix-1.6/navigation/lib/navigation/mailer.ex b/phoenix-1.6/navigation/lib/navigation/mailer.ex new file mode 100644 index 000000000..2ae9e757e --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation/mailer.ex @@ -0,0 +1,3 @@ +defmodule Navigation.Mailer do + use Swoosh.Mailer, otp_app: :navigation +end diff --git a/phoenix-1.6/navigation/lib/navigation_web.ex b/phoenix-1.6/navigation/lib/navigation_web.ex new file mode 100644 index 000000000..8b0a3a9ee --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web.ex @@ -0,0 +1,110 @@ +defmodule NavigationWeb do + @moduledoc """ + The entrypoint for defining your web interface, such + as controllers, views, channels and so on. + + This can be used in your application as: + + use NavigationWeb, :controller + use NavigationWeb, :view + + The definitions below will be executed for every view, + controller, etc, so keep them short and clean, focused + on imports, uses and aliases. + + Do NOT define functions inside the quoted expressions + below. Instead, define any helper function in modules + and import those modules here. + """ + + def controller do + quote do + use Phoenix.Controller, namespace: NavigationWeb + + import Plug.Conn + import NavigationWeb.Gettext + alias NavigationWeb.Router.Helpers, as: Routes + end + end + + def view do + quote do + use Phoenix.View, + root: "lib/navigation_web/templates", + namespace: NavigationWeb + + # Import convenience functions from controllers + import Phoenix.Controller, + only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1] + + # Include shared imports and aliases for views + unquote(view_helpers()) + end + end + + def live_view do + quote do + use Phoenix.LiveView, + layout: {NavigationWeb.LayoutView, "live.html"} + + unquote(view_helpers()) + end + end + + def live_component do + quote do + use Phoenix.LiveComponent + + unquote(view_helpers()) + end + end + + def component do + quote do + use Phoenix.Component + + unquote(view_helpers()) + end + end + + def router do + quote do + use Phoenix.Router + + import Plug.Conn + import Phoenix.Controller + import Phoenix.LiveView.Router + end + end + + def channel do + quote do + use Phoenix.Channel + import NavigationWeb.Gettext + end + end + + defp view_helpers do + quote do + # Use all HTML functionality (forms, tags, etc) + use Phoenix.HTML + + # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc) + import Phoenix.LiveView.Helpers + + # Import basic rendering functionality (render, render_layout, etc) + import Phoenix.View + + import NavigationWeb.ErrorHelpers + import NavigationWeb.Gettext + alias NavigationWeb.Router.Helpers, as: Routes + end + end + + @doc """ + When used, dispatch to the appropriate controller/view/etc. + """ + defmacro __using__(which) when is_atom(which) do + apply(__MODULE__, which, []) + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/controllers/about_controller.ex b/phoenix-1.6/navigation/lib/navigation_web/controllers/about_controller.ex new file mode 100644 index 000000000..ed96b247d --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/controllers/about_controller.ex @@ -0,0 +1,7 @@ +defmodule NavigationWeb.AboutController do + use NavigationWeb, :controller + + def about(conn, _params) do + render(conn, "about.html") + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/controllers/home_controller.ex b/phoenix-1.6/navigation/lib/navigation_web/controllers/home_controller.ex new file mode 100644 index 000000000..be52a558d --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/controllers/home_controller.ex @@ -0,0 +1,7 @@ +defmodule NavigationWeb.HomeController do + use NavigationWeb, :controller + + def home(conn, _params) do + render(conn, "home.html") + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/controllers/page_controller.ex b/phoenix-1.6/navigation/lib/navigation_web/controllers/page_controller.ex new file mode 100644 index 000000000..362a45f16 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/controllers/page_controller.ex @@ -0,0 +1,7 @@ +defmodule NavigationWeb.PageController do + use NavigationWeb, :controller + + def index(conn, _params) do + render(conn, "index.html") + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/controllers/projects_controller.ex b/phoenix-1.6/navigation/lib/navigation_web/controllers/projects_controller.ex new file mode 100644 index 000000000..c7c3d2d3d --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/controllers/projects_controller.ex @@ -0,0 +1,7 @@ +defmodule NavigationWeb.ProjectsController do + use NavigationWeb, :controller + + def projects(conn, _params) do + render(conn, "projects.html") + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/endpoint.ex b/phoenix-1.6/navigation/lib/navigation_web/endpoint.ex new file mode 100644 index 000000000..e2416c0b5 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/endpoint.ex @@ -0,0 +1,49 @@ +defmodule NavigationWeb.Endpoint do + use Phoenix.Endpoint, otp_app: :navigation + + # The session will be stored in the cookie and signed, + # this means its contents can be read but not tampered with. + # Set :encryption_salt if you would also like to encrypt it. + @session_options [ + store: :cookie, + key: "_navigation_key", + signing_salt: "0XYo/f0H" + ] + + socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] + + # Serve at "/" the static files from "priv/static" directory. + # + # You should set gzip to true if you are running phx.digest + # when deploying your static files in production. + plug Plug.Static, + at: "/", + from: :navigation, + gzip: false, + only: ~w(assets fonts images favicon.ico robots.txt) + + # Code reloading can be explicitly enabled under the + # :code_reloader configuration of your endpoint. + if code_reloading? do + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + plug Phoenix.LiveReloader + plug Phoenix.CodeReloader + end + + plug Phoenix.LiveDashboard.RequestLogger, + param_key: "request_logger", + cookie_key: "request_logger" + + plug Plug.RequestId + plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] + + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Phoenix.json_library() + + plug Plug.MethodOverride + plug Plug.Head + plug Plug.Session, @session_options + plug NavigationWeb.Router +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/gettext.ex b/phoenix-1.6/navigation/lib/navigation_web/gettext.ex new file mode 100644 index 000000000..7cca2250f --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/gettext.ex @@ -0,0 +1,24 @@ +defmodule NavigationWeb.Gettext do + @moduledoc """ + A module providing Internationalization with a gettext-based API. + + By using [Gettext](https://hexdocs.pm/gettext), + your module gains a set of macros for translations, for example: + + import NavigationWeb.Gettext + + # Simple translation + gettext("Here is the string to translate") + + # Plural translation + ngettext("Here is the string to translate", + "Here are the strings to translate", + 3) + + # Domain-based translation + dgettext("errors", "Here is the error message to translate") + + See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. + """ + use Gettext, otp_app: :navigation +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/router.ex b/phoenix-1.6/navigation/lib/navigation_web/router.ex new file mode 100644 index 000000000..221453535 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/router.ex @@ -0,0 +1,59 @@ +defmodule NavigationWeb.Router do + use NavigationWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_live_flash + plug :put_root_layout, {NavigationWeb.LayoutView, :root} + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + scope "/", NavigationWeb do + pipe_through :browser + + get "/", PageController, :index + get "/home", HomeController, :home + get "/about", AboutController, :about + get "/projects", ProjectsController, :projects + end + + # Other scopes may use custom stacks. + # scope "/api", NavigationWeb do + # pipe_through :api + # end + + # Enables LiveDashboard only for development + # + # If you want to use the LiveDashboard in production, you should put + # it behind authentication and allow only admins to access it. + # If your application does not have an admins-only section yet, + # you can use Plug.BasicAuth to set up some basic authentication + # as long as you are also using SSL (which you should anyway). + if Mix.env() in [:dev, :test] do + import Phoenix.LiveDashboard.Router + + scope "/" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: NavigationWeb.Telemetry + end + end + + # Enables the Swoosh mailbox preview in development. + # + # Note that preview only shows emails that were sent by the same + # node running the Phoenix server. + if Mix.env() == :dev do + scope "/dev" do + pipe_through :browser + + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/telemetry.ex b/phoenix-1.6/navigation/lib/navigation_web/telemetry.ex new file mode 100644 index 000000000..be9fe9bc7 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/telemetry.ex @@ -0,0 +1,48 @@ +defmodule NavigationWeb.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp periodic_measurements do + [ + # A module, function and arguments to be invoked periodically. + # This function must call :telemetry.execute/3 and a metric must be added above. + # {NavigationWeb, :count_users, []} + ] + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/about/about.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/about/about.html.heex new file mode 100644 index 000000000..8eb36c1f5 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/about/about.html.heex @@ -0,0 +1 @@ +

About Page

diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/home/home.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/home/home.html.heex new file mode 100644 index 000000000..d62a4c404 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/home/home.html.heex @@ -0,0 +1 @@ +

Home Page

diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/layout/app.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/layout/app.html.heex new file mode 100644 index 000000000..169aed956 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/layout/app.html.heex @@ -0,0 +1,5 @@ +
+ + + <%= @inner_content %> +
diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/layout/live.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/layout/live.html.heex new file mode 100644 index 000000000..a29d60448 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/layout/live.html.heex @@ -0,0 +1,11 @@ +
+ + + + + <%= @inner_content %> +
diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/layout/root.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/layout/root.html.heex new file mode 100644 index 000000000..c72fc27e4 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/layout/root.html.heex @@ -0,0 +1,39 @@ + + + + + + + + <%= live_title_tag assigns[:page_title] || "Navigation", suffix: " · Phoenix Framework" %> + + + + + +
+
+ + +
+
+ <%= @inner_content %> +
    +
  • <%= link "Home", to: "/home" %>

  • +
  • <%= link "About", to: "/about" %>

  • +
  • <%= link "Projects", to: "/projects" %>

  • +
+ + diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/page/home/home.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/page/home/home.html.heex new file mode 100644 index 000000000..d62a4c404 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/page/home/home.html.heex @@ -0,0 +1 @@ +

Home Page

diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/page/index.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/page/index.html.heex new file mode 100644 index 000000000..f844bd8d7 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/page/index.html.heex @@ -0,0 +1,41 @@ +
+

<%= gettext "Welcome to %{name}!", name: "Phoenix" %>

+

Peace of mind from prototype to production

+
+ +
+ + +
diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/page/projects/projects.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/page/projects/projects.html.heex new file mode 100644 index 000000000..f1b92b1cc --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/page/projects/projects.html.heex @@ -0,0 +1 @@ +

Projects Page

diff --git a/phoenix-1.6/navigation/lib/navigation_web/templates/projects/projects.html.heex b/phoenix-1.6/navigation/lib/navigation_web/templates/projects/projects.html.heex new file mode 100644 index 000000000..f1b92b1cc --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/templates/projects/projects.html.heex @@ -0,0 +1 @@ +

Projects Page

diff --git a/phoenix-1.6/navigation/lib/navigation_web/views/about_view.ex b/phoenix-1.6/navigation/lib/navigation_web/views/about_view.ex new file mode 100644 index 000000000..7c120b2e3 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/views/about_view.ex @@ -0,0 +1,3 @@ +defmodule NavigationWeb.AboutView do + use NavigationWeb, :view +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/views/error_helpers.ex b/phoenix-1.6/navigation/lib/navigation_web/views/error_helpers.ex new file mode 100644 index 000000000..c772d7604 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/views/error_helpers.ex @@ -0,0 +1,47 @@ +defmodule NavigationWeb.ErrorHelpers do + @moduledoc """ + Conveniences for translating and building error messages. + """ + + use Phoenix.HTML + + @doc """ + Generates tag for inlined form input errors. + """ + def error_tag(form, field) do + Enum.map(Keyword.get_values(form.errors, field), fn error -> + content_tag(:span, translate_error(error), + class: "invalid-feedback", + phx_feedback_for: input_name(form, field) + ) + end) + end + + @doc """ + Translates an error message using gettext. + """ + def translate_error({msg, opts}) do + # When using gettext, we typically pass the strings we want + # to translate as a static argument: + # + # # Translate "is invalid" in the "errors" domain + # dgettext("errors", "is invalid") + # + # # Translate the number of files with plural rules + # dngettext("errors", "1 file", "%{count} files", count) + # + # Because the error messages we show in our forms and APIs + # are defined inside Ecto, we need to translate them dynamically. + # This requires us to call the Gettext module passing our gettext + # backend as first argument. + # + # Note we use the "errors" domain, which means translations + # should be written to the errors.po file. The :count option is + # set by Ecto and indicates we should also apply plural rules. + if count = opts[:count] do + Gettext.dngettext(NavigationWeb.Gettext, "errors", msg, msg, count, opts) + else + Gettext.dgettext(NavigationWeb.Gettext, "errors", msg, opts) + end + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/views/error_view.ex b/phoenix-1.6/navigation/lib/navigation_web/views/error_view.ex new file mode 100644 index 000000000..ec221081a --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/views/error_view.ex @@ -0,0 +1,16 @@ +defmodule NavigationWeb.ErrorView do + use NavigationWeb, :view + + # If you want to customize a particular status code + # for a certain format, you may uncomment below. + # def render("500.html", _assigns) do + # "Internal Server Error" + # end + + # By default, Phoenix returns the status message from + # the template name. For example, "404.html" becomes + # "Not Found". + def template_not_found(template, _assigns) do + Phoenix.Controller.status_message_from_template(template) + end +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/views/home_view.ex b/phoenix-1.6/navigation/lib/navigation_web/views/home_view.ex new file mode 100644 index 000000000..af1f1f9d8 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/views/home_view.ex @@ -0,0 +1,3 @@ +defmodule NavigationWeb.HomeView do + use NavigationWeb, :view +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/views/layout_view.ex b/phoenix-1.6/navigation/lib/navigation_web/views/layout_view.ex new file mode 100644 index 000000000..397365e1f --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/views/layout_view.ex @@ -0,0 +1,7 @@ +defmodule NavigationWeb.LayoutView do + use NavigationWeb, :view + + # Phoenix LiveDashboard is available only in development by default, + # so we instruct Elixir to not warn if the dashboard route is missing. + @compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}} +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/views/page_view.ex b/phoenix-1.6/navigation/lib/navigation_web/views/page_view.ex new file mode 100644 index 000000000..e45509231 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/views/page_view.ex @@ -0,0 +1,3 @@ +defmodule NavigationWeb.PageView do + use NavigationWeb, :view +end diff --git a/phoenix-1.6/navigation/lib/navigation_web/views/projects_view.ex b/phoenix-1.6/navigation/lib/navigation_web/views/projects_view.ex new file mode 100644 index 000000000..0b14919b4 --- /dev/null +++ b/phoenix-1.6/navigation/lib/navigation_web/views/projects_view.ex @@ -0,0 +1,3 @@ +defmodule NavigationWeb.ProjectsView do + use NavigationWeb, :view +end diff --git a/phoenix-1.6/navigation/mix.exs b/phoenix-1.6/navigation/mix.exs new file mode 100644 index 000000000..57206205e --- /dev/null +++ b/phoenix-1.6/navigation/mix.exs @@ -0,0 +1,64 @@ +defmodule Navigation.MixProject do + use Mix.Project + + def project do + [ + app: :navigation, + version: "0.1.0", + elixir: "~> 1.12", + elixirc_paths: elixirc_paths(Mix.env()), + compilers: [:gettext] ++ Mix.compilers(), + start_permanent: Mix.env() == :prod, + aliases: aliases(), + deps: deps() + ] + end + + # Configuration for the OTP application. + # + # Type `mix help compile.app` for more information. + def application do + [ + mod: {Navigation.Application, []}, + extra_applications: [:logger, :runtime_tools] + ] + end + + # Specifies which paths to compile per environment. + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] + + # Specifies your project dependencies. + # + # Type `mix help deps` for examples and options. + defp deps do + [ + {:phoenix, "~> 1.6.15"}, + {:phoenix_html, "~> 3.0"}, + {:phoenix_live_reload, "~> 1.2", only: :dev}, + {:phoenix_live_view, "~> 0.17.5"}, + {:floki, ">= 0.30.0", only: :test}, + {:phoenix_live_dashboard, "~> 0.6"}, + {:esbuild, "~> 0.4", runtime: Mix.env() == :dev}, + {:swoosh, "~> 1.3"}, + {:telemetry_metrics, "~> 0.6"}, + {:telemetry_poller, "~> 1.0"}, + {:gettext, "~> 0.18"}, + {:jason, "~> 1.2"}, + {:plug_cowboy, "~> 2.5"} + ] + end + + # Aliases are shortcuts or tasks specific to the current project. + # For example, to install project dependencies and perform other setup tasks, run: + # + # $ mix setup + # + # See the documentation for `Mix` for more info on aliases. + defp aliases do + [ + setup: ["deps.get"], + "assets.deploy": ["esbuild default --minify", "phx.digest"] + ] + end +end diff --git a/phoenix-1.6/navigation/mix.lock b/phoenix-1.6/navigation/mix.lock new file mode 100644 index 000000000..47b126398 --- /dev/null +++ b/phoenix-1.6/navigation/mix.lock @@ -0,0 +1,29 @@ +%{ + "castore": {:hex, :castore, "1.0.1", "240b9edb4e9e94f8f56ab39d8d2d0a57f49e46c56aced8f873892df8ff64ff5a", [:mix], [], "hexpm", "b4951de93c224d44fac71614beabd88b71932d0b1dea80d2f80fb9044e01bbb3"}, + "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, + "esbuild": {:hex, :esbuild, "0.6.1", "a774bfa7b4512a1211bf15880b462be12a4c48ed753a170c68c63b2c95888150", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "569f7409fb5a932211573fc20e2a930a0d5cf3377c5b4f6506c651b1783a1678"}, + "expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"}, + "gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"}, + "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, + "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, + "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"}, + "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.14", "5ec615d4d61bf9d4755f158bd6c80372b715533fe6d6219e12d74fb5eedbeac1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "afeb6ba43ce329a6f7fc1c9acdfc6d3039995345f025febb7f409a92f6faebd3"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"}, + "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"}, + "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, + "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, +} diff --git a/phoenix-1.6/navigation/priv/gettext/en/LC_MESSAGES/errors.po b/phoenix-1.6/navigation/priv/gettext/en/LC_MESSAGES/errors.po new file mode 100644 index 000000000..cdec3a113 --- /dev/null +++ b/phoenix-1.6/navigation/priv/gettext/en/LC_MESSAGES/errors.po @@ -0,0 +1,11 @@ +## `msgid`s in this file come from POT (.pot) files. +## +## Do not add, change, or remove `msgid`s manually here as +## they're tied to the ones in the corresponding POT file +## (with the same domain). +## +## Use `mix gettext.extract --merge` or `mix gettext.merge` +## to merge POT files into PO files. +msgid "" +msgstr "" +"Language: en\n" diff --git a/phoenix-1.6/navigation/priv/gettext/errors.pot b/phoenix-1.6/navigation/priv/gettext/errors.pot new file mode 100644 index 000000000..d6f47fa87 --- /dev/null +++ b/phoenix-1.6/navigation/priv/gettext/errors.pot @@ -0,0 +1,10 @@ +## This is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here has no +## effect: edit them in PO (`.po`) files instead. + diff --git a/phoenix-1.6/navigation/priv/static/favicon.ico b/phoenix-1.6/navigation/priv/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..73de524aaadcf60fbe9d32881db0aa86b58b5cb9 GIT binary patch literal 1258 zcmbtUO>fgM7{=qN=;Mz_82;lvPEdVaxv-<-&=sZLwab?3I zBP>U*&(Hv<5n@9ZQ$vhg#|u$Zmtq8BV;+W*7(?jOx-{r?#TE&$Sdq77MbdJjD5`-q zMm_z(jLv3t>5NhzK{%aG(Yudfpjd3AFdKe2U7&zdepTe>^s(@!&0X8TJ`h+-I?84Ml# literal 0 HcmV?d00001 diff --git a/phoenix-1.6/navigation/priv/static/images/phoenix.png b/phoenix-1.6/navigation/priv/static/images/phoenix.png new file mode 100644 index 0000000000000000000000000000000000000000..9c81075f63d2151e6f40e9aa66f665749a87cc6a GIT binary patch literal 13900 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 UWxWXg`G1#+f~I_}taaG`2PLnS&Hw-a literal 0 HcmV?d00001 diff --git a/phoenix-1.6/navigation/priv/static/robots.txt b/phoenix-1.6/navigation/priv/static/robots.txt new file mode 100644 index 000000000..26e06b5f1 --- /dev/null +++ b/phoenix-1.6/navigation/priv/static/robots.txt @@ -0,0 +1,5 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / diff --git a/phoenix-1.6/navigation/test/navigation_web/controllers/page_controller_test.exs b/phoenix-1.6/navigation/test/navigation_web/controllers/page_controller_test.exs new file mode 100644 index 000000000..d1888d881 --- /dev/null +++ b/phoenix-1.6/navigation/test/navigation_web/controllers/page_controller_test.exs @@ -0,0 +1,8 @@ +defmodule NavigationWeb.PageControllerTest do + use NavigationWeb.ConnCase + + test "GET /", %{conn: conn} do + conn = get(conn, "/") + assert html_response(conn, 200) =~ "Welcome to Phoenix!" + end +end diff --git a/phoenix-1.6/navigation/test/navigation_web/views/error_view_test.exs b/phoenix-1.6/navigation/test/navigation_web/views/error_view_test.exs new file mode 100644 index 000000000..948c35664 --- /dev/null +++ b/phoenix-1.6/navigation/test/navigation_web/views/error_view_test.exs @@ -0,0 +1,14 @@ +defmodule NavigationWeb.ErrorViewTest do + use NavigationWeb.ConnCase, async: true + + # Bring render/3 and render_to_string/3 for testing custom views + import Phoenix.View + + test "renders 404.html" do + assert render_to_string(NavigationWeb.ErrorView, "404.html", []) == "Not Found" + end + + test "renders 500.html" do + assert render_to_string(NavigationWeb.ErrorView, "500.html", []) == "Internal Server Error" + end +end diff --git a/phoenix-1.6/navigation/test/navigation_web/views/layout_view_test.exs b/phoenix-1.6/navigation/test/navigation_web/views/layout_view_test.exs new file mode 100644 index 000000000..38e608b66 --- /dev/null +++ b/phoenix-1.6/navigation/test/navigation_web/views/layout_view_test.exs @@ -0,0 +1,8 @@ +defmodule NavigationWeb.LayoutViewTest do + use NavigationWeb.ConnCase, async: true + + # When testing helpers, you may want to import Phoenix.HTML and + # use functions such as safe_to_string() to convert the helper + # result into an HTML string. + # import Phoenix.HTML +end diff --git a/phoenix-1.6/navigation/test/navigation_web/views/page_view_test.exs b/phoenix-1.6/navigation/test/navigation_web/views/page_view_test.exs new file mode 100644 index 000000000..84c20f015 --- /dev/null +++ b/phoenix-1.6/navigation/test/navigation_web/views/page_view_test.exs @@ -0,0 +1,3 @@ +defmodule NavigationWeb.PageViewTest do + use NavigationWeb.ConnCase, async: true +end diff --git a/phoenix-1.6/navigation/test/support/conn_case.ex b/phoenix-1.6/navigation/test/support/conn_case.ex new file mode 100644 index 000000000..65f78fede --- /dev/null +++ b/phoenix-1.6/navigation/test/support/conn_case.ex @@ -0,0 +1,37 @@ +defmodule NavigationWeb.ConnCase do + @moduledoc """ + This module defines the test case to be used by + tests that require setting up a connection. + + Such tests rely on `Phoenix.ConnTest` and also + import other functionality to make it easier + to build common data structures and query the data layer. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use NavigationWeb.ConnCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + # Import conveniences for testing with connections + import Plug.Conn + import Phoenix.ConnTest + import NavigationWeb.ConnCase + + alias NavigationWeb.Router.Helpers, as: Routes + + # The default endpoint for testing + @endpoint NavigationWeb.Endpoint + end + end + + setup _tags do + {:ok, conn: Phoenix.ConnTest.build_conn()} + end +end diff --git a/phoenix-1.6/navigation/test/test_helper.exs b/phoenix-1.6/navigation/test/test_helper.exs new file mode 100644 index 000000000..869559e70 --- /dev/null +++ b/phoenix-1.6/navigation/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/phoenix-1.6/random_number/.formatter.exs b/phoenix-1.6/random_number/.formatter.exs new file mode 100644 index 000000000..47616780b --- /dev/null +++ b/phoenix-1.6/random_number/.formatter.exs @@ -0,0 +1,4 @@ +[ + import_deps: [:phoenix], + inputs: ["*.{ex,exs}", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/phoenix-1.6/random_number/.gitignore b/phoenix-1.6/random_number/.gitignore new file mode 100644 index 000000000..808a2cbbe --- /dev/null +++ b/phoenix-1.6/random_number/.gitignore @@ -0,0 +1,34 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +random_number-*.tar + +# Ignore assets that are produced by build tools. +/priv/static/assets/ + +# Ignore digested assets cache. +/priv/static/cache_manifest.json + +# In case you use Node.js/npm, you want to ignore these. +npm-debug.log +/assets/node_modules/ + diff --git a/phoenix-1.6/random_number/README.md b/phoenix-1.6/random_number/README.md new file mode 100644 index 000000000..9c5c6e3f5 --- /dev/null +++ b/phoenix-1.6/random_number/README.md @@ -0,0 +1,18 @@ +# RandomNumber + +To start your Phoenix server: + + * Install dependencies with `mix deps.get` + * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` + +Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. + +Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). + +## Learn more + + * Official website: https://www.phoenixframework.org/ + * Guides: https://hexdocs.pm/phoenix/overview.html + * Docs: https://hexdocs.pm/phoenix + * Forum: https://elixirforum.com/c/phoenix-forum + * Source: https://github.com/phoenixframework/phoenix diff --git a/phoenix-1.6/random_number/assets/css/app.css b/phoenix-1.6/random_number/assets/css/app.css new file mode 100644 index 000000000..19c2e51ed --- /dev/null +++ b/phoenix-1.6/random_number/assets/css/app.css @@ -0,0 +1,120 @@ +/* This file is for your main application CSS */ +@import "./phoenix.css"; + +/* Alerts and form errors used by phx.new */ +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert p { + margin-bottom: 0; +} +.alert:empty { + display: none; +} +.invalid-feedback { + color: #a94442; + display: block; + margin: -1rem 0 2rem; +} + +/* LiveView specific classes for your customization */ +.phx-no-feedback.invalid-feedback, +.phx-no-feedback .invalid-feedback { + display: none; +} + +.phx-click-loading { + opacity: 0.5; + transition: opacity 1s ease-out; +} + +.phx-loading{ + cursor: wait; +} + +.phx-modal { + opacity: 1!important; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.4); +} + +.phx-modal-content { + background-color: #fefefe; + margin: 15vh auto; + padding: 20px; + border: 1px solid #888; + width: 80%; +} + +.phx-modal-close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.phx-modal-close:hover, +.phx-modal-close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + +.fade-in-scale { + animation: 0.2s ease-in 0s normal forwards 1 fade-in-scale-keys; +} + +.fade-out-scale { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-scale-keys; +} + +.fade-in { + animation: 0.2s ease-out 0s normal forwards 1 fade-in-keys; +} +.fade-out { + animation: 0.2s ease-out 0s normal forwards 1 fade-out-keys; +} + +@keyframes fade-in-scale-keys{ + 0% { scale: 0.95; opacity: 0; } + 100% { scale: 1.0; opacity: 1; } +} + +@keyframes fade-out-scale-keys{ + 0% { scale: 1.0; opacity: 1; } + 100% { scale: 0.95; opacity: 0; } +} + +@keyframes fade-in-keys{ + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@keyframes fade-out-keys{ + 0% { opacity: 1; } + 100% { opacity: 0; } +} diff --git a/phoenix-1.6/random_number/assets/css/phoenix.css b/phoenix-1.6/random_number/assets/css/phoenix.css new file mode 100644 index 000000000..0d59050f8 --- /dev/null +++ b/phoenix-1.6/random_number/assets/css/phoenix.css @@ -0,0 +1,101 @@ +/* Includes some default style for the starter application. + * This can be safely deleted to start fresh. + */ + +/* Milligram v1.4.1 https://milligram.github.io + * Copyright (c) 2020 CJ Patoilo Licensed under the MIT license + */ + +*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#000000;font-family:'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#0069d9;border:0.1rem solid #0069d9;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#0069d9;border-color:#0069d9}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#0069d9}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#0069d9}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#0069d9}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#0069d9}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #0069d9;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='color'],input[type='date'],input[type='datetime'],input[type='datetime-local'],input[type='email'],input[type='month'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='week'],input:not([type]),textarea,select{-webkit-appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem .7rem;width:100%}input[type='color']:focus,input[type='date']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input[type='email']:focus,input[type='month']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='week']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#0069d9;outline:0}select{background:url('data:image/svg+xml;utf8,') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:none;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#0069d9;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;display:block;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media (min-width: 40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} + +/* General style */ +h1{font-size: 3.6rem; line-height: 1.25} +h2{font-size: 2.8rem; line-height: 1.3} +h3{font-size: 2.2rem; letter-spacing: -.08rem; line-height: 1.35} +h4{font-size: 1.8rem; letter-spacing: -.05rem; line-height: 1.5} +h5{font-size: 1.6rem; letter-spacing: 0; line-height: 1.4} +h6{font-size: 1.4rem; letter-spacing: 0; line-height: 1.2} +pre{padding: 1em;} + +.container{ + margin: 0 auto; + max-width: 80.0rem; + padding: 0 2.0rem; + position: relative; + width: 100% +} +select { + width: auto; +} + +/* Phoenix promo and logo */ +.phx-hero { + text-align: center; + border-bottom: 1px solid #e3e3e3; + background: #eee; + border-radius: 6px; + padding: 3em 3em 1em; + margin-bottom: 3rem; + font-weight: 200; + font-size: 120%; +} +.phx-hero input { + background: #ffffff; +} +.phx-logo { + min-width: 300px; + margin: 1rem; + display: block; +} +.phx-logo img { + width: auto; + display: block; +} + +/* Headers */ +header { + width: 100%; + background: #fdfdfd; + border-bottom: 1px solid #eaeaea; + margin-bottom: 2rem; +} +header section { + align-items: center; + display: flex; + flex-direction: column; + justify-content: space-between; +} +header section :first-child { + order: 2; +} +header section :last-child { + order: 1; +} +header nav ul, +header nav li { + margin: 0; + padding: 0; + display: block; + text-align: right; + white-space: nowrap; +} +header nav ul { + margin: 1rem; + margin-top: 0; +} +header nav a { + display: block; +} + +@media (min-width: 40.0rem) { /* Small devices (landscape phones, 576px and up) */ + header section { + flex-direction: row; + } + header nav ul { + margin: 1rem; + } + .phx-logo { + flex-basis: 527px; + margin: 2rem 1rem; + } +} diff --git a/phoenix-1.6/random_number/assets/js/app.js b/phoenix-1.6/random_number/assets/js/app.js new file mode 100644 index 000000000..2ca06a566 --- /dev/null +++ b/phoenix-1.6/random_number/assets/js/app.js @@ -0,0 +1,45 @@ +// We import the CSS which is extracted to its own file by esbuild. +// Remove this line if you add a your own CSS build pipeline (e.g postcss). +import "../css/app.css" + +// If you want to use Phoenix channels, run `mix help phx.gen.channel` +// to get started and then uncomment the line below. +// import "./user_socket.js" + +// You can include dependencies in two ways. +// +// The simplest option is to put them in assets/vendor and +// import them using relative paths: +// +// import "../vendor/some-package.js" +// +// Alternatively, you can `npm install some-package --prefix assets` and import +// them using a path starting with the package name: +// +// import "some-package" +// + +// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. +import "phoenix_html" +// Establish Phoenix Socket and LiveView configuration. +import {Socket} from "phoenix" +import {LiveSocket} from "phoenix_live_view" +import topbar from "../vendor/topbar" + +let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") +let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) + +// Show progress bar on live navigation and form submits +topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) +window.addEventListener("phx:page-loading-start", info => topbar.show()) +window.addEventListener("phx:page-loading-stop", info => topbar.hide()) + +// connect if there are any LiveViews on the page +liveSocket.connect() + +// expose liveSocket on window for web console debug logs and latency simulation: +// >> liveSocket.enableDebug() +// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session +// >> liveSocket.disableLatencySim() +window.liveSocket = liveSocket + diff --git a/phoenix-1.6/random_number/assets/vendor/topbar.js b/phoenix-1.6/random_number/assets/vendor/topbar.js new file mode 100644 index 000000000..1f6220974 --- /dev/null +++ b/phoenix-1.6/random_number/assets/vendor/topbar.js @@ -0,0 +1,157 @@ +/** + * @license MIT + * topbar 1.0.0, 2021-01-06 + * https://buunguyen.github.io/topbar + * Copyright (c) 2021 Buu Nguyen + */ +(function (window, document) { + "use strict"; + + // https://gist.github.com/paulirish/1579671 + (function () { + var lastTime = 0; + var vendors = ["ms", "moz", "webkit", "o"]; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = + window[vendors[x] + "RequestAnimationFrame"]; + window.cancelAnimationFrame = + window[vendors[x] + "CancelAnimationFrame"] || + window[vendors[x] + "CancelRequestAnimationFrame"]; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + })(); + + var canvas, + progressTimerId, + fadeTimerId, + currentProgress, + showing, + addEvent = function (elem, type, handler) { + if (elem.addEventListener) elem.addEventListener(type, handler, false); + else if (elem.attachEvent) elem.attachEvent("on" + type, handler); + else elem["on" + type] = handler; + }, + options = { + autoRun: true, + barThickness: 3, + barColors: { + 0: "rgba(26, 188, 156, .9)", + ".25": "rgba(52, 152, 219, .9)", + ".50": "rgba(241, 196, 15, .9)", + ".75": "rgba(230, 126, 34, .9)", + "1.0": "rgba(211, 84, 0, .9)", + }, + shadowBlur: 10, + shadowColor: "rgba(0, 0, 0, .6)", + className: null, + }, + repaint = function () { + canvas.width = window.innerWidth; + canvas.height = options.barThickness * 5; // need space for shadow + + var ctx = canvas.getContext("2d"); + ctx.shadowBlur = options.shadowBlur; + ctx.shadowColor = options.shadowColor; + + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); + for (var stop in options.barColors) + lineGradient.addColorStop(stop, options.barColors[stop]); + ctx.lineWidth = options.barThickness; + ctx.beginPath(); + ctx.moveTo(0, options.barThickness / 2); + ctx.lineTo( + Math.ceil(currentProgress * canvas.width), + options.barThickness / 2 + ); + ctx.strokeStyle = lineGradient; + ctx.stroke(); + }, + createCanvas = function () { + canvas = document.createElement("canvas"); + var style = canvas.style; + style.position = "fixed"; + style.top = style.left = style.right = style.margin = style.padding = 0; + style.zIndex = 100001; + style.display = "none"; + if (options.className) canvas.classList.add(options.className); + document.body.appendChild(canvas); + addEvent(window, "resize", repaint); + }, + topbar = { + config: function (opts) { + for (var key in opts) + if (options.hasOwnProperty(key)) options[key] = opts[key]; + }, + show: function () { + if (showing) return; + showing = true; + if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); + if (!canvas) createCanvas(); + canvas.style.opacity = 1; + canvas.style.display = "block"; + topbar.progress(0); + if (options.autoRun) { + (function loop() { + progressTimerId = window.requestAnimationFrame(loop); + topbar.progress( + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) + ); + })(); + } + }, + progress: function (to) { + if (typeof to === "undefined") return currentProgress; + if (typeof to === "string") { + to = + (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 + ? currentProgress + : 0) + parseFloat(to); + } + currentProgress = to > 1 ? 1 : to; + repaint(); + return currentProgress; + }, + hide: function () { + if (!showing) return; + showing = false; + if (progressTimerId != null) { + window.cancelAnimationFrame(progressTimerId); + progressTimerId = null; + } + (function loop() { + if (topbar.progress("+.1") >= 1) { + canvas.style.opacity -= 0.05; + if (canvas.style.opacity <= 0.05) { + canvas.style.display = "none"; + fadeTimerId = null; + return; + } + } + fadeTimerId = window.requestAnimationFrame(loop); + })(); + }, + }; + + if (typeof module === "object" && typeof module.exports === "object") { + module.exports = topbar; + } else if (typeof define === "function" && define.amd) { + define(function () { + return topbar; + }); + } else { + this.topbar = topbar; + } +}.call(this, window, document)); diff --git a/phoenix-1.6/random_number/config/config.exs b/phoenix-1.6/random_number/config/config.exs new file mode 100644 index 000000000..42341eaee --- /dev/null +++ b/phoenix-1.6/random_number/config/config.exs @@ -0,0 +1,49 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Config module. +# +# This configuration file is loaded before any dependency and +# is restricted to this project. + +# General application configuration +import Config + +# Configures the endpoint +config :random_number, RandomNumberWeb.Endpoint, + url: [host: "localhost"], + render_errors: [view: RandomNumberWeb.ErrorView, accepts: ~w(html json), layout: false], + pubsub_server: RandomNumber.PubSub, + live_view: [signing_salt: "dqVm5Fdf"] + +# Configures the mailer +# +# By default it uses the "Local" adapter which stores the emails +# locally. You can see the emails in your browser, at "/dev/mailbox". +# +# For production it's recommended to configure a different adapter +# at the `config/runtime.exs`. +config :random_number, RandomNumber.Mailer, adapter: Swoosh.Adapters.Local + +# Swoosh API client is needed for adapters other than SMTP. +config :swoosh, :api_client, false + +# Configure esbuild (the version is required) +config :esbuild, + version: "0.14.29", + default: [ + args: + ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), + cd: Path.expand("../assets", __DIR__), + env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} + ] + +# Configures Elixir's Logger +config :logger, :console, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id] + +# Use Jason for JSON parsing in Phoenix +config :phoenix, :json_library, Jason + +# Import environment specific config. This must remain at the bottom +# of this file so it overrides the configuration defined above. +import_config "#{config_env()}.exs" diff --git a/phoenix-1.6/random_number/config/dev.exs b/phoenix-1.6/random_number/config/dev.exs new file mode 100644 index 000000000..b763da167 --- /dev/null +++ b/phoenix-1.6/random_number/config/dev.exs @@ -0,0 +1,65 @@ +import Config + +# For development, we disable any cache and enable +# debugging and code reloading. +# +# The watchers configuration can be used to run external +# watchers to your application. For example, we use it +# with esbuild to bundle .js and .css sources. +config :random_number, RandomNumberWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. + # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. + http: [ip: {127, 0, 0, 1}, port: 4000], + check_origin: false, + code_reloader: true, + debug_errors: true, + secret_key_base: "NNnBf0nJ1YQqO3xlQpVi2IHExlE2jR0pNxyEFOnKZuVF1pWpsCI4JuVYriaq/kRT", + watchers: [ + # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args) + esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]} + ] + +# ## SSL Support +# +# In order to use HTTPS in development, a self-signed +# certificate can be generated by running the following +# Mix task: +# +# mix phx.gen.cert +# +# Note that this task requires Erlang/OTP 20 or later. +# Run `mix help phx.gen.cert` for more information. +# +# The `http:` config above can be replaced with: +# +# https: [ +# port: 4001, +# cipher_suite: :strong, +# keyfile: "priv/cert/selfsigned_key.pem", +# certfile: "priv/cert/selfsigned.pem" +# ], +# +# If desired, both `http:` and `https:` keys can be +# configured to run both http and https servers on +# different ports. + +# Watch static and templates for browser reloading. +config :random_number, RandomNumberWeb.Endpoint, + live_reload: [ + patterns: [ + ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", + ~r"priv/gettext/.*(po)$", + ~r"lib/random_number_web/(live|views)/.*(ex)$", + ~r"lib/random_number_web/templates/.*(eex)$" + ] + ] + +# Do not include metadata nor timestamps in development logs +config :logger, :console, format: "[$level] $message\n" + +# Set a higher stacktrace during development. Avoid configuring such +# in production as building large stacktraces may be expensive. +config :phoenix, :stacktrace_depth, 20 + +# Initialize plugs at runtime for faster development compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/random_number/config/prod.exs b/phoenix-1.6/random_number/config/prod.exs new file mode 100644 index 000000000..4930ad897 --- /dev/null +++ b/phoenix-1.6/random_number/config/prod.exs @@ -0,0 +1,49 @@ +import Config + +# For production, don't forget to configure the url host +# to something meaningful, Phoenix uses this information +# when generating URLs. +# +# Note we also include the path to a cache manifest +# containing the digested version of static files. This +# manifest is generated by the `mix phx.digest` task, +# which you should run after static files are built and +# before starting your production server. +config :random_number, RandomNumberWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" + +# Do not print debug messages in production +config :logger, level: :info + +# ## SSL Support +# +# To get SSL working, you will need to add the `https` key +# to the previous section and set your `:url` port to 443: +# +# config :random_number, RandomNumberWeb.Endpoint, +# ..., +# url: [host: "example.com", port: 443], +# https: [ +# ..., +# port: 443, +# cipher_suite: :strong, +# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), +# certfile: System.get_env("SOME_APP_SSL_CERT_PATH") +# ] +# +# The `cipher_suite` is set to `:strong` to support only the +# latest and more secure SSL ciphers. This means old browsers +# and clients may not be supported. You can set it to +# `:compatible` for wider support. +# +# `:keyfile` and `:certfile` expect an absolute path to the key +# and cert in disk or a relative path inside priv, for example +# "priv/ssl/server.key". For all supported SSL configuration +# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 +# +# We also recommend setting `force_ssl` in your endpoint, ensuring +# no data is ever sent via http, always redirecting to https: +# +# config :random_number, RandomNumberWeb.Endpoint, +# force_ssl: [hsts: true] +# +# Check `Plug.SSL` for all available options in `force_ssl`. diff --git a/phoenix-1.6/random_number/config/runtime.exs b/phoenix-1.6/random_number/config/runtime.exs new file mode 100644 index 000000000..8035ff2cb --- /dev/null +++ b/phoenix-1.6/random_number/config/runtime.exs @@ -0,0 +1,68 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/random_number start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :random_number, RandomNumberWeb.Endpoint, server: true +end + +if config_env() == :prod do + # The secret key base is used to sign/encrypt cookies and other secrets. + # A default value is used in config/dev.exs and config/test.exs but you + # want to use a different value for prod and you most likely don't want + # to check this value into version control, so we use an environment + # variable instead. + secret_key_base = + System.get_env("SECRET_KEY_BASE") || + raise """ + environment variable SECRET_KEY_BASE is missing. + You can generate one by calling: mix phx.gen.secret + """ + + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + + config :random_number, RandomNumberWeb.Endpoint, + url: [host: host, port: 443, scheme: "https"], + http: [ + # Enable IPv6 and bind on all interfaces. + # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. + # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html + # for details about using IPv6 vs IPv4 and loopback vs public addresses. + ip: {0, 0, 0, 0, 0, 0, 0, 0}, + port: port + ], + secret_key_base: secret_key_base + + # ## Configuring the mailer + # + # In production you need to configure the mailer to use a different adapter. + # Also, you may need to configure the Swoosh API client of your choice if you + # are not using SMTP. Here is an example of the configuration: + # + # config :random_number, RandomNumber.Mailer, + # adapter: Swoosh.Adapters.Mailgun, + # api_key: System.get_env("MAILGUN_API_KEY"), + # domain: System.get_env("MAILGUN_DOMAIN") + # + # For this example you need include a HTTP client required by Swoosh API client. + # Swoosh supports Hackney and Finch out of the box: + # + # config :swoosh, :api_client, Swoosh.ApiClient.Hackney + # + # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. +end diff --git a/phoenix-1.6/random_number/config/test.exs b/phoenix-1.6/random_number/config/test.exs new file mode 100644 index 000000000..a83d47823 --- /dev/null +++ b/phoenix-1.6/random_number/config/test.exs @@ -0,0 +1,18 @@ +import Config + +# We don't run a server during test. If one is required, +# you can enable the server option below. +config :random_number, RandomNumberWeb.Endpoint, + http: [ip: {127, 0, 0, 1}, port: 4002], + secret_key_base: "0k0qqH+QEs2L2geoma/UH7GsLfi67THVnVa1WtnVy/bmUOwAbl3e28YQjP3jQl3J", + server: false + +# In test we don't send emails. +config :random_number, RandomNumber.Mailer, + adapter: Swoosh.Adapters.Test + +# Print only warnings and errors during test +config :logger, level: :warn + +# Initialize plugs at runtime for faster test compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.6/random_number/lib/random_number.ex b/phoenix-1.6/random_number/lib/random_number.ex new file mode 100644 index 000000000..b891e071d --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number.ex @@ -0,0 +1,14 @@ +defmodule RandomNumber do + @moduledoc """ + RandomNumber keeps the contexts that define your domain + and business logic. + + Contexts are also responsible for managing your data, regardless + if it comes from the database, an external API or others. + """ + + def random_number() do + Enum.random(1..100) + end + +end diff --git a/phoenix-1.6/random_number/lib/random_number/application.ex b/phoenix-1.6/random_number/lib/random_number/application.ex new file mode 100644 index 000000000..86eb38f84 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number/application.ex @@ -0,0 +1,34 @@ +defmodule RandomNumber.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + children = [ + # Start the Telemetry supervisor + RandomNumberWeb.Telemetry, + # Start the PubSub system + {Phoenix.PubSub, name: RandomNumber.PubSub}, + # Start the Endpoint (http/https) + RandomNumberWeb.Endpoint + # Start a worker by calling: RandomNumber.Worker.start_link(arg) + # {RandomNumber.Worker, arg} + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: RandomNumber.Supervisor] + Supervisor.start_link(children, opts) + end + + # Tell Phoenix to update the endpoint configuration + # whenever the application is updated. + @impl true + def config_change(changed, _new, removed) do + RandomNumberWeb.Endpoint.config_change(changed, removed) + :ok + end +end diff --git a/phoenix-1.6/random_number/lib/random_number/mailer.ex b/phoenix-1.6/random_number/lib/random_number/mailer.ex new file mode 100644 index 000000000..27ead547d --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number/mailer.ex @@ -0,0 +1,3 @@ +defmodule RandomNumber.Mailer do + use Swoosh.Mailer, otp_app: :random_number +end diff --git a/phoenix-1.6/random_number/lib/random_number_web.ex b/phoenix-1.6/random_number/lib/random_number_web.ex new file mode 100644 index 000000000..4eb06eddb --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web.ex @@ -0,0 +1,110 @@ +defmodule RandomNumberWeb do + @moduledoc """ + The entrypoint for defining your web interface, such + as controllers, views, channels and so on. + + This can be used in your application as: + + use RandomNumberWeb, :controller + use RandomNumberWeb, :view + + The definitions below will be executed for every view, + controller, etc, so keep them short and clean, focused + on imports, uses and aliases. + + Do NOT define functions inside the quoted expressions + below. Instead, define any helper function in modules + and import those modules here. + """ + + def controller do + quote do + use Phoenix.Controller, namespace: RandomNumberWeb + + import Plug.Conn + import RandomNumberWeb.Gettext + alias RandomNumberWeb.Router.Helpers, as: Routes + end + end + + def view do + quote do + use Phoenix.View, + root: "lib/random_number_web/templates", + namespace: RandomNumberWeb + + # Import convenience functions from controllers + import Phoenix.Controller, + only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1] + + # Include shared imports and aliases for views + unquote(view_helpers()) + end + end + + def live_view do + quote do + use Phoenix.LiveView, + layout: {RandomNumberWeb.LayoutView, "live.html"} + + unquote(view_helpers()) + end + end + + def live_component do + quote do + use Phoenix.LiveComponent + + unquote(view_helpers()) + end + end + + def component do + quote do + use Phoenix.Component + + unquote(view_helpers()) + end + end + + def router do + quote do + use Phoenix.Router + + import Plug.Conn + import Phoenix.Controller + import Phoenix.LiveView.Router + end + end + + def channel do + quote do + use Phoenix.Channel + import RandomNumberWeb.Gettext + end + end + + defp view_helpers do + quote do + # Use all HTML functionality (forms, tags, etc) + use Phoenix.HTML + + # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc) + import Phoenix.LiveView.Helpers + + # Import basic rendering functionality (render, render_layout, etc) + import Phoenix.View + + import RandomNumberWeb.ErrorHelpers + import RandomNumberWeb.Gettext + alias RandomNumberWeb.Router.Helpers, as: Routes + end + end + + @doc """ + When used, dispatch to the appropriate controller/view/etc. + """ + defmacro __using__(which) when is_atom(which) do + apply(__MODULE__, which, []) + end +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/controllers/page_controller.ex b/phoenix-1.6/random_number/lib/random_number_web/controllers/page_controller.ex new file mode 100644 index 000000000..e3c8667be --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/controllers/page_controller.ex @@ -0,0 +1,8 @@ +defmodule RandomNumberWeb.PageController do + use RandomNumberWeb, :controller + + def index(conn, _params) do + render(conn, "index.html") + end + +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/controllers/random_number_controller.ex b/phoenix-1.6/random_number/lib/random_number_web/controllers/random_number_controller.ex new file mode 100644 index 000000000..c3f1085dd --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/controllers/random_number_controller.ex @@ -0,0 +1,7 @@ +defmodule RandomNumberWeb.RandomNumberController do + use RandomNumberWeb, :controller + + def random_number(conn, _params) do + render(conn, "random_number.html") + end +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/endpoint.ex b/phoenix-1.6/random_number/lib/random_number_web/endpoint.ex new file mode 100644 index 000000000..71459ab55 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/endpoint.ex @@ -0,0 +1,49 @@ +defmodule RandomNumberWeb.Endpoint do + use Phoenix.Endpoint, otp_app: :random_number + + # The session will be stored in the cookie and signed, + # this means its contents can be read but not tampered with. + # Set :encryption_salt if you would also like to encrypt it. + @session_options [ + store: :cookie, + key: "_random_number_key", + signing_salt: "24TE+CBv" + ] + + socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] + + # Serve at "/" the static files from "priv/static" directory. + # + # You should set gzip to true if you are running phx.digest + # when deploying your static files in production. + plug Plug.Static, + at: "/", + from: :random_number, + gzip: false, + only: ~w(assets fonts images favicon.ico robots.txt) + + # Code reloading can be explicitly enabled under the + # :code_reloader configuration of your endpoint. + if code_reloading? do + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + plug Phoenix.LiveReloader + plug Phoenix.CodeReloader + end + + plug Phoenix.LiveDashboard.RequestLogger, + param_key: "request_logger", + cookie_key: "request_logger" + + plug Plug.RequestId + plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] + + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Phoenix.json_library() + + plug Plug.MethodOverride + plug Plug.Head + plug Plug.Session, @session_options + plug RandomNumberWeb.Router +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/gettext.ex b/phoenix-1.6/random_number/lib/random_number_web/gettext.ex new file mode 100644 index 000000000..1b54ee342 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/gettext.ex @@ -0,0 +1,24 @@ +defmodule RandomNumberWeb.Gettext do + @moduledoc """ + A module providing Internationalization with a gettext-based API. + + By using [Gettext](https://hexdocs.pm/gettext), + your module gains a set of macros for translations, for example: + + import RandomNumberWeb.Gettext + + # Simple translation + gettext("Here is the string to translate") + + # Plural translation + ngettext("Here is the string to translate", + "Here are the strings to translate", + 3) + + # Domain-based translation + dgettext("errors", "Here is the error message to translate") + + See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. + """ + use Gettext, otp_app: :random_number +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/router.ex b/phoenix-1.6/random_number/lib/random_number_web/router.ex new file mode 100644 index 000000000..29fac6447 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/router.ex @@ -0,0 +1,58 @@ +defmodule RandomNumberWeb.Router do + use RandomNumberWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_live_flash + plug :put_root_layout, {RandomNumberWeb.LayoutView, :root} + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + scope "/", RandomNumberWeb do + pipe_through :browser + + get "/", PageController, :index + + get "/random_number", RandomNumberController, :random_number + end + + # Other scopes may use custom stacks. + # scope "/api", RandomNumberWeb do + # pipe_through :api + # end + + # Enables LiveDashboard only for development + # + # If you want to use the LiveDashboard in production, you should put + # it behind authentication and allow only admins to access it. + # If your application does not have an admins-only section yet, + # you can use Plug.BasicAuth to set up some basic authentication + # as long as you are also using SSL (which you should anyway). + if Mix.env() in [:dev, :test] do + import Phoenix.LiveDashboard.Router + + scope "/" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: RandomNumberWeb.Telemetry + end + end + + # Enables the Swoosh mailbox preview in development. + # + # Note that preview only shows emails that were sent by the same + # node running the Phoenix server. + if Mix.env() == :dev do + scope "/dev" do + pipe_through :browser + + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/telemetry.ex b/phoenix-1.6/random_number/lib/random_number_web/telemetry.ex new file mode 100644 index 000000000..9bf9de878 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/telemetry.ex @@ -0,0 +1,48 @@ +defmodule RandomNumberWeb.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp periodic_measurements do + [ + # A module, function and arguments to be invoked periodically. + # This function must call :telemetry.execute/3 and a metric must be added above. + # {RandomNumberWeb, :count_users, []} + ] + end +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/templates/layout/app.html.heex b/phoenix-1.6/random_number/lib/random_number_web/templates/layout/app.html.heex new file mode 100644 index 000000000..169aed956 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/templates/layout/app.html.heex @@ -0,0 +1,5 @@ +
+ + + <%= @inner_content %> +
diff --git a/phoenix-1.6/random_number/lib/random_number_web/templates/layout/live.html.heex b/phoenix-1.6/random_number/lib/random_number_web/templates/layout/live.html.heex new file mode 100644 index 000000000..a29d60448 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/templates/layout/live.html.heex @@ -0,0 +1,11 @@ +
+ + + + + <%= @inner_content %> +
diff --git a/phoenix-1.6/random_number/lib/random_number_web/templates/layout/root.html.heex b/phoenix-1.6/random_number/lib/random_number_web/templates/layout/root.html.heex new file mode 100644 index 000000000..4c84ba771 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/templates/layout/root.html.heex @@ -0,0 +1,30 @@ + + + + + + + + <%= live_title_tag assigns[:page_title] || "RandomNumber", suffix: " · Phoenix Framework" %> + + + + +
+
+ + +
+
+ <%= @inner_content %> + + diff --git a/phoenix-1.6/random_number/lib/random_number_web/templates/page/index.html.heex b/phoenix-1.6/random_number/lib/random_number_web/templates/page/index.html.heex new file mode 100644 index 000000000..f844bd8d7 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/templates/page/index.html.heex @@ -0,0 +1,41 @@ +
+

<%= gettext "Welcome to %{name}!", name: "Phoenix" %>

+

Peace of mind from prototype to production

+
+ +
+ + +
diff --git a/phoenix-1.6/random_number/lib/random_number_web/templates/random_number/random_number.html.heex b/phoenix-1.6/random_number/lib/random_number_web/templates/random_number/random_number.html.heex new file mode 100644 index 000000000..193b32d8e --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/templates/random_number/random_number.html.heex @@ -0,0 +1 @@ +

<%= RandomNumber.random_number() %>

diff --git a/phoenix-1.6/random_number/lib/random_number_web/views/error_helpers.ex b/phoenix-1.6/random_number/lib/random_number_web/views/error_helpers.ex new file mode 100644 index 000000000..088a3e2e3 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/views/error_helpers.ex @@ -0,0 +1,47 @@ +defmodule RandomNumberWeb.ErrorHelpers do + @moduledoc """ + Conveniences for translating and building error messages. + """ + + use Phoenix.HTML + + @doc """ + Generates tag for inlined form input errors. + """ + def error_tag(form, field) do + Enum.map(Keyword.get_values(form.errors, field), fn error -> + content_tag(:span, translate_error(error), + class: "invalid-feedback", + phx_feedback_for: input_name(form, field) + ) + end) + end + + @doc """ + Translates an error message using gettext. + """ + def translate_error({msg, opts}) do + # When using gettext, we typically pass the strings we want + # to translate as a static argument: + # + # # Translate "is invalid" in the "errors" domain + # dgettext("errors", "is invalid") + # + # # Translate the number of files with plural rules + # dngettext("errors", "1 file", "%{count} files", count) + # + # Because the error messages we show in our forms and APIs + # are defined inside Ecto, we need to translate them dynamically. + # This requires us to call the Gettext module passing our gettext + # backend as first argument. + # + # Note we use the "errors" domain, which means translations + # should be written to the errors.po file. The :count option is + # set by Ecto and indicates we should also apply plural rules. + if count = opts[:count] do + Gettext.dngettext(RandomNumberWeb.Gettext, "errors", msg, msg, count, opts) + else + Gettext.dgettext(RandomNumberWeb.Gettext, "errors", msg, opts) + end + end +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/views/error_view.ex b/phoenix-1.6/random_number/lib/random_number_web/views/error_view.ex new file mode 100644 index 000000000..45a647322 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/views/error_view.ex @@ -0,0 +1,16 @@ +defmodule RandomNumberWeb.ErrorView do + use RandomNumberWeb, :view + + # If you want to customize a particular status code + # for a certain format, you may uncomment below. + # def render("500.html", _assigns) do + # "Internal Server Error" + # end + + # By default, Phoenix returns the status message from + # the template name. For example, "404.html" becomes + # "Not Found". + def template_not_found(template, _assigns) do + Phoenix.Controller.status_message_from_template(template) + end +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/views/layout_view.ex b/phoenix-1.6/random_number/lib/random_number_web/views/layout_view.ex new file mode 100644 index 000000000..7d877f817 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/views/layout_view.ex @@ -0,0 +1,7 @@ +defmodule RandomNumberWeb.LayoutView do + use RandomNumberWeb, :view + + # Phoenix LiveDashboard is available only in development by default, + # so we instruct Elixir to not warn if the dashboard route is missing. + @compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}} +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/views/page_view.ex b/phoenix-1.6/random_number/lib/random_number_web/views/page_view.ex new file mode 100644 index 000000000..7b9f50750 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/views/page_view.ex @@ -0,0 +1,3 @@ +defmodule RandomNumberWeb.PageView do + use RandomNumberWeb, :view +end diff --git a/phoenix-1.6/random_number/lib/random_number_web/views/random_number_view.ex b/phoenix-1.6/random_number/lib/random_number_web/views/random_number_view.ex new file mode 100644 index 000000000..39f447933 --- /dev/null +++ b/phoenix-1.6/random_number/lib/random_number_web/views/random_number_view.ex @@ -0,0 +1,3 @@ +defmodule RandomNumberWeb.RandomNumberView do + use RandomNumberWeb, :view +end diff --git a/phoenix-1.6/random_number/mix.exs b/phoenix-1.6/random_number/mix.exs new file mode 100644 index 000000000..df66f3a70 --- /dev/null +++ b/phoenix-1.6/random_number/mix.exs @@ -0,0 +1,64 @@ +defmodule RandomNumber.MixProject do + use Mix.Project + + def project do + [ + app: :random_number, + version: "0.1.0", + elixir: "~> 1.12", + elixirc_paths: elixirc_paths(Mix.env()), + compilers: [:gettext] ++ Mix.compilers(), + start_permanent: Mix.env() == :prod, + aliases: aliases(), + deps: deps() + ] + end + + # Configuration for the OTP application. + # + # Type `mix help compile.app` for more information. + def application do + [ + mod: {RandomNumber.Application, []}, + extra_applications: [:logger, :runtime_tools] + ] + end + + # Specifies which paths to compile per environment. + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] + + # Specifies your project dependencies. + # + # Type `mix help deps` for examples and options. + defp deps do + [ + {:phoenix, "~> 1.6.15"}, + {:phoenix_html, "~> 3.0"}, + {:phoenix_live_reload, "~> 1.2", only: :dev}, + {:phoenix_live_view, "~> 0.17.5"}, + {:floki, ">= 0.30.0", only: :test}, + {:phoenix_live_dashboard, "~> 0.6"}, + {:esbuild, "~> 0.4", runtime: Mix.env() == :dev}, + {:swoosh, "~> 1.3"}, + {:telemetry_metrics, "~> 0.6"}, + {:telemetry_poller, "~> 1.0"}, + {:gettext, "~> 0.18"}, + {:jason, "~> 1.2"}, + {:plug_cowboy, "~> 2.5"} + ] + end + + # Aliases are shortcuts or tasks specific to the current project. + # For example, to install project dependencies and perform other setup tasks, run: + # + # $ mix setup + # + # See the documentation for `Mix` for more info on aliases. + defp aliases do + [ + setup: ["deps.get"], + "assets.deploy": ["esbuild default --minify", "phx.digest"] + ] + end +end diff --git a/phoenix-1.6/random_number/mix.lock b/phoenix-1.6/random_number/mix.lock new file mode 100644 index 000000000..47b126398 --- /dev/null +++ b/phoenix-1.6/random_number/mix.lock @@ -0,0 +1,29 @@ +%{ + "castore": {:hex, :castore, "1.0.1", "240b9edb4e9e94f8f56ab39d8d2d0a57f49e46c56aced8f873892df8ff64ff5a", [:mix], [], "hexpm", "b4951de93c224d44fac71614beabd88b71932d0b1dea80d2f80fb9044e01bbb3"}, + "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, + "esbuild": {:hex, :esbuild, "0.6.1", "a774bfa7b4512a1211bf15880b462be12a4c48ed753a170c68c63b2c95888150", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "569f7409fb5a932211573fc20e2a930a0d5cf3377c5b4f6506c651b1783a1678"}, + "expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"}, + "gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"}, + "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, + "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, + "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"}, + "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.14", "5ec615d4d61bf9d4755f158bd6c80372b715533fe6d6219e12d74fb5eedbeac1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "afeb6ba43ce329a6f7fc1c9acdfc6d3039995345f025febb7f409a92f6faebd3"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"}, + "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"}, + "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"}, + "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, + "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, +} diff --git a/phoenix-1.6/random_number/priv/gettext/en/LC_MESSAGES/errors.po b/phoenix-1.6/random_number/priv/gettext/en/LC_MESSAGES/errors.po new file mode 100644 index 000000000..cdec3a113 --- /dev/null +++ b/phoenix-1.6/random_number/priv/gettext/en/LC_MESSAGES/errors.po @@ -0,0 +1,11 @@ +## `msgid`s in this file come from POT (.pot) files. +## +## Do not add, change, or remove `msgid`s manually here as +## they're tied to the ones in the corresponding POT file +## (with the same domain). +## +## Use `mix gettext.extract --merge` or `mix gettext.merge` +## to merge POT files into PO files. +msgid "" +msgstr "" +"Language: en\n" diff --git a/phoenix-1.6/random_number/priv/gettext/errors.pot b/phoenix-1.6/random_number/priv/gettext/errors.pot new file mode 100644 index 000000000..d6f47fa87 --- /dev/null +++ b/phoenix-1.6/random_number/priv/gettext/errors.pot @@ -0,0 +1,10 @@ +## This is a PO Template file. +## +## `msgid`s here are often extracted from source code. +## Add new translations manually only if they're dynamic +## translations that can't be statically extracted. +## +## Run `mix gettext.extract` to bring this file up to +## date. Leave `msgstr`s empty as changing them here has no +## effect: edit them in PO (`.po`) files instead. + diff --git a/phoenix-1.6/random_number/priv/static/favicon.ico b/phoenix-1.6/random_number/priv/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..73de524aaadcf60fbe9d32881db0aa86b58b5cb9 GIT binary patch literal 1258 zcmbtUO>fgM7{=qN=;Mz_82;lvPEdVaxv-<-&=sZLwab?3I zBP>U*&(Hv<5n@9ZQ$vhg#|u$Zmtq8BV;+W*7(?jOx-{r?#TE&$Sdq77MbdJjD5`-q zMm_z(jLv3t>5NhzK{%aG(Yudfpjd3AFdKe2U7&zdepTe>^s(@!&0X8TJ`h+-I?84Ml# literal 0 HcmV?d00001 diff --git a/phoenix-1.6/random_number/priv/static/images/phoenix.png b/phoenix-1.6/random_number/priv/static/images/phoenix.png new file mode 100644 index 0000000000000000000000000000000000000000..9c81075f63d2151e6f40e9aa66f665749a87cc6a GIT binary patch literal 13900 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 UWxWXg`G1#+f~I_}taaG`2PLnS&Hw-a literal 0 HcmV?d00001 diff --git a/phoenix-1.6/random_number/priv/static/robots.txt b/phoenix-1.6/random_number/priv/static/robots.txt new file mode 100644 index 000000000..26e06b5f1 --- /dev/null +++ b/phoenix-1.6/random_number/priv/static/robots.txt @@ -0,0 +1,5 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / diff --git a/phoenix-1.6/random_number/test/random_number_web/controllers/page_controller_test.exs b/phoenix-1.6/random_number/test/random_number_web/controllers/page_controller_test.exs new file mode 100644 index 000000000..ba3133ec3 --- /dev/null +++ b/phoenix-1.6/random_number/test/random_number_web/controllers/page_controller_test.exs @@ -0,0 +1,8 @@ +defmodule RandomNumberWeb.PageControllerTest do + use RandomNumberWeb.ConnCase + + test "GET /", %{conn: conn} do + conn = get(conn, "/") + assert html_response(conn, 200) =~ "Welcome to Phoenix!" + end +end diff --git a/phoenix-1.6/random_number/test/random_number_web/views/error_view_test.exs b/phoenix-1.6/random_number/test/random_number_web/views/error_view_test.exs new file mode 100644 index 000000000..0c3c7c4c8 --- /dev/null +++ b/phoenix-1.6/random_number/test/random_number_web/views/error_view_test.exs @@ -0,0 +1,14 @@ +defmodule RandomNumberWeb.ErrorViewTest do + use RandomNumberWeb.ConnCase, async: true + + # Bring render/3 and render_to_string/3 for testing custom views + import Phoenix.View + + test "renders 404.html" do + assert render_to_string(RandomNumberWeb.ErrorView, "404.html", []) == "Not Found" + end + + test "renders 500.html" do + assert render_to_string(RandomNumberWeb.ErrorView, "500.html", []) == "Internal Server Error" + end +end diff --git a/phoenix-1.6/random_number/test/random_number_web/views/layout_view_test.exs b/phoenix-1.6/random_number/test/random_number_web/views/layout_view_test.exs new file mode 100644 index 000000000..7a032de40 --- /dev/null +++ b/phoenix-1.6/random_number/test/random_number_web/views/layout_view_test.exs @@ -0,0 +1,8 @@ +defmodule RandomNumberWeb.LayoutViewTest do + use RandomNumberWeb.ConnCase, async: true + + # When testing helpers, you may want to import Phoenix.HTML and + # use functions such as safe_to_string() to convert the helper + # result into an HTML string. + # import Phoenix.HTML +end diff --git a/phoenix-1.6/random_number/test/random_number_web/views/page_view_test.exs b/phoenix-1.6/random_number/test/random_number_web/views/page_view_test.exs new file mode 100644 index 000000000..26ed22954 --- /dev/null +++ b/phoenix-1.6/random_number/test/random_number_web/views/page_view_test.exs @@ -0,0 +1,3 @@ +defmodule RandomNumberWeb.PageViewTest do + use RandomNumberWeb.ConnCase, async: true +end diff --git a/phoenix-1.6/random_number/test/support/conn_case.ex b/phoenix-1.6/random_number/test/support/conn_case.ex new file mode 100644 index 000000000..c0b572fc2 --- /dev/null +++ b/phoenix-1.6/random_number/test/support/conn_case.ex @@ -0,0 +1,37 @@ +defmodule RandomNumberWeb.ConnCase do + @moduledoc """ + This module defines the test case to be used by + tests that require setting up a connection. + + Such tests rely on `Phoenix.ConnTest` and also + import other functionality to make it easier + to build common data structures and query the data layer. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use RandomNumberWeb.ConnCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + # Import conveniences for testing with connections + import Plug.Conn + import Phoenix.ConnTest + import RandomNumberWeb.ConnCase + + alias RandomNumberWeb.Router.Helpers, as: Routes + + # The default endpoint for testing + @endpoint RandomNumberWeb.Endpoint + end + end + + setup _tags do + {:ok, conn: Phoenix.ConnTest.build_conn()} + end +end diff --git a/phoenix-1.6/random_number/test/test_helper.exs b/phoenix-1.6/random_number/test/test_helper.exs new file mode 100644 index 000000000..869559e70 --- /dev/null +++ b/phoenix-1.6/random_number/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/phoenix-1.7/counter/.formatter.exs b/phoenix-1.7/counter/.formatter.exs new file mode 100644 index 000000000..e945e12b9 --- /dev/null +++ b/phoenix-1.7/counter/.formatter.exs @@ -0,0 +1,5 @@ +[ + import_deps: [:phoenix], + plugins: [Phoenix.LiveView.HTMLFormatter], + inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}"] +] diff --git a/phoenix-1.7/counter/.gitignore b/phoenix-1.7/counter/.gitignore new file mode 100644 index 000000000..bd521da14 --- /dev/null +++ b/phoenix-1.7/counter/.gitignore @@ -0,0 +1,37 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Temporary files, for example, from tests. +/tmp/ + +# Ignore package tarball (built via "mix hex.build"). +counter-*.tar + +# Ignore assets that are produced by build tools. +/priv/static/assets/ + +# Ignore digested assets cache. +/priv/static/cache_manifest.json + +# In case you use Node.js/npm, you want to ignore these. +npm-debug.log +/assets/node_modules/ + diff --git a/phoenix-1.7/counter/README.md b/phoenix-1.7/counter/README.md new file mode 100644 index 000000000..b8a1d7779 --- /dev/null +++ b/phoenix-1.7/counter/README.md @@ -0,0 +1,18 @@ +# Counter + +To start your Phoenix server: + + * Run `mix setup` to install and setup dependencies + * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` + +Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. + +Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). + +## Learn more + + * Official website: https://www.phoenixframework.org/ + * Guides: https://hexdocs.pm/phoenix/overview.html + * Docs: https://hexdocs.pm/phoenix + * Forum: https://elixirforum.com/c/phoenix-forum + * Source: https://github.com/phoenixframework/phoenix diff --git a/phoenix-1.7/counter/assets/css/app.css b/phoenix-1.7/counter/assets/css/app.css new file mode 100644 index 000000000..378c8f905 --- /dev/null +++ b/phoenix-1.7/counter/assets/css/app.css @@ -0,0 +1,5 @@ +@import "tailwindcss/base"; +@import "tailwindcss/components"; +@import "tailwindcss/utilities"; + +/* This file is for your main application CSS */ diff --git a/phoenix-1.7/counter/assets/js/app.js b/phoenix-1.7/counter/assets/js/app.js new file mode 100644 index 000000000..df0cdd9f6 --- /dev/null +++ b/phoenix-1.7/counter/assets/js/app.js @@ -0,0 +1,41 @@ +// If you want to use Phoenix channels, run `mix help phx.gen.channel` +// to get started and then uncomment the line below. +// import "./user_socket.js" + +// You can include dependencies in two ways. +// +// The simplest option is to put them in assets/vendor and +// import them using relative paths: +// +// import "../vendor/some-package.js" +// +// Alternatively, you can `npm install some-package --prefix assets` and import +// them using a path starting with the package name: +// +// import "some-package" +// + +// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. +import "phoenix_html" +// Establish Phoenix Socket and LiveView configuration. +import {Socket} from "phoenix" +import {LiveSocket} from "phoenix_live_view" +import topbar from "../vendor/topbar" + +let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") +let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) + +// Show progress bar on live navigation and form submits +topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) +window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) +window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) + +// connect if there are any LiveViews on the page +liveSocket.connect() + +// expose liveSocket on window for web console debug logs and latency simulation: +// >> liveSocket.enableDebug() +// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session +// >> liveSocket.disableLatencySim() +window.liveSocket = liveSocket + diff --git a/phoenix-1.7/counter/assets/tailwind.config.js b/phoenix-1.7/counter/assets/tailwind.config.js new file mode 100644 index 000000000..cc9e6a276 --- /dev/null +++ b/phoenix-1.7/counter/assets/tailwind.config.js @@ -0,0 +1,67 @@ +// See the Tailwind configuration guide for advanced usage +// https://tailwindcss.com/docs/configuration + +const plugin = require("tailwindcss/plugin") +const fs = require("fs") +const path = require("path") + +module.exports = { + content: [ + "./js/**/*.js", + "../lib/*_web.ex", + "../lib/*_web/**/*.*ex" + ], + theme: { + extend: { + colors: { + brand: "#FD4F00", + } + }, + }, + plugins: [ + require("@tailwindcss/forms"), + // Allows prefixing tailwind classes with LiveView classes to add rules + // only when LiveView classes are applied, for example: + // + //
+ // + plugin(({addVariant}) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])), + plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])), + plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])), + plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])), + + // Embeds Hero Icons (https://heroicons.com) into your app.css bundle + // See your `CoreComponents.icon/1` for more information. + // + plugin(function({matchComponents, theme}) { + let iconsDir = path.join(__dirname, "../priv/hero_icons/optimized") + let values = {} + let icons = [ + ["", "/24/outline"], + ["-solid", "/24/solid"], + ["-mini", "/20/solid"] + ] + icons.forEach(([suffix, dir]) => { + fs.readdirSync(path.join(iconsDir, dir)).map(file => { + let name = path.basename(file, ".svg") + suffix + values[name] = {name, fullPath: path.join(iconsDir, dir, file)} + }) + }) + matchComponents({ + "hero": ({name, fullPath}) => { + let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "") + return { + [`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`, + "-webkit-mask": `var(--hero-${name})`, + "mask": `var(--hero-${name})`, + "background-color": "currentColor", + "vertical-align": "middle", + "display": "inline-block", + "width": theme("spacing.5"), + "height": theme("spacing.5") + } + } + }, {values}) + }) + ] +} diff --git a/phoenix-1.7/counter/assets/vendor/topbar.js b/phoenix-1.7/counter/assets/vendor/topbar.js new file mode 100644 index 000000000..41957274d --- /dev/null +++ b/phoenix-1.7/counter/assets/vendor/topbar.js @@ -0,0 +1,165 @@ +/** + * @license MIT + * topbar 2.0.0, 2023-02-04 + * https://buunguyen.github.io/topbar + * Copyright (c) 2021 Buu Nguyen + */ +(function (window, document) { + "use strict"; + + // https://gist.github.com/paulirish/1579671 + (function () { + var lastTime = 0; + var vendors = ["ms", "moz", "webkit", "o"]; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = + window[vendors[x] + "RequestAnimationFrame"]; + window.cancelAnimationFrame = + window[vendors[x] + "CancelAnimationFrame"] || + window[vendors[x] + "CancelRequestAnimationFrame"]; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + })(); + + var canvas, + currentProgress, + showing, + progressTimerId = null, + fadeTimerId = null, + delayTimerId = null, + addEvent = function (elem, type, handler) { + if (elem.addEventListener) elem.addEventListener(type, handler, false); + else if (elem.attachEvent) elem.attachEvent("on" + type, handler); + else elem["on" + type] = handler; + }, + options = { + autoRun: true, + barThickness: 3, + barColors: { + 0: "rgba(26, 188, 156, .9)", + ".25": "rgba(52, 152, 219, .9)", + ".50": "rgba(241, 196, 15, .9)", + ".75": "rgba(230, 126, 34, .9)", + "1.0": "rgba(211, 84, 0, .9)", + }, + shadowBlur: 10, + shadowColor: "rgba(0, 0, 0, .6)", + className: null, + }, + repaint = function () { + canvas.width = window.innerWidth; + canvas.height = options.barThickness * 5; // need space for shadow + + var ctx = canvas.getContext("2d"); + ctx.shadowBlur = options.shadowBlur; + ctx.shadowColor = options.shadowColor; + + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); + for (var stop in options.barColors) + lineGradient.addColorStop(stop, options.barColors[stop]); + ctx.lineWidth = options.barThickness; + ctx.beginPath(); + ctx.moveTo(0, options.barThickness / 2); + ctx.lineTo( + Math.ceil(currentProgress * canvas.width), + options.barThickness / 2 + ); + ctx.strokeStyle = lineGradient; + ctx.stroke(); + }, + createCanvas = function () { + canvas = document.createElement("canvas"); + var style = canvas.style; + style.position = "fixed"; + style.top = style.left = style.right = style.margin = style.padding = 0; + style.zIndex = 100001; + style.display = "none"; + if (options.className) canvas.classList.add(options.className); + document.body.appendChild(canvas); + addEvent(window, "resize", repaint); + }, + topbar = { + config: function (opts) { + for (var key in opts) + if (options.hasOwnProperty(key)) options[key] = opts[key]; + }, + show: function (delay) { + if (showing) return; + if (delay) { + if (delayTimerId) return; + delayTimerId = setTimeout(() => topbar.show(), delay); + } else { + showing = true; + if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); + if (!canvas) createCanvas(); + canvas.style.opacity = 1; + canvas.style.display = "block"; + topbar.progress(0); + if (options.autoRun) { + (function loop() { + progressTimerId = window.requestAnimationFrame(loop); + topbar.progress( + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) + ); + })(); + } + } + }, + progress: function (to) { + if (typeof to === "undefined") return currentProgress; + if (typeof to === "string") { + to = + (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 + ? currentProgress + : 0) + parseFloat(to); + } + currentProgress = to > 1 ? 1 : to; + repaint(); + return currentProgress; + }, + hide: function () { + clearTimeout(delayTimerId); + delayTimerId = null; + if (!showing) return; + showing = false; + if (progressTimerId != null) { + window.cancelAnimationFrame(progressTimerId); + progressTimerId = null; + } + (function loop() { + if (topbar.progress("+.1") >= 1) { + canvas.style.opacity -= 0.05; + if (canvas.style.opacity <= 0.05) { + canvas.style.display = "none"; + fadeTimerId = null; + return; + } + } + fadeTimerId = window.requestAnimationFrame(loop); + })(); + }, + }; + + if (typeof module === "object" && typeof module.exports === "object") { + module.exports = topbar; + } else if (typeof define === "function" && define.amd) { + define(function () { + return topbar; + }); + } else { + this.topbar = topbar; + } +}.call(this, window, document)); diff --git a/phoenix-1.7/counter/config/config.exs b/phoenix-1.7/counter/config/config.exs new file mode 100644 index 000000000..2708337d6 --- /dev/null +++ b/phoenix-1.7/counter/config/config.exs @@ -0,0 +1,61 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Config module. +# +# This configuration file is loaded before any dependency and +# is restricted to this project. + +# General application configuration +import Config + +# Configures the endpoint +config :counter, CounterWeb.Endpoint, + url: [host: "localhost"], + render_errors: [ + formats: [html: CounterWeb.ErrorHTML, json: CounterWeb.ErrorJSON], + layout: false + ], + pubsub_server: Counter.PubSub, + live_view: [signing_salt: "DB1nH+Sn"] + +# Configures the mailer +# +# By default it uses the "Local" adapter which stores the emails +# locally. You can see the emails in your browser, at "/dev/mailbox". +# +# For production it's recommended to configure a different adapter +# at the `config/runtime.exs`. +config :counter, Counter.Mailer, adapter: Swoosh.Adapters.Local + +# Configure esbuild (the version is required) +config :esbuild, + version: "0.14.41", + default: [ + args: + ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), + cd: Path.expand("../assets", __DIR__), + env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} + ] + +# Configure tailwind (the version is required) +config :tailwind, + version: "3.2.4", + default: [ + args: ~w( + --config=tailwind.config.js + --input=css/app.css + --output=../priv/static/assets/app.css + ), + cd: Path.expand("../assets", __DIR__) + ] + +# Configures Elixir's Logger +config :logger, :console, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id] + +# Use Jason for JSON parsing in Phoenix +config :phoenix, :json_library, Jason + +# Import environment specific config. This must remain at the bottom +# of this file so it overrides the configuration defined above. +import_config "#{config_env()}.exs" diff --git a/phoenix-1.7/counter/config/dev.exs b/phoenix-1.7/counter/config/dev.exs new file mode 100644 index 000000000..3768bba41 --- /dev/null +++ b/phoenix-1.7/counter/config/dev.exs @@ -0,0 +1,69 @@ +import Config + +# For development, we disable any cache and enable +# debugging and code reloading. +# +# The watchers configuration can be used to run external +# watchers to your application. For example, we use it +# with esbuild to bundle .js and .css sources. +config :counter, CounterWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. + # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. + http: [ip: {127, 0, 0, 1}, port: 4000], + check_origin: false, + code_reloader: true, + debug_errors: true, + secret_key_base: "KmPkbfiVqpsyJHpm+RlNHgX85D1Fhj5vXUpdASRh2JBWNcQDWa7h8Fb6ft59rCW8", + watchers: [ + esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}, + tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]} + ] + +# ## SSL Support +# +# In order to use HTTPS in development, a self-signed +# certificate can be generated by running the following +# Mix task: +# +# mix phx.gen.cert +# +# Run `mix help phx.gen.cert` for more information. +# +# The `http:` config above can be replaced with: +# +# https: [ +# port: 4001, +# cipher_suite: :strong, +# keyfile: "priv/cert/selfsigned_key.pem", +# certfile: "priv/cert/selfsigned.pem" +# ], +# +# If desired, both `http:` and `https:` keys can be +# configured to run both http and https servers on +# different ports. + +# Watch static and templates for browser reloading. +config :counter, CounterWeb.Endpoint, + live_reload: [ + patterns: [ + ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", + ~r"priv/gettext/.*(po)$", + ~r"lib/counter_web/(controllers|live|components)/.*(ex|heex)$" + ] + ] + +# Enable dev routes for dashboard and mailbox +config :counter, dev_routes: true + +# Do not include metadata nor timestamps in development logs +config :logger, :console, format: "[$level] $message\n" + +# Set a higher stacktrace during development. Avoid configuring such +# in production as building large stacktraces may be expensive. +config :phoenix, :stacktrace_depth, 20 + +# Initialize plugs at runtime for faster development compilation +config :phoenix, :plug_init_mode, :runtime + +# Disable swoosh api client as it is only required for production adapters. +config :swoosh, :api_client, false diff --git a/phoenix-1.7/counter/config/prod.exs b/phoenix-1.7/counter/config/prod.exs new file mode 100644 index 000000000..a713ea1be --- /dev/null +++ b/phoenix-1.7/counter/config/prod.exs @@ -0,0 +1,21 @@ +import Config + +# For production, don't forget to configure the url host +# to something meaningful, Phoenix uses this information +# when generating URLs. + +# Note we also include the path to a cache manifest +# containing the digested version of static files. This +# manifest is generated by the `mix phx.digest` task, +# which you should run after static files are built and +# before starting your production server. +config :counter, CounterWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" + +# Configures Swoosh API Client +config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: Counter.Finch + +# Do not print debug messages in production +config :logger, level: :info + +# Runtime production configuration, including reading +# of environment variables, is done on config/runtime.exs. diff --git a/phoenix-1.7/counter/config/runtime.exs b/phoenix-1.7/counter/config/runtime.exs new file mode 100644 index 000000000..dcd5a8f93 --- /dev/null +++ b/phoenix-1.7/counter/config/runtime.exs @@ -0,0 +1,100 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/counter start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :counter, CounterWeb.Endpoint, server: true +end + +if config_env() == :prod do + # The secret key base is used to sign/encrypt cookies and other secrets. + # A default value is used in config/dev.exs and config/test.exs but you + # want to use a different value for prod and you most likely don't want + # to check this value into version control, so we use an environment + # variable instead. + secret_key_base = + System.get_env("SECRET_KEY_BASE") || + raise """ + environment variable SECRET_KEY_BASE is missing. + You can generate one by calling: mix phx.gen.secret + """ + + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + + config :counter, CounterWeb.Endpoint, + url: [host: host, port: 443, scheme: "https"], + http: [ + # Enable IPv6 and bind on all interfaces. + # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. + # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html + # for details about using IPv6 vs IPv4 and loopback vs public addresses. + ip: {0, 0, 0, 0, 0, 0, 0, 0}, + port: port + ], + secret_key_base: secret_key_base + + # ## SSL Support + # + # To get SSL working, you will need to add the `https` key + # to your endpoint configuration: + # + # config :counter, CounterWeb.Endpoint, + # https: [ + # ..., + # port: 443, + # cipher_suite: :strong, + # keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), + # certfile: System.get_env("SOME_APP_SSL_CERT_PATH") + # ] + # + # The `cipher_suite` is set to `:strong` to support only the + # latest and more secure SSL ciphers. This means old browsers + # and clients may not be supported. You can set it to + # `:compatible` for wider support. + # + # `:keyfile` and `:certfile` expect an absolute path to the key + # and cert in disk or a relative path inside priv, for example + # "priv/ssl/server.key". For all supported SSL configuration + # options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 + # + # We also recommend setting `force_ssl` in your endpoint, ensuring + # no data is ever sent via http, always redirecting to https: + # + # config :counter, CounterWeb.Endpoint, + # force_ssl: [hsts: true] + # + # Check `Plug.SSL` for all available options in `force_ssl`. + + # ## Configuring the mailer + # + # In production you need to configure the mailer to use a different adapter. + # Also, you may need to configure the Swoosh API client of your choice if you + # are not using SMTP. Here is an example of the configuration: + # + # config :counter, Counter.Mailer, + # adapter: Swoosh.Adapters.Mailgun, + # api_key: System.get_env("MAILGUN_API_KEY"), + # domain: System.get_env("MAILGUN_DOMAIN") + # + # For this example you need include a HTTP client required by Swoosh API client. + # Swoosh supports Hackney and Finch out of the box: + # + # config :swoosh, :api_client, Swoosh.ApiClient.Hackney + # + # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details. +end diff --git a/phoenix-1.7/counter/config/test.exs b/phoenix-1.7/counter/config/test.exs new file mode 100644 index 000000000..412f6fd6e --- /dev/null +++ b/phoenix-1.7/counter/config/test.exs @@ -0,0 +1,21 @@ +import Config + +# We don't run a server during test. If one is required, +# you can enable the server option below. +config :counter, CounterWeb.Endpoint, + http: [ip: {127, 0, 0, 1}, port: 4002], + secret_key_base: "C0EAAkvHuDfPxDguT8F8Ck8IQLBBSuOhu1hyJ1KPxapR+obidRpl5fxMqJFWusvA", + server: false + +# In test we don't send emails. +config :counter, Counter.Mailer, + adapter: Swoosh.Adapters.Test + +# Disable swoosh api client as it is only required for production adapters. +config :swoosh, :api_client, false + +# Print only warnings and errors during test +config :logger, level: :warning + +# Initialize plugs at runtime for faster test compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/phoenix-1.7/counter/lib/counter.ex b/phoenix-1.7/counter/lib/counter.ex new file mode 100644 index 000000000..bf4261567 --- /dev/null +++ b/phoenix-1.7/counter/lib/counter.ex @@ -0,0 +1,9 @@ +defmodule Counter do + @moduledoc """ + Counter keeps the contexts that define your domain + and business logic. + + Contexts are also responsible for managing your data, regardless + if it comes from the database, an external API or others. + """ +end diff --git a/phoenix-1.7/counter/lib/counter/application.ex b/phoenix-1.7/counter/lib/counter/application.ex new file mode 100644 index 000000000..7e6b37691 --- /dev/null +++ b/phoenix-1.7/counter/lib/counter/application.ex @@ -0,0 +1,36 @@ +defmodule Counter.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + children = [ + # Start the Telemetry supervisor + CounterWeb.Telemetry, + # Start the PubSub system + {Phoenix.PubSub, name: Counter.PubSub}, + # Start Finch + {Finch, name: Counter.Finch}, + # Start the Endpoint (http/https) + CounterWeb.Endpoint + # Start a worker by calling: Counter.Worker.start_link(arg) + # {Counter.Worker, arg} + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: Counter.Supervisor] + Supervisor.start_link(children, opts) + end + + # Tell Phoenix to update the endpoint configuration + # whenever the application is updated. + @impl true + def config_change(changed, _new, removed) do + CounterWeb.Endpoint.config_change(changed, removed) + :ok + end +end diff --git a/phoenix-1.7/counter/lib/counter/mailer.ex b/phoenix-1.7/counter/lib/counter/mailer.ex new file mode 100644 index 000000000..fa6f9cda4 --- /dev/null +++ b/phoenix-1.7/counter/lib/counter/mailer.ex @@ -0,0 +1,3 @@ +defmodule Counter.Mailer do + use Swoosh.Mailer, otp_app: :counter +end diff --git a/phoenix-1.7/counter/lib/counter_web.ex b/phoenix-1.7/counter/lib/counter_web.ex new file mode 100644 index 000000000..2f231711e --- /dev/null +++ b/phoenix-1.7/counter/lib/counter_web.ex @@ -0,0 +1,113 @@ +defmodule CounterWeb do + @moduledoc """ + The entrypoint for defining your web interface, such + as controllers, components, channels, and so on. + + This can be used in your application as: + + use CounterWeb, :controller + use CounterWeb, :html + + The definitions below will be executed for every controller, + component, etc, so keep them short and clean, focused + on imports, uses and aliases. + + Do NOT define functions inside the quoted expressions + below. Instead, define additional modules and import + those modules here. + """ + + def static_paths, do: ~w(assets fonts images favicon.ico robots.txt) + + def router do + quote do + use Phoenix.Router, helpers: false + + # Import common connection and controller functions to use in pipelines + import Plug.Conn + import Phoenix.Controller + import Phoenix.LiveView.Router + end + end + + def channel do + quote do + use Phoenix.Channel + end + end + + def controller do + quote do + use Phoenix.Controller, + formats: [:html, :json], + layouts: [html: CounterWeb.Layouts] + + import Plug.Conn + import CounterWeb.Gettext + + unquote(verified_routes()) + end + end + + def live_view do + quote do + use Phoenix.LiveView, + layout: {CounterWeb.Layouts, :app} + + unquote(html_helpers()) + end + end + + def live_component do + quote do + use Phoenix.LiveComponent + + unquote(html_helpers()) + end + end + + def html do + quote do + use Phoenix.Component + + # Import convenience functions from controllers + import Phoenix.Controller, + only: [get_csrf_token: 0, view_module: 1, view_template: 1] + + # Include general helpers for rendering HTML + unquote(html_helpers()) + end + end + + defp html_helpers do + quote do + # HTML escaping functionality + import Phoenix.HTML + # Core UI components and translation + import CounterWeb.CoreComponents + import CounterWeb.Gettext + + # Shortcut for generating JS commands + alias Phoenix.LiveView.JS + + # Routes generation with the ~p sigil + unquote(verified_routes()) + end + end + + def verified_routes do + quote do + use Phoenix.VerifiedRoutes, + endpoint: CounterWeb.Endpoint, + router: CounterWeb.Router, + statics: CounterWeb.static_paths() + end + end + + @doc """ + When used, dispatch to the appropriate controller/view/etc. + """ + defmacro __using__(which) when is_atom(which) do + apply(__MODULE__, which, []) + end +end diff --git a/phoenix-1.7/counter/lib/counter_web/components/core_components.ex b/phoenix-1.7/counter/lib/counter_web/components/core_components.ex new file mode 100644 index 000000000..1d9ef1466 --- /dev/null +++ b/phoenix-1.7/counter/lib/counter_web/components/core_components.ex @@ -0,0 +1,689 @@ +defmodule CounterWeb.CoreComponents do + @moduledoc """ + Provides core UI components. + + The components in this module use Tailwind CSS, a utility-first CSS framework. + See the [Tailwind CSS documentation](https://tailwindcss.com) to learn how to + customize the generated components in this module. + + Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage. + """ + use Phoenix.Component + + alias Phoenix.LiveView.JS + import CounterWeb.Gettext + + @doc """ + Renders a modal. + + ## Examples + + <.modal id="confirm-modal"> + Are you sure? + <:confirm>OK + <:cancel>Cancel + + + JS commands may be passed to the `:on_cancel` and `on_confirm` attributes + for the caller to react to each button press, for example: + + <.modal id="confirm" on_confirm={JS.push("delete")} on_cancel={JS.navigate(~p"/posts")}> + Are you sure you? + <:confirm>OK + <:cancel>Cancel + + """ + attr :id, :string, required: true + attr :show, :boolean, default: false + attr :on_cancel, JS, default: %JS{} + attr :on_confirm, JS, default: %JS{} + + slot :inner_block, required: true + slot :title + slot :subtitle + slot :confirm + slot :cancel + + def modal(assigns) do + ~H""" +