├── .gitgnore ├── binaries_example ├── test │ ├── test_helper.exs │ └── java_test.exs ├── .gitignore ├── java ├── Bar.class ├── Foo.class ├── Hello.class ├── build │ ├── Bar.class │ ├── Foo.class │ └── Hello.class ├── Foo.java ├── src │ ├── Foo.java │ ├── Bar.java │ └── Hello.java ├── Bar.java ├── Hello.java ├── README.md ├── mix.exs ├── config │ └── config.exs └── lib │ └── java.ex ├── Hello.class ├── publishing.md ├── 2_08_channels.md ├── otp.md ├── documentation.md ├── releases.md ├── supervision.md ├── mix.md ├── links_and_monitors.md ├── otp_app.md ├── macros.md ├── testing.md ├── nodes.md ├── processes.md ├── 2_07_phoenix.md ├── binaries.md ├── README.md ├── data_types.md ├── cats.exs ├── pattern_matching.md ├── control_flow.md ├── pipe_operator.md ├── modules_and_functions.md ├── tasks_and_agents.md ├── functional_programming.md └── java.ex /.gitgnore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /binaries_example/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /binaries_example/.gitignore: -------------------------------------------------------------------------------- 1 | /_build 2 | /deps 3 | erl_crash.dump 4 | *.ez 5 | -------------------------------------------------------------------------------- /Hello.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/Hello.class -------------------------------------------------------------------------------- /binaries_example/java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/binaries_example/java -------------------------------------------------------------------------------- /publishing.md: -------------------------------------------------------------------------------- 1 | ## Publishing a library exercises 2 | 3 | * Create a new mix project. Publish it is hex.pm. 4 | -------------------------------------------------------------------------------- /binaries_example/Bar.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/binaries_example/Bar.class -------------------------------------------------------------------------------- /binaries_example/Foo.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/binaries_example/Foo.class -------------------------------------------------------------------------------- /binaries_example/Hello.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/binaries_example/Hello.class -------------------------------------------------------------------------------- /binaries_example/build/Bar.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/binaries_example/build/Bar.class -------------------------------------------------------------------------------- /binaries_example/build/Foo.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/binaries_example/build/Foo.class -------------------------------------------------------------------------------- /binaries_example/build/Hello.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobenian/elixir-mastery-exercises/HEAD/binaries_example/build/Hello.class -------------------------------------------------------------------------------- /binaries_example/Foo.java: -------------------------------------------------------------------------------- 1 | public class Foo { 2 | public void foo() { 3 | System.out.println("Here we are in foo... just chillin'"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /binaries_example/test/java_test.exs: -------------------------------------------------------------------------------- 1 | defmodule JavaTest do 2 | use ExUnit.Case 3 | 4 | test "the truth" do 5 | assert 1 + 1 == 2 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /binaries_example/src/Foo.java: -------------------------------------------------------------------------------- 1 | public class Foo { 2 | public void foo() { 3 | System.out.println("Here we are in foo... just chillin'"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /2_08_channels.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | Modify the leaderboard Phoenix app to update the top 25 scores as new ones are 4 | added. Use channels to get the soft real time updates. 5 | -------------------------------------------------------------------------------- /binaries_example/Bar.java: -------------------------------------------------------------------------------- 1 | public class Bar extends Foo { 2 | public void foo() { 3 | super.foo(); 4 | System.out.println("You've been hacked and you had no idea..."); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /binaries_example/src/Bar.java: -------------------------------------------------------------------------------- 1 | public class Bar extends Foo { 2 | public void foo() { 3 | super.foo(); 4 | System.out.println("You've been hacked and you had no idea..."); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /binaries_example/Hello.java: -------------------------------------------------------------------------------- 1 | public class Hello { 2 | public static void main(String[] args) { 3 | System.out.println("hey, let's call foo"); 4 | Foo f = new Foo(); 5 | f.foo(); 6 | System.out.println("all done."); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /binaries_example/src/Hello.java: -------------------------------------------------------------------------------- 1 | public class Hello { 2 | public static void main(String[] args) { 3 | System.out.println("hey, let's call foo"); 4 | Foo f = new Foo(); 5 | f.foo(); 6 | System.out.println("all done."); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /otp.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 2 | * Make an OTP Catstore GenServer that starts with a call to new_store 3 | * Implement add/remove/list/close 4 | * Note: this is mysteriously like the examples in the slides 5 | [Answer](https://gist.github.com/MonkeyIsNull/4ceaa2f72e2f9c9c177e) 6 | 7 | -------------------------------------------------------------------------------- /binaries_example/README.md: -------------------------------------------------------------------------------- 1 | Java 2 | ==== 3 | 4 | We're going to parse a Java class file, yeah! 5 | 6 | * cp build/Hello.class Hello.class 7 | * mix escript.build 8 | * java -cp . Hello 9 | * ./java Hello.class 10 | * java -cp . Hello 11 | * cmp -bl Hello.class build/Hello.class 12 | -------------------------------------------------------------------------------- /documentation.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | * Create a new mix project and add module documentation to it. Generate the html files. 4 | 5 | ## Exercise 2 6 | 7 | * Add function documentation to the mix project and generate the updated html files 8 | 9 | [Answer](https://gist.github.com/brweber2/9c888641bdb4892cf4c65683164ef527) 10 | -------------------------------------------------------------------------------- /releases.md: -------------------------------------------------------------------------------- 1 | ## Releases exercises 2 | 3 | * Generate a new mix project. Create a relelease for the project. Install it and run it. 4 | 5 | ### Advanced 6 | 7 | * Upgrade your release to a new version without stopping the running process. 8 | 9 | [Answer](https://gist.github.com/brweber2/f49330dffb49476dd4bd30d253b86fce) 10 | -------------------------------------------------------------------------------- /supervision.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 2 | * Get the [DroidStore Supervisor branch](https://github.com/MonkeyIsNull/DroidStore/tree/sup) up and running inside iex 3 | * Crash a process and check for restarts, check the contents of the stores 4 | * Launch :observer.start and check the links section of :hoth, :mose etc and their supervisors ( I am lying - you cannot do this!) 5 | -------------------------------------------------------------------------------- /mix.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | * Create a new mix project called 'redpull' 4 | 5 | ## Exercise 2 6 | 7 | * Compile the project and identify the files that were created 8 | 9 | ## Exercise 3 10 | 11 | * Run the tests. What does the dot mean? 12 | 13 | ## Exercise 4 14 | 15 | * Make your own Hello World mix task 16 | 17 | ## Exercise 5 (BONUS) 18 | 19 | * Build an escript and run it 20 | -------------------------------------------------------------------------------- /links_and_monitors.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | Monitor the process you created in the previous exercise and restart it if it 4 | crashes. It is ok to call the function that detects the crash and restarts the 5 | process yourself. Explore and try different things in iex. 6 | 7 | Send it some messages, make it crash and verify that it restarts and accepts 8 | messages again. 9 | 10 | [Answer](https://gist.github.com/brweber2/ac0a42d667210451b65231a151ee1ebc) 11 | -------------------------------------------------------------------------------- /otp_app.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | * Create a default app and get it to start/stop. Try some of the run options 3 | 4 | * You have all the knowledge to turn the [Supervised branch](https://github.com/MonkeyIsNull/DroidStore/tree/sup) of the DroidStore 5 | into an OTP app. Start it up with iex -S mix 6 | [Answer](https://github.com/MonkeyIsNull/DroidStore/tree/app) 7 | 8 | * Run :observer.start() and find the application. Kill a supervisor and 9 | watch what happens 10 | -------------------------------------------------------------------------------- /macros.md: -------------------------------------------------------------------------------- 1 | ## Macros exercise 2 | 3 | * Write a macro that wraps an expression in a try block. Have it return the result of the expression 4 | if the expression does not raise an error. Have the macro take a second argument that is a default value. 5 | The macro should log a warning and return the default value if an error is raised. The default value must not be evaluated if the expression does not raise an error. 6 | 7 | [Answer](https://gist.github.com/brweber2/fcfbf34526884a88f2e9e6b24178b147) 8 | -------------------------------------------------------------------------------- /testing.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 2 | 3 | * Write a FAILING test, make sure that it fails and you see *red* 4 | 5 | # Exercise 1.1 6 | 7 | * Write a PASSING test, make sure that passes and you seen *green* 8 | 9 | # Exercise 2 10 | 11 | * Write tests for map, reduce, filter 12 | Answers: 13 | [answers](https://github.com/MonkeyIsNull/fp/blob/master/test/fp_test.exs) 14 | 15 | # Bonus Exerise 16 | 17 | * Without looking at the slides, write a doctest 18 | Answer: use the force, I mean slides. 19 | 20 | 21 | -------------------------------------------------------------------------------- /nodes.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | * Clone the [Hub repo](https://github.com/MonkeyIsNull/hub/tree/master) and run the examples from the slide, ensure you understand how it works 4 | 5 | ## Exercise 2 6 | 7 | * Modify the Hub project and create a chat function that can send directly to a client. 8 | It doesn't go through the hub. The other client should be 9 | able to receive it and see the response. For example: 10 | ```iex(r2d2@panda)2> Client.chat("ig88", "imperial scum!")``` 11 | and on ig88s side, it would display 12 | ```[r2d2@panda] imperial scum!!``` 13 | 14 | * Instead of showing the pid number when a client connects 15 | have every connected client see the registered name of the client 16 | 17 | * [Answer](https://github.com/MonkeyIsNull/hub/tree/answer) 18 | -------------------------------------------------------------------------------- /processes.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | Run `elixir cats.exs` to make a directory structure that looks like this: 4 | 5 | ``` 6 | cats/virginia/felix.cat 7 | cats/virginia/angel.cat 8 | cats/virginia/midnight.cat 9 | cats/maryland/pepper.cat 10 | cats/maryland/oreo.cat 11 | cats/dc/tiger.cat 12 | cats/dc/garfield.cat 13 | cats/dc/misty.cat 14 | ``` 15 | 16 | 17 | Start a process that looks for "cats" (Cats are files...) in a 18 | "state" (States are directories). 19 | 20 | Whenever a message arrives looking for a cat, return the content of the file 21 | matching the name of the cat. Send it a message with a valid cat name. Send 22 | it a message with an invalid cat name. 23 | 24 | Assume the file exists and let it "crash" if it does not. 25 | 26 | [Answer](https://gist.github.com/brweber2/56e9a991b023f8b46518e6389b79ce44) 27 | -------------------------------------------------------------------------------- /2_07_phoenix.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | Create a new phoenix project called 'leaderboard'. 4 | 5 | ## Exercise 2 6 | 7 | ```text 8 | It helps to have Postgres installed. If you don't want to install it, you may 9 | want to pair with someone else for this exercise. 10 | 11 | If you are on a Mac, you can install Postgres very simply with http://postgresapp.com. 12 | 13 | If you are on the latest version of Ubuntu you will have Postgres installed already. 14 | ``` 15 | 16 | Create an HTML page that will display the scores of a video game. 17 | 18 | Allow users to enter their video game scores. 19 | 20 | Do NOT worry about authenticating the users. Anyone can enter a score for any 21 | initials. 22 | 23 | The 'model' should have these pieces of data: 24 | 25 | * Video game 26 | * Player initials 27 | * Date of the score 28 | * Score 29 | -------------------------------------------------------------------------------- /binaries.md: -------------------------------------------------------------------------------- 1 | ## Exercise 1 2 | 3 | Read the magic word (0b110010101111111010111010101) from a Java class file. 4 | Then read the minor version (2 bytes) and the major version (2 bytes). 5 | 6 | You will find a class file in the [binaries_example](binaries_example) directory. 7 | 8 | Figure out which version of Java is being used based on the following table: 9 | 10 | ```text 11 | major version number of the class file format being used. 12 | J2SE 8 = 52 (0x34 hex), 13 | J2SE 7 = 51 (0x33 hex), 14 | J2SE 6.0 = 50 (0x32 hex), 15 | J2SE 5.0 = 49 (0x31 hex), 16 | JDK 1.4 = 48 (0x30 hex), 17 | JDK 1.3 = 47 (0x2F hex), 18 | JDK 1.2 = 46 (0x2E hex), 19 | JDK 1.1 = 45 (0x2D hex). 20 | ``` 21 | 22 | [Answer](https://gist.github.com/brweber2/14a3c847650f60fffa9a26784fa0a643) 23 | 24 | ## Exercise 2 (BONUS) 25 | 26 | Read [binaries_example/lib/java.ex](binaries_example/lib/java.ex) and figure out what it does. 27 | -------------------------------------------------------------------------------- /binaries_example/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Java.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [app: :java, 6 | version: "0.0.1", 7 | elixir: "~> 1.0", 8 | build_embedded: Mix.env == :prod, 9 | start_permanent: Mix.env == :prod, 10 | escript: escript, 11 | deps: deps] 12 | end 13 | 14 | def escript do 15 | [main_module: Java] 16 | end 17 | 18 | # Configuration for the OTP application 19 | # 20 | # Type `mix help compile.app` for more information 21 | def application do 22 | [applications: [:logger]] 23 | end 24 | 25 | # Dependencies can be Hex packages: 26 | # 27 | # {:mydep, "~> 0.3.0"} 28 | # 29 | # Or git/path repositories: 30 | # 31 | # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"} 32 | # 33 | # Type `mix help deps` for more examples and options 34 | defp deps do 35 | [] 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elixir-mastery-questions 2 | 3 | Updated for Fall 2016 4 | 5 | ## Day 1 6 | 7 | * [Data Types](data_types.md) 8 | * [Control Flow](control_flow.md) 9 | * [Functional Programming](functional_programming.md) 10 | * [Pattern Matching](pattern_matching.md) 11 | * [Modules and Functions](modules_and_functions.md) 12 | * [Pipe Operator](pipe_operator.md) 13 | * [Mix](mix.md) 14 | * [Testing](testing.md) 15 | * [Publishing](publishing.md) 16 | * [Documentaiton](documentation.md) 17 | * [Releases](releases.md) 18 | 19 | 20 | ## Day 2 21 | 22 | * [Binaries](binaries.md) 23 | * [Macros](macros.md) 24 | * [Processes](processes.md) 25 | * [Links and Monitors](links_and_monitors.md) 26 | * [Tasks and Agents](tasks_and_agents.md) 27 | * [Nodes](nodes.md) 28 | * [OTP](otp.md) 29 | * [Supervisors](supervision.md) 30 | * [OTP Applications](otp_app.md) 31 | 32 | 33 | ## Day 3 34 | 35 | * [Phoenix](phoenix.md) 36 | * [Channels](channels.md) 37 | -------------------------------------------------------------------------------- /binaries_example/config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | use Mix.Config 4 | 5 | # This configuration is loaded before any dependency and is restricted 6 | # to this project. If another project depends on this project, this 7 | # file won't be loaded nor affect the parent project. For this reason, 8 | # if you want to provide default values for your application for third- 9 | # party users, it should be done in your mix.exs file. 10 | 11 | # Sample configuration: 12 | # 13 | # config :logger, :console, 14 | # level: :info, 15 | # format: "$date $time [$level] $metadata$message\n", 16 | # metadata: [:user_id] 17 | 18 | # It is also possible to import configuration files, relative to this 19 | # directory. For example, you can emulate configuration per environment 20 | # by uncommenting the line below and defining dev.exs, test.exs and such. 21 | # Configuration from the imported file will override the ones defined 22 | # here (which is why it is important to import them last). 23 | # 24 | # import_config "#{Mix.env}.exs" 25 | -------------------------------------------------------------------------------- /data_types.md: -------------------------------------------------------------------------------- 1 | ## Reading Excercises 2 | * Spend some time in iex looking at the functions for 3 | Map, List, Keyword. For example, type in Map and then ```.``` 4 | and then hit tab. Read the doc for some eg: ```h List.delete``` 5 | 6 | ## List Exercises 7 | * Create a list with six star wars characters 8 | * Get the third item out of the list 9 | * Create another list with three characters 10 | * bonus, make them atoms and at least one a tuple of atoms 11 | * Create a third list that contains both previous lists 12 | * Delete the seventh character 13 | * Add one more character to the list 14 | * use 'in' to check that a character exists 15 | 16 | ## Map exercises 17 | * Create a map with at least two key/value pairs. 18 | Some suggested ones are :name, :side. 19 | alliance should be :rebel or :imperial 20 | * Print out the name and the side values 21 | * Add a weight to each character 22 | * Update the alliance to its opposite 23 | * Create a LOM: list of maps of three characters 24 | * Update or replace the second item in the list with 25 | 'Jabba the Hutt' and :scum or :criminal as the side 26 | 27 | * [Answers](https://gist.github.com/MonkeyIsNull/8b26a6a05ba0d54b13cf) 28 | 29 | -------------------------------------------------------------------------------- /cats.exs: -------------------------------------------------------------------------------- 1 | defmodule Cats do 2 | 3 | @prefix "/tmp" 4 | 5 | def make do 6 | cats |> mk 7 | end 8 | 9 | def cats do 10 | 11 | [ 12 | [state: "Virginia", 13 | cats: [[name: "Felix", age: 7], 14 | [name: "Angel", age: 1], 15 | [name: "Midnight", age: 9]]], 16 | [state: "Maryland", 17 | cats: [[name: "Pepper", age: 4], 18 | [name: "Oreo", age: 6]]], 19 | [state: "DC", 20 | cats: [[name: "Tiger", age: 3], 21 | [name: "Garfield", age: 3], 22 | [name: "Misty", age: 8]]], 23 | ] 24 | end 25 | 26 | def mk_state(state) do 27 | [@prefix, "cats", String.downcase(state)] |> Path.join |> File.mkdir_p! 28 | end 29 | 30 | def mk_cat(state, cat = [name: name, age: _age]) do 31 | [@prefix, "cats", String.downcase(state), String.downcase(name) <> ".cat"] 32 | |> Path.join 33 | |> File.write!(Macro.to_string(cat) <> "\n") 34 | end 35 | 36 | def mk([]) do 37 | # all done 38 | end 39 | 40 | def mk([[state: state, cats: cats] | t]) do 41 | state |> mk_state 42 | cats |> Enum.map(&(mk_cat(state, &1))) 43 | mk(t) 44 | end 45 | 46 | end 47 | 48 | Cats.make 49 | -------------------------------------------------------------------------------- /pattern_matching.md: -------------------------------------------------------------------------------- 1 | # use the following data to answer the questions in this section 2 | 3 | ```elixir 4 | characters = [ 5 | %{name: "Han", type: :human, rebel: true, weight: 185}, 6 | %{name: "Jabba", type: :hutt, rebel: false, weight: 2200}, 7 | %{name: "Chewie", type: :wookie, rebel: true, weight: 350}, 8 | %{name: "r2d2", type: :droid, rebel: true, weight: 250}, 9 | %{name: "Luke", type: :human, rebel: true, weight: 140}, 10 | %{name: "Boba Fett", type: :human, rebel: false, weight: 175}, 11 | ] 12 | 13 | ``` 14 | 15 | > Note that there is more than one correct answer for all of these! 16 | 17 | ## Exercise 1 18 | 19 | * In one line of code, set a variable called wookie_name to the name of the wookie character 20 | 21 | ## Exercise 2 22 | 23 | * In one line of code, set a variable called 'weight' to how much Han weighs 24 | 25 | > Advanced (we haven't covered all of this yet, you'll likely need to read documentation) 26 | 27 | ## Exercise 3 28 | 29 | * In one line of code, create a list of the names of the humans 30 | 31 | ## Exercise 4 32 | 33 | * In one line of code, create a list of all the humans that weigh less than 180 lbs. 34 | 35 | [Answer](https://gist.github.com/brweber2/340a2f53c00a7d38c527313c0642398a) 36 | -------------------------------------------------------------------------------- /control_flow.md: -------------------------------------------------------------------------------- 1 | ## Conditional Exercises 2 | 3 | * Create a variable has_seen_star_wars and set it to true. 4 | * Write code that prints "Ready for class" if you have seen at least one Star Wars movie (has_seen_star_wars). 5 | * Flip has_seen_star_wars to false. 6 | * Write code that prints "Ready for class" if you have seen at least one Star Wars movie (has_seen_star_wars). Otherwise print "Not ready". 7 | * Set the variable i_am_a_fan based on the if expression. 8 | * Set the variable inside the if expression. What happens? Why? 9 | * Set the variable to the return value of the if expression. What happens? Why? 10 | 11 | ## Case Exercises 12 | 13 | * Do the same exercise, but replace 'if' with 'case'. 14 | * Do the same exercise, but replace 'if' with 'cond'. 15 | 16 | ## Errors 17 | 18 | * Write a function that will raise an error depending on the inputs. 19 | * Call the function and trigger the error. 20 | * Call the function and do not trigger the error. 21 | * Add error handling to the function so it does not fail if an error occurs. 22 | * Write a function that always prints out "Star Wars is awesome" even if it raises an error. 23 | * Write a function that raises an error, handles it and logs the stacktrace in a friendly manner. 24 | 25 | [Answer](https://gist.github.com/brweber2/26c834effd8c3c17e19c2009381db514) 26 | -------------------------------------------------------------------------------- /pipe_operator.md: -------------------------------------------------------------------------------- 1 | # Use this code and data to answer the questions. 2 | 3 | ```elixir 4 | defmodule Millenium.Falcon do 5 | def rebel?(c = %{rebel: true}) do 6 | c.type != :droid 7 | end 8 | 9 | def rebel?(_), do: false 10 | 11 | def fill_ship(characters) do 12 | characters 13 | |> Enum.map(&(&1.name)) 14 | |> Enum.join(",") 15 | end 16 | end 17 | 18 | characters = [ 19 | %{name: "Han", type: :human, rebel: true, weight: 185}, 20 | %{name: "Jabba", type: :hutt, rebel: false, weight: 2200}, 21 | %{name: "Chewie", type: :wookie, rebel: true, weight: 350}, 22 | %{name: "r2d2", type: :droid, rebel: true, weight: 250}, 23 | %{name: "Luke", type: :human, rebel: true, weight: 140}, 24 | %{name: "Boba Fett", type: :human, rebel: false, weight: 175}, 25 | ] 26 | 27 | ``` 28 | 29 | ## Exercise 1 30 | 31 | * Create a list of all the rebel scum 32 | 33 | ## Exercise 2 34 | 35 | * Fill the Millenium Falcon with all the rebels 36 | 37 | ## Exercise 3 38 | 39 | * How much do all the humans weigh? 40 | 41 | ## Exercise 4 (BONUS) 42 | 43 | * If the Millenium Falcon can hold 1000 pounds, what is the optimal set of characters that can fit on the ship without going over the weight limit? 44 | 45 | 46 | [Answer](https://gist.github.com/brweber2/5d594842ac81d55d92ee6b44510bfc45) 47 | -------------------------------------------------------------------------------- /modules_and_functions.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 2 | * Write a function in a module that takes a map with :name and prints out the value 3 | with a "-NG" appended to it since it's the NextGeneration ;) -- 4 | Ensure it takes only maps that contain the :droid atom which is true 5 | 6 | * Write another function (with the same name) with the (almost) same arguments that takes any name and returns it 7 | if the :droid value is false 8 | 9 | * [Answer](https://gist.github.com/MonkeyIsNull/02b43cd673a228d57fc0) 10 | 11 | # Exercise 2 12 | * Write an & function using &1.... and sums 4 values 13 | * [Answer](https://gist.github.com/MonkeyIsNull/f1c12df84de6e5156237) 14 | 15 | # Exercise 3 16 | * Write an function called greeter that returns a function that takes differing types and values and prints out 17 | a different response to each. Try a map, a three element tuple, an :atom and a string. 18 | It should also take a fallthrough default value that returns :ok 19 | * [Answer](https://gist.github.com/MonkeyIsNull/37368f35d6cfa35d1919) 20 | 21 | # Exercise 4 22 | * read up on _Enum.reduce_. Inside of iex How can you combine Enum.map and Enum.reduce to 23 | take a list of numbers, double each of them and then sum them up. 24 | Try the numbers 1,2,3,4 - that way you'll know the answer (20) and if you got it correct 25 | * [Answer](https://gist.github.com/MonkeyIsNull/738e0ae9114416ed1f11) 26 | -------------------------------------------------------------------------------- /tasks_and_agents.md: -------------------------------------------------------------------------------- 1 | # Task Exercise 2 | ## Exercise 3 | * Create your own sleep function that can sleep for n secs. Don't forget to wait longer than that. 4 | Have it return it's own pid or :ok 5 | * [Answer](https://gist.github.com/MonkeyIsNull/7deb099da777178068e0) 6 | 7 | ## Exercise 8 | * Create 5 files /tmp/t1 /tmp/t2 /tmp/t3 /tmp/t4 /tmp/5. Put something in each file. 9 | Write a program that launches 5 different tasks, each one takes a function that reads 10 | one of the numbered files. You might need to use the format Task.async(mod,fun,args) 11 | Hint: recursion or map would be helpful 12 | * [Answer](https://gist.github.com/MonkeyIsNull/3cb5afcb8cfe00c63f5c) 13 | 14 | 15 | # Agent Exercise 16 | ## Exercises 17 | * Create a cat store. Start the store with a default cat in it. 18 | * Create a function that adds a cat 19 | * Create a function that shows a cat 20 | * Create a function that removes a cat 21 | * [Answer](https://gist.github.com/MonkeyIsNull/d70bf3cc15cfea961e2a) 22 | 23 | ## Bonus Exercise 24 | * Implement finding a cat by name 25 | * [Answer](https://gist.github.com/MonkeyIsNull/afd0c270da25a31c822f65646cdfc1e3) 26 | 27 | ## Bonus Number 2 Exercise (only AFTER you have done the Agent exercises) 28 | * Using the same template for the Task program above, grab the lib [reddhl](https://hex.pm/packages/reddhl) 29 | Launch 5 different Tasks, await their output and dump it. 30 | Hint: Not too unlike previous exercise 31 | * [Answer](https://gist.github.com/MonkeyIsNull/13aec9eac86489db15f2) 32 | 33 | ## Reference: Low Level Cat Store 34 | * [Meow](https://gist.github.com/MonkeyIsNull/a5b97b52117a97ca5742) 35 | 36 | ## Homework Exercise 37 | * Read https://howistart.org/posts/elixir/1 38 | 39 | -------------------------------------------------------------------------------- /functional_programming.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 2 | * Given the data below, write a function that pulls the _uniq_ first word 3 | items out of the fifth field. You should get back 4 | ``` 5 | ["Open", "Asset", "Core", "Xcode", "_launchservicesd"] 6 | ``` 7 | 8 | ``` 9 | admin:*:231:-2:Open Directory Kerberos Admin Service:/var/empty:/usr/bin/false 10 | _krb_changepw:*:232:-2:Open Directory Kerberos Change Password Service:/var/empty:/usr/bin/false 11 | _krb_kerberos:*:233:-2:Open Directory Kerberos:/var/empty:/usr/bin/false 12 | _krb_anonymous:*:234:-2:Open Directory Kerberos Anonymous:/var/empty:/usr/bin/false 13 | _assetcache:*:235:235:Asset Cache Service:/var/empty:/usr/bin/false 14 | _coremediaiod:*:236:236:Core Media IO Daemon:/var/empty:/usr/bin/false 15 | _xcsbuildagent:*:237:237:Xcode Server Build Agent:/var/empty:/usr/bin/false 16 | _xcscredserver:*:238:238:Xcode Server Credential Server:/var/empty:/usr/bin/false 17 | _launchservicesd:*:239:239:_launchservicesd:/var/empty:/usr/bin/false 18 | ``` 19 | 20 | [answer](https://github.com/MonkeyIsNull/fpexer/blob/master/test/fpexer_test.exs) 21 | 22 | # Exercise 2 23 | 24 | * Given the following data, write a function called find_by_type. 25 | Use it to find all droids, then use it find all humans. Use recursion to do this. 26 | [answer](https://github.com/MonkeyIsNull/fpexer/blob/master/lib/fpexer.ex) 27 | 28 | ``` 29 | characters = [ 30 | %{name: "Han", type: :human, rebel: true, weight: 185}, 31 | %{name: "Jabba", type: :hutt, rebel: false, weight: 2200}, 32 | %{name: "Chewie", type: :wookie, rebel: true, weight: 350}, 33 | %{name: "r2d2", type: :droid, rebel: true, weight: 250}, 34 | %{name: "Luke", type: :human, rebel: true, weight: 140}, 35 | %{name: "Boba Fett", type: :human, rebel: false, weight: 175}, 36 | ] 37 | ``` 38 | 39 | # Bonus Exercise 3 40 | 41 | * Without looking at the slides, code the implementation for map, filter and reduce. 42 | Wikipedia has implementations that are close so you can use those if you're stuck. Reduce is also called fold. 43 | Answers: slides 44 | 45 | -------------------------------------------------------------------------------- /java.ex: -------------------------------------------------------------------------------- 1 | defmodule Java do 2 | 3 | @default_class_file "Hello.class" 4 | 5 | def main(args) do 6 | args |> read_java_class_file |> class_file |> another_class_file(args) 7 | end 8 | 9 | def class_file(<<0xCA, 0xFE, 0xBA, 0xBE, # magic word 10 | minor_version :: bytes-size(2), 11 | major_version :: bytes-size(2), 12 | constant_pool_count :: unsigned-integer-size(16), 13 | rest :: binary >>) do 14 | IO.puts "magic word matched, this is a Java class file" 15 | print_java_version(major_version, minor_version) 16 | IO.puts "there are #{constant_pool_count} entries in the constant pool" 17 | {remaining, new_constant_pool} = constant_pool_entry(rest, constant_pool_count) 18 | 19 | <<>> 20 | <> <<0xCA, 0xFE, 0xBA, 0xBE>> 21 | <> minor_version 22 | <> major_version 23 | <> integer_to_two_bytes(constant_pool_count) 24 | <> new_constant_pool 25 | <> remaining 26 | end 27 | 28 | def print_java_version(<<0x00, 0x34>>, minor_version) do 29 | IO.write "Java 8 minor version: " 30 | IO.inspect minor_version 31 | end 32 | 33 | def print_java_version(<<0x00, 0x33>>, minor_version) do 34 | IO.write "Java 7 minor version: " 35 | IO.inspect minor_version 36 | end 37 | 38 | def print_java_version(<<0x00, 0x32>>, minor_version) do 39 | IO.write "Java 6 minor version: " 40 | IO.inspect minor_version 41 | end 42 | 43 | def print_java_version(v, minor_version) do 44 | IO.puts "Some really old java version..." 45 | IO.write "major version: " 46 | IO.inspect v 47 | IO.write "minor version: " 48 | IO.inspect minor_version 49 | end 50 | 51 | @default_transformation &Java.transformation/1 52 | 53 | def transformation(<<70, 111, 111>>) do 54 | <<66, 97, 114>> 55 | end 56 | 57 | def transformation(anything), do: anything 58 | 59 | def constant_pool_entry(bytes, count) do 60 | constant_pool_entry(bytes, count - 1, <<>>) 61 | end 62 | 63 | def constant_pool_entry(rest, 0, acc ) do 64 | {rest, acc} 65 | end 66 | 67 | def constant_pool_entry(<<1, string_length :: unsigned-integer-size(16), str :: bytes-size(string_length), rest :: binary>>, constant_pool_count, acc ) do 68 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<1>> <> integer_to_two_bytes(string_length) <> @default_transformation.(str)) 69 | end 70 | 71 | def constant_pool_entry(<<3, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 72 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<3>> <> value) 73 | end 74 | 75 | def constant_pool_entry(<<4, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 76 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<4>> <> value) 77 | end 78 | 79 | def constant_pool_entry(<<5, value :: bytes-size(8), rest :: binary>>, constant_pool_count, acc ) do 80 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<5>> <> value) 81 | end 82 | 83 | def constant_pool_entry(<<6, value :: bytes-size(8), rest :: binary>>, constant_pool_count, acc ) do 84 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<6>> <> value) 85 | end 86 | 87 | def constant_pool_entry(<<7, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc) do 88 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<7>> <> value) 89 | end 90 | 91 | def constant_pool_entry(<<8, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc ) do 92 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<8>> <> value) 93 | end 94 | 95 | def constant_pool_entry(<<9, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 96 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<9>> <> value) 97 | end 98 | 99 | def constant_pool_entry(<< <<10>>, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 100 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<10>> <> value) 101 | end 102 | 103 | def constant_pool_entry(<<11, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 104 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<11>> <> value) 105 | end 106 | 107 | def constant_pool_entry(<<12, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 108 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<12>> <> value) 109 | end 110 | 111 | def constant_pool_entry(<<15, value :: bytes-size(3), rest :: binary>>, constant_pool_count, acc ) do 112 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<15>> <> value) 113 | end 114 | 115 | def constant_pool_entry(<<16, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc ) do 116 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<16>> <> value) 117 | end 118 | 119 | def constant_pool_entry(<<18, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc ) do 120 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<18>> <> value) 121 | end 122 | 123 | def read_java_class_file([]) do 124 | read_java_class_file([@default_class_file]) 125 | end 126 | 127 | def read_java_class_file([f]) do 128 | File.read! f 129 | end 130 | 131 | def another_class_file(bytes, []) do 132 | another_class_file(bytes, [@default_class_file]) 133 | end 134 | 135 | def another_class_file(bytes, [f]) do 136 | File.write!(f, bytes) 137 | end 138 | 139 | def integer_to_two_bytes(i) do 140 | if i < 255 do 141 | <<0x00, i>> 142 | else 143 | <> 144 | end 145 | end 146 | 147 | end 148 | -------------------------------------------------------------------------------- /binaries_example/lib/java.ex: -------------------------------------------------------------------------------- 1 | defmodule Java do 2 | 3 | @default_class_file "Hello.class" 4 | 5 | def main(args) do 6 | args |> read_java_class_file |> class_file |> another_class_file(args) 7 | end 8 | 9 | def class_file(<<0xCA, 0xFE, 0xBA, 0xBE, # magic word 10 | minor_version :: bytes-size(2), 11 | major_version :: bytes-size(2), 12 | constant_pool_count :: unsigned-integer-size(16), 13 | rest :: binary >>) do 14 | IO.puts "magic word matched, this is a Java class file" 15 | print_java_version(major_version, minor_version) 16 | IO.puts "there are #{constant_pool_count} entries in the constant pool" 17 | {remaining, new_constant_pool} = constant_pool_entry(rest, constant_pool_count) 18 | 19 | <<>> 20 | <> <<0xCA, 0xFE, 0xBA, 0xBE>> 21 | <> minor_version 22 | <> major_version 23 | <> integer_to_two_bytes(constant_pool_count) 24 | <> new_constant_pool 25 | <> remaining 26 | end 27 | 28 | def print_java_version(<<0x00, 0x34>>, minor_version) do 29 | IO.write "Java 8 minor version: " 30 | IO.inspect minor_version 31 | end 32 | 33 | def print_java_version(<<0x00, 0x33>>, minor_version) do 34 | IO.write "Java 7 minor version: " 35 | IO.inspect minor_version 36 | end 37 | 38 | def print_java_version(<<0x00, 0x32>>, minor_version) do 39 | IO.write "Java 6 minor version: " 40 | IO.inspect minor_version 41 | end 42 | 43 | def print_java_version(v, minor_version) do 44 | IO.puts "Some really old java version..." 45 | IO.write "major version: " 46 | IO.inspect v 47 | IO.write "minor version: " 48 | IO.inspect minor_version 49 | end 50 | 51 | @default_transformation &Java.transformation/1 52 | 53 | def transformation(<<70, 111, 111>>) do 54 | <<66, 97, 114>> 55 | end 56 | 57 | def transformation(anything), do: anything 58 | 59 | def constant_pool_entry(bytes, count) do 60 | constant_pool_entry(bytes, count - 1, <<>>) 61 | end 62 | 63 | def constant_pool_entry(rest, 0, acc ) do 64 | {rest, acc} 65 | end 66 | 67 | def constant_pool_entry(<<1, string_length :: unsigned-integer-size(16), str :: bytes-size(string_length), rest :: binary>>, constant_pool_count, acc ) do 68 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<1>> <> integer_to_two_bytes(string_length) <> @default_transformation.(str)) 69 | end 70 | 71 | def constant_pool_entry(<<3, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 72 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<3>> <> value) 73 | end 74 | 75 | def constant_pool_entry(<<4, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 76 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<4>> <> value) 77 | end 78 | 79 | def constant_pool_entry(<<5, value :: bytes-size(8), rest :: binary>>, constant_pool_count, acc ) do 80 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<5>> <> value) 81 | end 82 | 83 | def constant_pool_entry(<<6, value :: bytes-size(8), rest :: binary>>, constant_pool_count, acc ) do 84 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<6>> <> value) 85 | end 86 | 87 | def constant_pool_entry(<<7, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc) do 88 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<7>> <> value) 89 | end 90 | 91 | def constant_pool_entry(<<8, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc ) do 92 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<8>> <> value) 93 | end 94 | 95 | def constant_pool_entry(<<9, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 96 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<9>> <> value) 97 | end 98 | 99 | def constant_pool_entry(<< <<10>>, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 100 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<10>> <> value) 101 | end 102 | 103 | def constant_pool_entry(<<11, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 104 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<11>> <> value) 105 | end 106 | 107 | def constant_pool_entry(<<12, value :: bytes-size(4), rest :: binary>>, constant_pool_count, acc ) do 108 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<12>> <> value) 109 | end 110 | 111 | def constant_pool_entry(<<15, value :: bytes-size(3), rest :: binary>>, constant_pool_count, acc ) do 112 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<15>> <> value) 113 | end 114 | 115 | def constant_pool_entry(<<16, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc ) do 116 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<16>> <> value) 117 | end 118 | 119 | def constant_pool_entry(<<18, value :: bytes-size(2), rest :: binary>>, constant_pool_count, acc ) do 120 | constant_pool_entry(rest, constant_pool_count - 1, acc <> <<18>> <> value) 121 | end 122 | 123 | def read_java_class_file([]) do 124 | read_java_class_file([@default_class_file]) 125 | end 126 | 127 | def read_java_class_file([f]) do 128 | File.read! f 129 | end 130 | 131 | def another_class_file(bytes, []) do 132 | another_class_file(bytes, [@default_class_file]) 133 | end 134 | 135 | def another_class_file(bytes, [f]) do 136 | File.write!(f, bytes) 137 | end 138 | 139 | def integer_to_two_bytes(i) do 140 | if i < 255 do 141 | <<0x00, i>> 142 | else 143 | <> 144 | end 145 | end 146 | 147 | end 148 | --------------------------------------------------------------------------------