Week 07 of 2019
Development log of Elm Tree Workshop
14 items
- Create a test run page about the UU4U collaboration
- Merge branch 'pricing' into 'master'
- Reedit test run page
- Merge branch 'pricing' into 'master'
- Initial implementation of Examples.AnimatedTree
- Integrate Examples.AnimatedTree with Examples module
- Rewrite content to work on Ellie.
- Edited Fold block on day 2.
- Edit Fold block on day 2.
- Add workshop dates to test-run.
- Merge branch 'workshop-dates' into 'master'
- Merge branch 'rewrite-content-ellie' of gitlab.com:software-garden/software-garden.gitlab.io into rewrite-content-ellie
- Change code Terminal to code Elm Repl on day 3 and day 4.
- Remove import String from Elm Repl on day 3.
Create a test run page about the UU4U collaboration
On by
index 79e54bd..36da1e7 100644
--- a/content/index.txt
+++ b/content/index.txt
@@ -13,7 +13,12 @@ Hello! We are running a workshop that will give you a glimpse into the way softw
=
= or drop us a note at {Link|fana@software.garden|url= mailto:fana@software.garden}
=
-You can learn more about {Link|our motivation|url=/motivation.html}. Below is material through which we will be going during the workshop. Only the first section is a required read before you come, but feel free to read more to get more prepared.
+During this *5 days workshop* (4 hours each day) you will learn to solve problems using a functional programming language. We think {Link|it's important|url=/motivation.html}. Upon completion of the course your name, photo and link to your website (or LinkedIn profile etc) will be posted here. The price for participation is *500 €* (inc. 21% VAT).
+
+| Note
+ {Icon|name=gift} {Link|Special offer for University of Utrecht students|url=/test-run.html}.
+
+Below is the material through which we will be going during the workshop. Only the first section is a required read before you come.
=
=| Link
= url = /preparation.htmlnew file mode 100644
index 0000000..a0c1120
--- /dev/null
+++ b/content/test-run.txt
@@ -0,0 +1,11 @@
+| Title
+ Special Offer for University of Utrecht Students
+
+In collaboration with {Link|Career Services|url=https://students.uu.nl/en/careerservices} of the University of Utrecht we are offering a one time, free workshop for first 12 students to sign up. The workshop will be shorter than usual (3 hours a day) because you are so smart 🤓
+
+| Emphasize
+ {Link|Sign up!|url=https://fd21.formdesk.com/universiteitutrecht/CS-20190304-08-SoftwareGarden}
+
+ <>
+
+ {Icon|name=phone} {Link|+31 638 216 166|url=tel:+31638216166} | {Icon|name=mail} {Link|fana@software.garden|url= mailto:fana@software.garden} | {Icon|name=home} {Link|Back|url=/}index 499cdc9..12dfff2 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -188,6 +188,9 @@ view model =
= Routes.Motivation ->
= Element.none
=
+ Routes.TestRun ->
+ Element.none
+
= Routes.Content _ ->
= contentNavigationBar model
=
@@ -464,6 +467,12 @@ loadContent route =
= , expect = Http.expectString ContentFetched
= }
=
+ Routes.TestRun ->
+ Http.get
+ { url = "/content/test-run.txt"
+ , expect = Http.expectString ContentFetched
+ }
+
= Routes.Content base ->
= Http.get
= { url = "/content/" ++ base ++ ".txt"index 29893c6..8dbac32 100644
--- a/src/Routes.elm
+++ b/src/Routes.elm
@@ -12,6 +12,7 @@ type Route
= = Home
= | Content String
= | Motivation
+ | TestRun
= | NotFound
=
=
@@ -20,6 +21,7 @@ parser =
= Parser.oneOf
= [ Parser.map Home Parser.top
= , Parser.map Motivation (Parser.s "motivation.html")
+ , Parser.map TestRun (Parser.s "test-run.html")
= , Parser.custom "Content"
= (\path ->
= case String.split "." path ofMerge branch 'pricing' into 'master'
On by
Create a test run page about the UU4U collaboration
See merge request software-garden/software-garden.gitlab.io!22
Reedit test run page
On by
index a0c1120..00ea641 100644
--- a/content/test-run.txt
+++ b/content/test-run.txt
@@ -1,10 +1,10 @@
=| Title
= Special Offer for University of Utrecht Students
=
-In collaboration with {Link|Career Services|url=https://students.uu.nl/en/careerservices} of the University of Utrecht we are offering a one time, free workshop for first 12 students to sign up. The workshop will be shorter than usual (3 hours a day) because you are so smart 🤓
+In collaboration with {Link|Career Services|url=https://students.uu.nl/en/careerservices} of the University of Utrecht we are offering a one time, free workshop for the first 12 students to sign up. The workshop will be shorter than usual - 3 hours a day.
=
=| Emphasize
- {Link|Sign up!|url=https://fd21.formdesk.com/universiteitutrecht/CS-20190304-08-SoftwareGarden}
+ {Link|Sign up now|url=https://fd21.formdesk.com/universiteitutrecht/CS-20190304-08-SoftwareGarden}
=
= <>
=Merge branch 'pricing' into 'master'
On by
Reedit test run page
See merge request software-garden/software-garden.gitlab.io!23
Initial implementation of Examples.AnimatedTree
On by
No integration with markup yet. Works only in Elm Reactor.
new file mode 100644
index 0000000..a61064c
--- /dev/null
+++ b/src/Examples/AnimatedTree.elm
@@ -0,0 +1,134 @@
+module Examples.AnimatedTree exposing
+ ( main
+ , ui
+ )
+
+import Browser
+import Browser.Events
+import Element exposing (Element)
+import Element.Input as Input
+import Examples.Tree
+import Html exposing (Html)
+
+
+main : Program Flags Model Msg
+main =
+ Browser.element
+ { init = init
+ , view = view
+ , update = update
+ , subscriptions = subscriptions
+ }
+
+
+type alias Model =
+ { age : Float
+ , maxAge : Float
+ , minAge : Float
+ , play : Bool
+ , config : Examples.Tree.Config
+ }
+
+
+type alias Flags =
+ ()
+
+
+init : Flags -> ( Model, Cmd msg )
+init flags =
+ ( { age = 0.0
+ , maxAge = 6.0
+ , minAge = 0
+ , play = False
+ , config = Examples.Tree.defaults
+ }
+ , Cmd.none
+ )
+
+
+ui : Examples.Tree.Config -> Model -> Element Msg
+ui config model =
+ let
+ tree =
+ { config | axiom = { axiom | age = model.age } }
+
+ controls =
+ if model.play then
+ pauseButton
+
+ else
+ playButton
+
+ axiom =
+ config.axiom
+
+ playButton =
+ Input.button []
+ { onPress = Just Play
+ , label = Element.text "Play"
+ }
+
+ pauseButton =
+ Input.button []
+ { onPress = Just Pause
+ , label = Element.text "Pause"
+ }
+ in
+ Element.column
+ [ Element.width Element.fill, Element.height Element.fill ]
+ [ Examples.Tree.ui tree
+ , controls
+ ]
+
+
+type Msg
+ = Play
+ | Pause
+ | Animate Float
+
+
+view : Model -> Html Msg
+view model =
+ model
+ |> ui Examples.Tree.defaults
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update msg model =
+ case msg of
+ Play ->
+ ( { model | play = True }
+ , Cmd.none
+ )
+
+ Pause ->
+ ( { model | play = False }
+ , Cmd.none
+ )
+
+ Animate delta ->
+ let
+ progress =
+ min 32 delta / 5000
+
+ age =
+ (model.age + progress)
+ |> min model.maxAge
+ |> max model.minAge
+ in
+ ( { model | age = age }
+ , Cmd.none
+ )
+
+
+subscriptions : Model -> Sub Msg
+subscriptions model =
+ if model.play then
+ Browser.Events.onAnimationFrameDelta Animate
+
+ else
+ Sub.noneIntegrate Examples.AnimatedTree with Examples module
On by
No integration with markup yet.
index 4db325b..2492c7d 100644
--- a/src/Examples.elm
+++ b/src/Examples.elm
@@ -1,5 +1,6 @@
=module Examples exposing (Model, Msg(..), init, subscriptions, update)
=
+import Examples.AnimatedTree
=import Examples.CartesianCoordinates
=import Examples.Circle
=import Examples.Counter
@@ -21,6 +22,7 @@ type alias Model =
= , cartesianCoordinates : Examples.CartesianCoordinates.Model
= , polarCoordinates : Examples.PolarCoordinates.Model
= , viewBox : Examples.ViewBox.Model
+ , animatedTree : Examples.AnimatedTree.Model
= }
=
=
@@ -31,18 +33,24 @@ type Msg
= | CartesianCoordinatesMsg Examples.CartesianCoordinates.Msg
= | PolarCoordinatesMsg Examples.PolarCoordinates.Msg
= | ViewBoxMsg Examples.ViewBox.Msg
+ | AnimatedTreeMsg Examples.AnimatedTree.Msg
=
=
=init : ( Model, Cmd Msg )
=init =
+ let
+ ( animatedTreeModel, animatedTreeMsg ) =
+ Examples.AnimatedTree.init ()
+ in
= ( { counter = Examples.Counter.init
= , transformations = Examples.Transformations.init
= , nestedTransformations = Examples.NestedTransformations.init
= , cartesianCoordinates = Examples.CartesianCoordinates.init
= , polarCoordinates = Examples.PolarCoordinates.init
= , viewBox = Examples.ViewBox.init
+ , animatedTree = animatedTreeModel
= }
- , Cmd.none
+ , animatedTreeMsg
= )
=
=
@@ -89,7 +97,18 @@ update msg model =
= ViewBoxMsg m ->
= ( { model | viewBox = Examples.ViewBox.update m model.viewBox }, Cmd.none )
=
+ AnimatedTreeMsg m ->
+ let
+ ( animatedTreeModel, animatedTreeMsg ) =
+ Examples.AnimatedTree.update m model.animatedTree
+ in
+ ( { model | animatedTree = animatedTreeModel }
+ , animatedTreeMsg |> Cmd.map AnimatedTreeMsg
+ )
+
=
=subscriptions : Model -> Sub Msg
=subscriptions model =
- Sub.none
+ model.animatedTree
+ |> Examples.AnimatedTree.subscriptions
+ |> Sub.map AnimatedTreeMsgindex a61064c..f6efba1 100644
--- a/src/Examples/AnimatedTree.elm
+++ b/src/Examples/AnimatedTree.elm
@@ -1,6 +1,11 @@
=module Examples.AnimatedTree exposing
- ( main
+ ( Model
+ , Msg
+ , init
+ , main
+ , subscriptions
= , ui
+ , update
= )
=
=import BrowserRewrite content to work on Ellie.
On by
I have removed contents from day 1 and moved it to preparation.
index 6b759b8..3ddc2f7 100644
--- a/content/day-1.txt
+++ b/content/day-1.txt
@@ -15,100 +15,6 @@
= -> Layouts with Elm UI
= -> Lists
=
-
-| Header
- Our First Program!
-
-As mentioned before, programs are represented as text (called the /source code/). The source code is stored in files {Icon|name=file} and files are organized in directories {Icon|name=folder}.
-
-
-So the first step is to create a directory for our new program. Let's call it {Code|software-garden}.
-
-In the terminal type:
-
-| Terminal
- mkdir software-garden/
-
-press {Key|enter} key. Then type:
-
-| Terminal
- cd software-garden/
-
-| Note
- Press {Key|enter} again. Generally when we ask you to type something in a terminal, we imply that you press enter afterwards. That's how you signal that you are done typing and expect computer to process your command. Alternatively we call it entering a command.
-
- In this case the first command ({Code|mkdir}) will *m*a*k*e our new *dir*ectory and the second ({Code|cd}) will set it as the *c*urrent *d*irectory, so that subsequent commands will be executed in the context of {Code|software-garden//} directory.
-
- Don't worry about the details too much. Just remember that if you close your terminal and then open it again, you will need to enter:
-
- {Code|cd software-garden//}
-
- to set the current directory again.
-
-We can easily create a new program by entering a following command:
-
-| Terminal
- elm init
-
-You should see something similar to this:
-
-| Terminal
- Hello! Elm projects always start with an elm.json file. I can create them!
-
- Now you may be wondering, what will be in this file? How do I add Elm files to
- my project? How do I see it in the browser? How will my code grow? Do I need
- more directories? What about tests? Etc.
-
- Check out <https://elm-lang.org/0.19.0/init> for all the answers!
-
- Knowing all that, would you like me to create an elm.json file now? [Y/n]:
-
-
-Just press {Key|enter} once again to proceed. Then to create the file which will contain our source code, type:
-
-| Terminal
- atom src/Main.elm
-
-| Note
- Notice that the word {Code|Main} is capitalized. It's important! You can enter uppercase letter {Code|M} with {Key|shift} + {Key|m}, which means:
-
- | List
- - Press and hold {Key|shift}
- - While holding press the {Key|m} button once.
- - Finally release the {Key|shift}.
-
-It may take few seconds, but eventually this command should open a new Atom editor window with an empty text file. If you prefer to use different editor, feel free to do so. Once the editor is ready, type the code below and save the file.
-
-| Editor
- | Annotations
- | None
-
- | Code
- module Main exposing (main)
-
-
- import Html
-
- main =
- Html.text "Hello, Tree"
-
-Then switch back to the terminal and enter the following command:
-
-| Terminal
- elm reactor
-
-This command will start the Elm Reactor, which will allow you to run your program in the web browser. Note that it won't give you the command prompt back - it will run in the terminal until you stop it. Leave it running and open the following address in the web browser:
-
-| Emphasize
- {Link|http:////localhost:8000//src//Main.elm|url=http://localhost:8000/src/Main.elm}
-
-You should see something like this:
-
-| Window
- Hello, Tree!
-
-This was a warmup. Let's try something more challenging.
-
=| Header
= The problem
=
@@ -162,30 +68,9 @@ Below is the complete code to draw a dot like this, but don't type it in your ed
= , Element.height Element.fill
= ]
=
-We are going to use a technology called *SVG (Scalable Vector Graphics)*. It's all about drawing shapes on the screen. Let's install an Elm Package to help us work with SVG. Stop the reactor running in the terminal by pressing {Key|ctrl} + {Key|c} and then enter the following command:
+We are going to use a technology called *SVG (Scalable Vector Graphics)*. It's all about drawing shapes on the screen. Let's install an Elm Package to help us work with SVG. Go to {Icon|name=package} to install svg.
=
-| Terminal
- elm install elm/svg
-
-| Note
- To press {Key|ctrl} + {Key|c} means:
-
- | List
- - Press and hold {Key|ctrl} button (on some keyboards it's labeled as {Key|control}).
- - While holding press the {Key|c} button once.
- - Finally release the {Key|ctrl}.
-
-In response you should see something like this:
-
-| Terminal
- Here is my plan:
-
- Add:
- elm/svg 1.0.1
-
- Would you like me to update your elm.json accordingly? [Y/n]:
-
-Press {Key|enter} to proceed with the installation. Now that we have {Code|elm//svg} installed, we can write the code that will draw a dot for us. Change the code to look like this:
+Now that we have {Code|elm//svg} installed, we can write the code that will draw a dot for us. Change the code to look like this:
=
=| Editor
= | Annotations
@@ -204,15 +89,8 @@ Press {Key|enter} to proceed with the installation. Now that we have {Code|elm//
= [ Svg.Attributes.r "10" ] []
= ]
=
-Start the reactor again by entering:
=
-| Terminal
- elm reactor
-
-| Note
- You can press the up arrow {Key|▲} on the keyboard to retrieve commands entered previously.
-
-Reload the browser. You should see something like this:
+Click {Key|COMPILE}, you should see something like this:
=
=| Window
= | Shapes
@@ -253,7 +131,8 @@ First we have to realize that the dot is inside an {Code|svg} element that itsel
= []
= ]
=
-Reloading the browser should reveal something like this:
+
+Click {Key|COMPILE} and it should reveal something like this:
=
=| Window
= | Shapes
@@ -272,16 +151,17 @@ Reloading the browser should reveal something like this:
=
=Since the dot is inside the {Code|svg} element, and the {Code|svg} element doesn't cover the center of the screen, it's impossible to place the dot at the center. Before anything else, let's make the {Code|svg} fill entire {Definition|term=viewport|definiens=the area of the browser window where the content is displayed}.
=
-To do this we will use a package called {Code|mdgriffith//elm-ui}. It makes laying out elements relatively easy. Install it with the terminal. Press {Key|ctrl} + {Key|c} to stop the elm reactor and enter the command
+To do this we will use a package called {Code|mdgriffith//elm-ui}. It makes laying out elements relatively easy. Go to {Icon|name=package} and install elm-ui.
=
-| Terminal
- elm install mdgriffith/elm-ui
-
-As before, press {Key|enter} to follow the plan. Now let's use the package. Change the code to look like this:
+Now let's use the package. Change the code to look like this:
=
=| Editor
= | Annotations
- | None
+ | Highlight
+ top = 3
+ left = 1
+ width = 14
+ height = 1
=
= | Code
= module Main exposing (main)
@@ -308,7 +188,6 @@ As before, press {Key|enter} to follow the plan. Now let's use the package. Chan
= , Element.height Element.fill
= ]
=
-
=| Note
= Don't worry if it all looks like black magic now. We will discuss what it all means on {Link|Day 3|url=day-3.html} of the workshop.
=
@@ -318,7 +197,7 @@ As before, press {Key|enter} to follow the plan. Now let's use the package. Chan
=
= Then there are some new things on lines 19 - 23. First is the pipe operator ({Code|\|>}). We use it to pass the {Code|svg} element together with the {Code|circle} inside it into `Element.html` function (we need to convert it into an {Code|Element}) and then to pass this {Code|Element} into an {Code|Element.layout} which will fill the viewport with its contents. Again, more about the pipe and functions on day 3.
=
-Reload the browser. The SVG space now fills the entire viewport. Even the small white margin is gone!
+Click {Icon|name=align-left} to format your code and then click {Key|COMPILE}. The SVG space now fills the entire viewport. Even the small white margin is gone!
=
=| Window
= | Shapes
@@ -335,7 +214,7 @@ Reload the browser. The SVG space now fills the entire viewport. Even the small
= x = 0
= y = 0
=
-It should now be possible to place our dot in the center of the screen. Currently the dot is in the top left corner of the viewport, but at least the parent {Code|svg} element is covering it, so the center of the viewport is somewher within the {Code|svg} element.
+It should now be possible to place our dot in the center of the screen. Currently the dot is in the top left corner of the viewport, but at least the parent {Code|svg} element is covering it, so the center of the viewport is somewhere within the {Code|svg} element.
=
=| Header
= The Coordinates
@@ -399,6 +278,7 @@ To change the position of the dot, we can use the {Code|cx} and {Code|cy} attrib
= , Element.height Element.fill
= ]
=
+
=| Window
= | Shapes
= | Containerindex afa080b..f2fbb4c 100644
--- a/content/day-2.txt
+++ b/content/day-2.txt
@@ -32,14 +32,47 @@ Previously we have created a program that displays one dot in the center of the
=
=First obvious difference is that now we have multiple dots. The only dot we have created using {Code|Svg.circle} function on line 9 - 15, this code block:
=
-| Monospace
- Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "skyblue"
- ]
- []
+| Editor
+ | Annotations
+ | None
+
+ | Fold
+ start = 1
+ length = 8
+
+ | Fold
+ start = 17
+ length = 12
+
+
+ | Code
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ ]
+ |> Svg.svg
+ [ Svg.Attributes.height "100%"
+ , Svg.Attributes.width "100%"
+ , Svg.Attributes.viewBox "-300 -300 600 600"
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
=
=If you look closely in your source code, the block above is surrounded by {Code|[} and {Code|]} characters. That's a list. We will talk about lists during the next day. For now it's enough to say that a list can contain zero, one or more items of the same type. In this case it contains one item of type {Code|Svg msg} - our lonely, blue dot. Let's add a second one like this:
=
@@ -90,6 +123,7 @@ If you look closely in your source code, the block above is surrounded by {Code|
= , Element.height Element.fill
= ]
=
+
=Now the list spans from lines 9 to 23 and contains two items: skyblue and orange dots. The result should be:
=
=| Window
@@ -420,10 +454,7 @@ In mathematics there is a special operation to determine it. Perhaps you have he
=| Monospace
= 360 / 5
=
-Maybe you can solve it in your head, but if not, why not use Elm REPL? Go to the terminal, stop the reactor (if it's running) and type:
-
-| Monospace
- elm repl
+Maybe you can solve it in your head, but if not, why not use an online Elm REPL? Go to {Link|elmrepl.cuberoot.in|url=http://elmrepl.cuberoot.in/}.
=
=And then
=
@@ -440,8 +471,6 @@ You should see:
= 72 : Float
= >
=
-Type {Code|:exit} to close the REPL.
-
=Turns out that the result is 72. That's the number of degrees we have to turn our ruler around the center each time we place a new dot. If you have a protractor like the one pictured above, you can use it to measure the turn. Then measure the distance from the center along the ruler (a length called radius) and place the dot there.
=
=| Circle
@@ -468,7 +497,7 @@ Now that we understand what it means to be placed on a circle and evenly distrib
= radius = 80
= scatter = False
=
-We will start from where we left off yesterday. Open {Code|src//Main.elm} in your editor. It should have the following code:
+We will start from where we left off yesterday. Open Eliie in your browser and go to your saved bookmark. It should have the following code:
=
=| Editor
= | Annotations
@@ -515,23 +544,42 @@ Also, let's change the color of the dot. In the end it should look like this:
= | Annotations
= | None
=
+ | Fold
+ start = 1
+ length = 11
+
+ | Fold
+ start = 21
+ length = 7
+
= | Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- ]
+ module Main exposing (main)
=
-With this change, start the reactor by typing in your terminal:
+ import Element
+ import Svg
+ import Svg.Attributes
=
-| Monospace
- elm reactor
=
-and {Link|open the program in your browser|url=http://localhost/src/Main.elm}. You should see something like this:
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+With this change, click {Key|COMPILE}. You should see something like this:
=
=| Window
= | Circle
@@ -551,24 +599,48 @@ Now we need a second dot. If you remember the discussion about lists from previo
= | Annotations
= | None
=
+ | Fold
+ start = 1
+ length = 11
+
+ | Fold
+ start = 29
+ length = 8
+
= | Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "translate(80)"
- ]
- []
- ]
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "translate(80)"
+ ]
+ []
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=Now let's focus on the second one. We gave it a different color, so we can distinguish between them, but now we don't see the first one! That's because it's exactly in the same spot as the second one, which covers it. They are stacked in a way. We need to move the second dot in a different direction, so it's on a circle, but 72 degree apart from the first one.
=
@@ -577,72 +649,116 @@ For that we need to add another transformation before the move. First we will ro
=| Editor
= | Annotations
= | Highlight
- top = 14
- left = 6
- width = 53
+ top = 25
+ left = 14
+ width = 51
= height = 1
=
+ | Fold
+ start = 1
+ length = 11
+
+ | Fold
+ start = 29
+ length = 8
+
= | Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "rotate(72) translate(80)"
- ]
- []
- ]
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
=
-This will rotate the element by 72 degrees. On its own it wouldn't make any difference, because the dot is round - it doesn't matter how you rotate it, it always looks the same. But It also rotates it's internal coordinates system. So the translation will move it in a different direction then the first dot.
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
+
+This will rotate the element by 72 degrees. On its own it wouldn't make any difference, because the dot is round - it doesn't matter how you rotate it, it always looks the same. But It also rotates its internal coordinates system. So the translation will move it in a different direction then the first dot.
=
=Now it's time to add the third, red dot. Duplicate the second one, change fill to `"red"` and put `144` for rotate function, like this:
=
=| Editor
= | Annotations
= | Highlight
- top = 22
- left = 6
+ top = 33
+ left = 14
= width = 54
= height = 1
=
= | Fold
= start = 1
- length = 16
+ length = 27
+
+ | Fold
+ start = 37
+ length = 7
=
= | Code
- [ Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.transform "translate(80)"
- , Svg.Attributes.fill "skyblue"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "orange"
- , Svg.Attributes.transform "rotate(72) translate(80)"
- ]
- []
- , Svg.circle
- [ Svg.Attributes.r "10"
- , Svg.Attributes.cx "0"
- , Svg.Attributes.cy "0"
- , Svg.Attributes.fill "red"
- , Svg.Attributes.transform "rotate(144) translate(80)"
- ]
- []
- ]
+ module Main exposing (main)
+
+ import Element
+ import Svg
+ import Svg.Attributes
+
+
+ main =
+ Svg.svg
+ [ Svg.Attributes.viewBox "-100 -100 200 200"
+ ]
+ [ Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.transform "translate(80)"
+ , Svg.Attributes.fill "skyblue"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "orange"
+ , Svg.Attributes.transform "rotate(72) translate(80)"
+ ]
+ []
+ , Svg.circle
+ [ Svg.Attributes.r "10"
+ , Svg.Attributes.cx "0"
+ , Svg.Attributes.cy "0"
+ , Svg.Attributes.fill "red"
+ , Svg.Attributes.transform "rotate(144) translate(80)"
+ ]
+ []
+ ]
+ |> Element.html
+ |> Element.layout
+ [ Element.width Element.fill
+ , Element.height Element.fill
+ ]
=
=Why 144? It's because 72 + 72 is 144! So to be 72 degree apart from a dot that's at 72 degree, you need to be at 144 (or 0, but the first dot is already there).
=
@@ -732,7 +848,7 @@ The complete program should look like this:
= , Element.height Element.fill
= ]
=
-In the browser it should look exactly as we planned:
+In Ellie it should look exactly as we planned:
=
=| Window
= | Circleindex f39b2ad..19b53ef 100644
--- a/content/day-3.txt
+++ b/content/day-3.txt
@@ -24,10 +24,7 @@ Before we begin, let's reflect on the following.
=| Emphasize
= Every Elm program is composed of three basic building blocks: {Code|values}, {Code|names} and {Code|types}.
=
-For efficiency we are going to play with these concepts in REPL (the Read - Evaluate - Print Loop). Go to the terminal. If you have Elm reactor running, then stop it with {Key|ctrl} + {Key|c}. Then start the REPL by entering
-
-| Terminal
- elm repl
+For efficiency we are going to play with these concepts in REPL (the Read - Evaluate - Print Loop). Go to online Elm REPL {Link|elmrepl.cuberoot.in|url=http://elmrepl.cuberoot.in/}.
=
=It should show something like this
=
@@ -525,7 +522,7 @@ Move your cursor to the end of the file and type {Code|dot =}, press {Key|enter}
= ]
= []
=
-Reload the browser. Everything should work exactly the same as before. One of the dots is now a named value, but for our program it makes no difference. What is important is its value, not where it comes from.
+Click {Key|COMPILE}. Everything should work exactly the same as before. One of the dots is now a named value, but for our program it makes no difference. What is important is its value, not where it comes from.
=
=Of course the goal is to have our list of dots looking like this:
=
@@ -551,7 +548,7 @@ The dots need to have some parameters so they can be different. We already ident
=
= | Fold
= start = 13
- length = 38
+ length = 39
=
= | Code
= module Main exposing (main)
@@ -565,7 +562,7 @@ The dots need to have some parameters so they can be different. We already ident
= Svg.svg
= [ Svg.Attributes.viewBox "-100 -100 200 200"
= ]
- [ dot color rotation
+ [ dot "skyblue" 0
= , Svg.circle
= [ Svg.Attributes.r "10"
= , Svg.Attributes.cx "0"
@@ -605,6 +602,7 @@ The dots need to have some parameters so they can be different. We already ident
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -627,7 +625,7 @@ This way we declared that when calling a {Code|dot} name you will provide two va
=
= | Fold
= start = 18
- length = 5
+ length = 6
=
= | Code
= module Main exposing (main)
@@ -653,6 +651,7 @@ This way we declared that when calling a {Code|dot} name you will provide two va
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -670,7 +669,7 @@ First, let's use the {Code|color} parameter. If you want to change the color of
=| Editor
= | Annotations
= | Highlight
- top = 29
+ top = 30
= left = 31
= width = 5
= height = 1
@@ -681,7 +680,7 @@ First, let's use the {Code|color} parameter. If you want to change the color of
=
= | Fold
= start = 18
- length = 5
+ length = 6
=
= | Code
= module Main exposing (main)
@@ -707,6 +706,7 @@ First, let's use the {Code|color} parameter. If you want to change the color of
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -753,6 +753,7 @@ We can use the {Code|++} operator to glue the strings together. First part is co
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -797,6 +798,7 @@ But Elm will complain about this. First it looks like we gave 5 arguments to the
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -921,7 +923,7 @@ That's what we need! Let's pass the value of {Code|rotation} through this functi
= ]
= []
=
-This should work! The browser should now present the dots as intended and I hope you agree that the code is more readable now.
+This should work! Ellie should now present the dots as intended and I hope you agree that the code is more readable now.
=
=| Header
= Lines to Connect the Dots
@@ -1048,7 +1050,7 @@ Once you have the function defined, let's use it. For every dot, create one line
= ]
= []
=
-You should see something like this in the browser:
+You should see something like this in on Ellie:
=
=| Window
= | Shapesindex 5b8499f..5cf6d1a 100644
--- a/content/day-4.txt
+++ b/content/day-4.txt
@@ -63,11 +63,11 @@ The tree is built from segments: a line and a dot. In this respect it is similar
=
= | Fold
= start = 1
- length = 6
+ length = 7
=
= | Fold
- start = 29
- length = 48
+ start = 30
+ length = 49
=
= | Code
= module Main exposing (main)
@@ -76,6 +76,7 @@ The tree is built from segments: a line and a dot. In this respect it is similar
= import Svg
= import Svg.Attributes
=
+
= main =
= [ Svg.g []
= [ dot "skyblue" 0
@@ -110,6 +111,7 @@ The tree is built from segments: a line and a dot. In this respect it is similar
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -145,7 +147,7 @@ The tree is built from segments: a line and a dot. In this respect it is similar
= ]
= []
=
-Reload the browser there should be no difference at this point. Looking back at code I notice that each segment looks the same: it is a group with a dot and a line, where the {Code|group} and {Code|line} functions have the same arguments passed to them. This kind of repetition begs for a function. Let's call it {Code|segment} and define like this:
+{Key|COMPILE} on Ellie there should be no difference at this point. Looking back at code I notice that each segment looks the same: it is a group with a dot and a line, where the {Code|group} and {Code|line} functions have the same arguments passed to them. This kind of repetition begs for a function. Let's call it {Code|segment} and define like this:
=
=| Editor
= | Annotations
@@ -163,24 +165,24 @@ Type this code at the bottom of the file and then replace main with the followin
=| Editor
= | Annotations
= | Highlight
- top = 61
+ top = 64
= left = 1
= width = 29
= height = 5
=
= | Highlight
- top = 8
+ top = 9
= left = 4
= width = 22
= height = 6
=
= | Fold
= start = 1
- length = 6
+ length = 7
=
= | Fold
- start = 26
- length = 34
+ start = 27
+ length = 36
=
= | Code
= module Main exposing (main)
@@ -189,6 +191,7 @@ Type this code at the bottom of the file and then replace main with the followin
= import Svg
= import Svg.Attributes
=
+
= main =
= [ segment "skyblue" 0
= , segment "orange" 72
@@ -208,6 +211,7 @@ Type this code at the bottom of the file and then replace main with the followin
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -243,6 +247,7 @@ Type this code at the bottom of the file and then replace main with the followin
= ]
= []
=
+
= segment color rotation =
= Svg.g []
= [ dot color rotation
@@ -252,7 +257,7 @@ Type this code at the bottom of the file and then replace main with the followin
=| Note
= I hope you can see the pattern in what we are doing. We are taking repetitive blocks of code and turning them into named functions. Parameters help us deal with variability in the repeated code (like color and rotation that is different for each segment).
=
-Reload the browser. There should still be no visible difference in the behavior of the program, but our source code is getting more readable. That's good.
+Click {Key|COMPILE}. There should still be no visible difference in the behavior of the program, but our source code is getting more readable. That's good.
=
=The big difference between our program and the one we are trying to build is that ours have only one level of segments, whereas in the example segments grow from the tip of other segments. You can think of it as segments having child segments: the green segment has two child red segments and one green segment. Each red segment has two green child segments.
=
@@ -264,10 +269,10 @@ It's similar to how the way an SVG group has child elements. But group itself (t
=
= | Fold
= start = 1
- length = 6
+ length = 7
=
= | Fold
- start = 26
+ start = 28
= length = 35
=
= | Code
@@ -277,6 +282,7 @@ It's similar to how the way an SVG group has child elements. But group itself (t
= import Svg
= import Svg.Attributes
=
+
= main =
= [ segment "skyblue" 0
= , segment "orange" 72
@@ -296,6 +302,7 @@ It's similar to how the way an SVG group has child elements. But group itself (t
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -331,6 +338,7 @@ It's similar to how the way an SVG group has child elements. But group itself (t
= ]
= []
=
+
= segment color rotation =
= Svg.g []
= [ dot color rotation
@@ -699,30 +707,30 @@ Now the program should display something like this:
= x = 80
= y = 0
=
-It's already starts to look interesting, but there are two problems with it. First it doesn't fit on screen. This is easy to fix using {Code|viewBox}. We need to zoom out to see more of a picture. Change the value passed to {Code|viewBox} on line 19 to {Code|"-500 -500 1000 1000"}, effectively zooming out 5x but preserving keeping the origin in the center of our viewbox.
+It already starts to look interesting, but there are two problems with it. First it doesn't fit on screen. This is easy to fix using {Code|viewBox}. We need to zoom out to see more of a picture. Change the value passed to {Code|viewBox} on line 19 to {Code|"-500 -500 1000 1000"}, effectively zooming out 5x but preserving keeping the origin in the center of our viewbox.
=
=Then the lines look ugly displayed on top of the dots of different color. This is also easy to fix. In SVG several siblings (children of the same parent element) lay one on top of another. The "younger" sibling is laying on top of the older, so in our case the group containing the blue and red dots and lines lays on top of the dot and line. Let's change the order of siblings by moving the group to the beginning of the list, like this:
=
=| Editor
= | Annotations
= | Highlight
- top = 18
+ top = 19
= left = 12
= width = 46
= height = 1
=
= | Highlight
- top = 73
+ top = 74
= left = 10
= width = 21
= height = 8
=
= | Fold
= start = 1
- length = 6
+ length = 7
=
= | Fold
- start = 20
+ start = 21
= length = 43
=
= | Code
@@ -732,6 +740,7 @@ Then the lines look ugly displayed on top of the dots of different color. This i
= import Svg
= import Svg.Attributes
=
+
= main =
= [ segment "skyblue" 0
= , segment "orange" 72
@@ -751,6 +760,7 @@ Then the lines look ugly displayed on top of the dots of different color. This i
= , Element.height Element.fill
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -807,6 +817,7 @@ Then the lines look ugly displayed on top of the dots of different color. This i
= , line color rotation
= ]
=
+
=With this two changes applied you should see something like this in the browser:
=
=| Window
@@ -1277,9 +1288,9 @@ So now each segment has two sub segments: red and blue. The red one is rotated 1
= []
=
=
-We have added third parameter to {Code|segment} function on line 35 (before the changes it was 28). The parameter is named {Code|children} and we use it in place of the list on line 46 (previously 39). The list itself was moved to line 11, where it is passed as a value for the parameter of the first segment. This move made all the lines shift down. All other segments will also need to get value for {Code|children} parameter, so let's just give each of them an empty list - meaning they have 0 children.
+We have added third parameter to the {Code|segment} function on line 35 (before the changes it was 64). The parameter is named {Code|children} and we use it in place of the list on line 46 (previously 75). The list itself was moved to line 11, where it is passed as a value for the parameter of the first segment. This move made all the lines shift down. All other segments will also need to get value for {Code|children} parameter, so let's just give each of them an empty list - meaning they have 0 children.
=
-Once all changes are applied, reload the browser and see that only first, skyblue segment has child segments.
+Once all changes are applied, click {Key|COMPILE} and see that only first, skyblue segment has child segments.
=
=| Window
= | Shapes
@@ -1424,7 +1435,7 @@ Before we continue, let's notice that on lines 11 - 15 we have a nice opportunit
=
= | Fold
= start = 16
- length = 72
+ length = 73
=
= | Code
= module Main exposing (main)
@@ -1513,6 +1524,7 @@ Before we continue, let's notice that on lines 11 - 15 we have a nice opportunit
= ]
= []
=
+
=with:
=| Editor
= | Annotations
@@ -1715,6 +1727,7 @@ A segment within a segment! Consider that every segment can have child segments.
= ]
= []
=
+
=| Emphasize
= Time to play
=
@@ -1938,6 +1951,7 @@ The tree following these rules will look like this:
= y = 0
= | Rotate
= -45
+
= | Dot
= radius = 10
= color = red
@@ -1974,6 +1988,7 @@ The tree following these rules will look like this:
= y = 0
= | Rotate
= -5
+
= | Dot
= radius = 10
= color = red
@@ -2030,6 +2045,7 @@ The tree following these rules will look like this:
= | Translate
= x = 80
= y = 0
+
= | Line
= length = 80
= color = red
@@ -2199,7 +2215,7 @@ Let's start with a record. Currently our {Code|segment} function takes three arg
=
= | Fold
= start = 22
- length = 66
+ length = 67
=
= | Code
= module Main exposing (main)
@@ -2288,6 +2304,7 @@ Let's start with a record. Currently our {Code|segment} function takes three arg
= ]
= []
=
+
=Not much changed. Instead of passing two separate values for {Code|color} and {Code|rotation} we pass one value with two named fields. That's a record!
=
=Why did I do it? That way I can store complete information about a segment in one value. I need this for the *dictionary* of rules.
@@ -2308,7 +2325,7 @@ Dictionary let's us associate one value (let's say color) with another value (le
=
= | Fold
= start = 48
- length = 55
+ length = 56
=
= | Code
= module Main exposing (main)
@@ -2412,6 +2429,7 @@ Dictionary let's us associate one value (let's say color) with another value (le
= ]
= []
=
+
=We have added an import statement for {Code|Dict} module and created a dictionary with two entries: one for {Code|"brown"} and one for {Code|"green"}. The values associated with these keys are a list of segment records. The meaning of this is following:
=
=| List
@@ -2428,11 +2446,11 @@ Here it is:
=
= | Fold
= start = 1
- length = 47
+ length = 48
=
= | Fold
- start = 67
- length = 36
+ start = 69
+ length = 38
=
= | Code
= module Main exposing (main)
@@ -2469,6 +2487,7 @@ Here it is:
= , Element.height Element.fill
= ]
=
+
= rules =
= Dict.empty
= |> Dict.insert "brown"
@@ -2482,6 +2501,7 @@ Here it is:
= , { color = "red", rotation = 50 }
= ]
=
+
= segment { color, rotation } =
= Svg.g []
= [ rules
@@ -2501,6 +2521,7 @@ Here it is:
= , line color rotation
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -2517,6 +2538,7 @@ Here it is:
= ]
= []
=
+
= line color rotation =
= Svg.line
= [ Svg.Attributes.strokeWidth "1"
@@ -2541,18 +2563,18 @@ We also have to change the definition of {Code|main}. Segment no longer takes tw
=| Editor
= | Annotations
= | Highlight
- top = 9
+ top = 10
= left = 4
= width = 47
= height = 1
=
= | Fold
= start = 1
- length = 5
+ length = 7
=
= | Fold
- start = 20
- length = 70
+ start = 23
+ length = 72
=
= | Code
= module Main exposing (main)
@@ -2562,6 +2584,7 @@ We also have to change the definition of {Code|main}. Segment no longer takes tw
= import Svg exposing (Svg)
= import Svg.Attributes
=
+
= main =
= [ segment { color = "brown", rotation = -90 } ]
= |> Svg.svg
@@ -2576,6 +2599,7 @@ We also have to change the definition of {Code|main}. Segment no longer takes tw
= , Element.height Element.fill
= ]
=
+
= rules =
= Dict.empty
= |> Dict.insert "brown"
@@ -2589,6 +2613,7 @@ We also have to change the definition of {Code|main}. Segment no longer takes tw
= , { color = "red", rotation = 50 }
= ]
=
+
= segment { color, rotation } =
= Svg.g []
= [ rules
@@ -2608,6 +2633,7 @@ We also have to change the definition of {Code|main}. Segment no longer takes tw
= , line color rotation
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -2624,6 +2650,7 @@ We also have to change the definition of {Code|main}. Segment no longer takes tw
= ]
= []
=
+
= line color rotation =
= Svg.line
= [ Svg.Attributes.strokeWidth "1"
@@ -2670,6 +2697,7 @@ The result should be exactly like we wanted it to be:
= color = green
= rotation = -30
=
+
= | Rule
= parent = green
= children =
@@ -2683,23 +2711,24 @@ The result should be exactly like we wanted it to be:
= color = red
= rotation = 50
=
+
=Nice, but what's going on here:
=
=| Editor
= | Annotations
= | Highlight
- top = 38
+ top = 41
= left = 12
= width = 23
= height = 3
=
= | Fold
= start = 1
- length = 34
+ length = 36
=
= | Fold
- start = 53
- length = 36
+ start = 57
+ length = 38
=
=
= | Code
@@ -2710,6 +2739,7 @@ Nice, but what's going on here:
= import Svg exposing (Svg)
= import Svg.Attributes
=
+
= main =
= [ segment { color = "brown", rotation = -90 } ]
= |> Svg.svg
@@ -2724,6 +2754,7 @@ Nice, but what's going on here:
= , Element.height Element.fill
= ]
=
+
= rules =
= Dict.empty
= |> Dict.insert "brown"
@@ -2737,6 +2768,7 @@ Nice, but what's going on here:
= , { color = "red", rotation = 50 }
= ]
=
+
= segment { color, rotation } =
= Svg.g []
= [ rules
@@ -2756,6 +2788,7 @@ Nice, but what's going on here:
= , line color rotation
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -2772,6 +2805,7 @@ Nice, but what's going on here:
= ]
= []
=
+
= line color rotation =
= Svg.line
= [ Svg.Attributes.strokeWidth "1"
@@ -2789,6 +2823,7 @@ Nice, but what's going on here:
= )
= ]
= []
+
=
=There are three new things here:
=
@@ -2825,18 +2860,18 @@ Take some time to grasp it and then compare with our code.
=| Editor
= | Annotations
= | Highlight
- top = 37
+ top = 40
= left = 12
= width = 41
= height = 13
=
= | Fold
= start = 1
- length = 35
+ length = 36
=
= | Fold
- start = 53
- length = 36
+ start = 56
+ length = 39
=
= | Code
= module Main exposing (main)
@@ -2846,6 +2881,7 @@ Take some time to grasp it and then compare with our code.
= import Svg exposing (Svg)
= import Svg.Attributes
=
+
= main =
= [ segment { color = "brown", rotation = -90 } ]
= |> Svg.svg
@@ -2860,6 +2896,7 @@ Take some time to grasp it and then compare with our code.
= , Element.height Element.fill
= ]
=
+
= rules =
= Dict.empty
= |> Dict.insert "brown"
@@ -2873,6 +2910,7 @@ Take some time to grasp it and then compare with our code.
= , { color = "red", rotation = 50 }
= ]
=
+
= segment { color, rotation } =
= Svg.g []
= [ rules
@@ -2892,6 +2930,7 @@ Take some time to grasp it and then compare with our code.
= , line color rotation
= ]
=
+
= dot color rotation =
= Svg.circle
= [ Svg.Attributes.r "10"
@@ -2908,6 +2947,7 @@ Take some time to grasp it and then compare with our code.
= ]
= []
=
+
= line color rotation =
= Svg.line
= [ Svg.Attributes.strokeWidth "1"
@@ -2926,6 +2966,7 @@ Take some time to grasp it and then compare with our code.
= ]
= []
=
+
=Let's analyze it line by line:
=
=| List
@@ -2989,7 +3030,7 @@ We can do it like this. When we create our first segment (the brown one), we wil
=
= | Fold
= start = 60
- length = 38
+ length = 39
=
= | Fold
= start = 22
@@ -3092,6 +3133,7 @@ We can do it like this. When we create our first segment (the brown one), we wil
= ]
= []
=
+
=On line 10 we pass the age to the {Code|segment} function as the first argument. The record is a second parameter now. The reason is that it makes mapping on line 47 easier. Age is the same for all the children (age of the parent minus 1).
=
=On line 39 we see something new. It's the {Code|if ... then ... else ...} expression. You can probably guess how it works: first we give it a condition (in this case {Code|age <= 0} - meaning that age is zero or less). That's our halting condition.
@@ -3190,7 +3232,7 @@ Since the size depends on the age, and the age is given for every segment, we ca
=
= | Fold
= start = 77
- length = 20
+ length = 22
=
= | Code
= module Main exposing (main)
@@ -3270,6 +3312,7 @@ Since the size depends on the age, and the age is given for every segment, we ca
= ]
= []
=
+
= line color rotation =
= Svg.line
= [ Svg.Attributes.strokeWidth "1"
@@ -3288,9 +3331,10 @@ Since the size depends on the age, and the age is given for every segment, we ca
= ]
= []
=
+
=Next let's pass the age to the {Code|line} function and use it for both the thickness ({Code|strokWidth}) and length ({Code|x2}).
=
-If you reload now, the tree will look as if it exploded. It's funny. The reason is that we did not adjust the translation of the child groups nor the dots. It's always 80, even though the length of the lines is variable - see lines {Code|53} and {Code|72}. Let's change it like that:
+If you click {Key|COMPILE} now, the tree will look as if it exploded. It's funny. The reason is that we did not adjust the translation of the child groups nor the dots. It's always 80, even though the length of the lines is variable - see lines {Code|53} and {Code|72}. Let's change it like that:
=
=| Editor
= | Annotationsindex fe7dc56..389479e 100644
--- a/content/day-5.txt
+++ b/content/day-5.txt
@@ -95,19 +95,19 @@ First let's change the value of {Code|main} and create the {Code|view} function,
=| Editor
= | Annotations
= | Highlight
- top = 10
+ top = 11
= left = 4
= width = 35
= height = 6
=
= | Highlight
- top = 18
+ top = 19
= left = 1
= width = 8
= height = 1
=
= | Fold
- start = 31
+ start = 32
= length = 81
=
= | Code
@@ -119,6 +119,7 @@ First let's change the value of {Code|main} and create the {Code|view} function,
= import Svg exposing (Svg)
= import Svg.Attributes
=
+
= main =
= Browser.element
= { init = init
@@ -302,6 +303,7 @@ And the complete code like this:
= left = 1
= width = 49
= height = 2
+
= | Fold
= start = 51
= length = 81index 4c3c26d..e2d25b1 100644
--- a/content/preparation.txt
+++ b/content/preparation.txt
@@ -1,109 +1,44 @@
=| Title
= Before the course begins
=
-During the workshop you will learn how to write and publish a computer program running in a web browser. Please follow this instructions before we start, so that we have more time to focus on programming. It shouldn't take you more than 30 minutes {Icon|name=watch} and can save us several hours together.
+During the workshop you will learn how to write and publish a computer program running in a web browser. Computer Programs are represented as text, so the text editor is the most fundamental tool of a programmer. We are going to use the Elm live editor called Ellie {Link|ellie-app.com|url=https://ellie-app.com} to write our code. When you open Ellie there will be a code, but you don't need that and please delete it. On Ellie, you write your codes on the left side (black screen) and the result is displayed on the right side (white screen). On the top left side of the black screen there are two buttons. {Icon|name=package} is for installing packages and {Icon|name=settings} is for adjusting settings. On the top right side of the black screen there is {Icon|name=align-left} we will use to format and make our code look pretty. After finishing writing a code we click {Key|COMPILE} (on the top right side of the white screen) to see the output.
=
-| Note
- This setup instructions are based on an assumption that you are using a Mac.
-
- If you are using Linux or BSD, then feel free to ask us for help.
-
- If you are using anything else (like Windows), then we are sorry, but we do not support your operating system. A Mac, Linux or BSD are required for the workshop. If you don't have one, we can advise you on getting and setting up a Linux machine.
-
-| Header
- Setup
-
-You will need
-
-| List
- - a Mac or Linux laptop,
- - a text editor (I use Atom)
- - and the Elm programming language
+Go to {Icon|name=settings} to give your project a name. Insert any name you wish. To save your work first click {Key|SAVE} and then bookmark it in your browser.
=
=| Header
- Installing Elm
-
-
-To install the Elm programming language, go to it's website:
-
-| Emphasize
- {Link|elm-lang.org|url=http://elm-lang.org/}
-
-
-and follow the installation instructions.
-
-Some of the tools we use with Elm require Node.js. Go to the {Link|Node.js|url=https://nodejs.org/en/} website and install the current version (the green button on the right)
-
-We will need to use the {Definition|term=terminal|definiens=a program that let's you enter commands for your computer} {Icon|name=terminal} a little bit. Open Launchpad (the icon with a rocket) and type {Code|terminal}, like this:
+ Our First Program!
=
-| Image
- src = /assets/mac-launchpad-terminal.png
- description = Here is a picture of terminal
+We are going to write "Hello Tree", but first let's install html package. Go to {Icon|name=package} and install html. Write the code as shown below.
=
+| Editor
+ | Annotations
+ | None
=
-Press {Key|enter} key or click the black icon with {Icon|name=terminal} sign. You should see a window similar to this:
+ | Code
+ module Main exposing (main)
=
=
-| Image
- src = /assets/mac-terminal-window.png
- description = A picture of Mac Terminal
+ import Html
=
-Type the following in the terminal.
+ main =
+ Html.text "Hello, Tree"
=
+Click {Icon|name=align-left} and then {Key|COMPILE} you should see something like this:
=
-| Terminal
- elm repl
+| Window
+ Hello, Tree!
=
-Then press the {Key|enter} key. Note that the command line changes. You should see something like this:
-
-| Terminal
- ---- Elm 0.19.0 --------------------------------------------------
- Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help
- ------------------------------------------------------------------
- >
-
-It's the Elm REPL (Read-Evaluate-Print Loop). Inside the REPL type.
-
-| Terminal
- 2+2
-
-| Note
- Press {Key|enter} again. Generally when we ask you to type something in a terminal, we imply that you press enter afterwards. That's how you signal that you are done typing and expect computer to process your command. Alternatively we call it entering a command.
-
-You should see:
-
-| Terminal
- ---- Elm 0.19.0 ----------------
- Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help
- --------------------------------
- > 2 + 2
- 4 : number
- >
-
-Easy, huh? We will learn more about REPL later. For now enter the following command to close it.
-
-| Terminal
- :exit
-
-The command line should get back to its initial state.
+This was a warmup. Let's try something more challenging on day 1.
=
=| Header
- Install Atom Text Editor
-
-Computer Programs are represented as text, so the text editor is the most fundamental tool of a programmer. There is a lot of good text editors, but to get you started, we will use Atom here.
-
-| Note
- If you are already using a text editor that you like, feel free to continue using it during the workshop.
-
-Go to {Link|atom.io|url=https://atom.io} and download the editor. After installation, open it and from {Code|Atom} menu choose {Code|Install Shell Commands}.
-
-One last thing we need is the Elm support for the Atom editor. You can install it by entering the following command in the terminal:
+ Setup
=
-| Terminal
- apm install language-elm
+You will need
=
-| Note
- APM is the Atom Package Manager, but don't pay much attention to it. We won't be using it again.
+| List
+ - A Laptop
+ - Mozilla firefox or Chrome browser
+ - Internet connection
=
=| Emphasize
= Congratulations! We are all set and you are ready for {Link|Day 1|url=/day-1.html}!Edited Fold block on day 2.
On by
index f2fbb4c..26e0ab6 100644
--- a/content/day-2.txt
+++ b/content/day-2.txt
@@ -42,7 +42,7 @@ First obvious difference is that now we have multiple dots. The only dot we have
=
= | Fold
= start = 17
- length = 12
+ length = 13
=
=
= | Code
@@ -86,7 +86,7 @@ If you look closely in your source code, the block above is surrounded by {Code|
=
= | Fold
= start = 24
- length = 12
+ length = 13
=
= | Code
= module Main exposing (main)Edit Fold block on day 2.
On by
index f2fbb4c..26e0ab6 100644
--- a/content/day-2.txt
+++ b/content/day-2.txt
@@ -42,7 +42,7 @@ First obvious difference is that now we have multiple dots. The only dot we have
=
= | Fold
= start = 17
- length = 12
+ length = 13
=
=
= | Code
@@ -86,7 +86,7 @@ If you look closely in your source code, the block above is surrounded by {Code|
=
= | Fold
= start = 24
- length = 12
+ length = 13
=
= | Code
= module Main exposing (main)Add workshop dates to test-run.
On by
index 00ea641..9a06486 100644
--- a/content/test-run.txt
+++ b/content/test-run.txt
@@ -3,6 +3,13 @@
=
=In collaboration with {Link|Career Services|url=https://students.uu.nl/en/careerservices} of the University of Utrecht we are offering a one time, free workshop for the first 12 students to sign up. The workshop will be shorter than usual - 3 hours a day.
=
+| Note
+ 04 March 2019: /Marinus Ruppert Room 029/ Time *16:00* - *19:00*
+ 05 March 2019: /Marinus Ruppert Room 005/ Time *16:00* - *19:00*
+ 06 March 2019: /Marinus Ruppert Room 031/ Time *16:00* - *19:00*
+ 07 March 2019: /Marinus Langeveld Room G230/ Time *16:00* - *19:00*
+ 08 March 2019: /Marinus Ruppert Room 121/ Time *16:00* - *19:00*
+
=| Emphasize
= {Link|Sign up now|url=https://fd21.formdesk.com/universiteitutrecht/CS-20190304-08-SoftwareGarden}
=Merge branch 'workshop-dates' into 'master'
On by
Add workshop dates to test-run.
See merge request software-garden/software-garden.gitlab.io!24
Merge branch 'rewrite-content-ellie' of gitlab.com:software-garden/software-garden.gitlab.io into rewrite-content-ellie
On by
Change code Terminal to code Elm Repl on day 3 and day 4.
On by
Put Fana's bio before Sam.
Change widget terminal to elmRepl in Mark.Custom.
Change terminal to elmRepl in Mark/Custom so we can use the online Elm Repl.
index 19b53ef..e6dd358 100644
--- a/content/day-3.txt
+++ b/content/day-3.txt
@@ -28,7 +28,7 @@ For efficiency we are going to play with these concepts in REPL (the Read - Eval
=
=It should show something like this
=
-| Terminal
+| ElmRepl
= ---- Elm 0.19.0 ----------------------------------------------------------------
= Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
= --------------------------------------------------------------------------------
@@ -41,7 +41,7 @@ Here you can enter snippets of Elm code and see it evaluated.
=
=Let's start with values. The simplest way to create a value is to literally type it in our code. Try it (type things after {Code|>} and expect to see what follows):
=
-| Terminal
+| ElmRepl
= > 2
= 2 : number
= > "Hello"
@@ -52,7 +52,7 @@ These expressions ({Code|2} and {Code|"Hello!"}) are called /literals/, because
=
=Some value literals are simple, like numbers and strings. Some are complex. Previously we have touched the subject of lists. You can also type them literally, like this:
=
-| Terminal
+| ElmRepl
= > [ 1, 2, 5, 77, 2 ]
= [1,2,5,77.6,2] : List number
=
@@ -63,13 +63,13 @@ First notice that a list literal starts with {Code|[} and ends with {Code|]}. In
=
=List can be empty:
=
-| Terminal
+| ElmRepl
= > []
= [] : List a
=
=or contain only one element:
=
-| Terminal
+| ElmRepl
= > [ "Hello" ]
= ["Hello"] : List String
=
@@ -78,7 +78,7 @@ or contain only one element:
=
=Now let's focus our attention to *names*. If you have a value, you can give it a name.
=
-| Terminal
+| ElmRepl
= > kittens = 2
= 2 : number
= > greeting = "Hello!"
@@ -87,7 +87,7 @@ Now let's focus our attention to *names*. If you have a value, you can give it a
=
=From now on you can refer to this value either literally or by its name:
=
-| Terminal
+| ElmRepl
= > kittens
= 2 : number
= > 2
@@ -95,19 +95,19 @@ From now on you can refer to this value either literally or by its name:
=
=The effect will be exactly the same - you will get a value back. So we see that there are at least two ways of getting values: by literally expressing them or referring to them by names given to them previously. In a composite value of a list, you can mix the two ways together:
=
-| Terminal
+| ElmRepl
= > [ 1, kittens, 3 ]
= [1,2,3] : List number
=
=A *function* is a special kind of a value. Let's create a named function like this:
=
-| Terminal
+| ElmRepl
= > fun something = something ++ " is fun!"
= <function> : String -> String
=
=Here we gave a name {Code|fun} to a function, that given {Code|something} will produce a string saying that this {Code|something} is fun! Let's see how you can use it:
=
-| Terminal
+| ElmRepl
= > fun "Learning Elm"
= "Learning Elm is fun!" : String
=
@@ -129,13 +129,13 @@ Not every function can be applied to any value. You can add two numbers (like {C
=
=Every value in Elm has a type. You can see the type in the REPL - after evaluating the expression it shows its value and the type, like here:
=
-| Terminal
+| ElmRepl
= > kittens
= 2 : number
=
=Above {Code|2} is the value and `number` is the type. Similar here:
=
-| Terminal
+| ElmRepl
= > fun "Learning Elm"
= "Learning Elm is fun!" : String
=
@@ -143,19 +143,19 @@ The value is {Code|"Learning Elm is fun!"} and the type is {Code|String}.
=
=Composite values like lists have composite types. For example here the type is {Code|List String}.
=
-| Terminal
+| ElmRepl
= > [ "Hello", "Good bye" ]
= ["Hello","Good bye"] : List String
=
=This means that it's a list of strings. All the elements of this list are of type {Code|String}. When talking about lists you have to tell that it's a list and what is the type of its elements. Only this can be considered a fully specified type. Compare:
=
-| Terminal
+| ElmRepl
= > [ 1, 2, 3 ]
= [1,2,3] : List number
=
=This is a list of numbers. It's easy to see - all the elements are numbers, just as previously they were strings. All the elements of a list must be of the same type. If you try mixing the types, Elm will refuse to build your program. Try:
=
-| Terminal
+| ElmRepl
= > [ 1, 2, 3, "Carrot" ]
= -- TYPE MISMATCH ----------------------------------------------------------- elm
=
@@ -179,7 +179,7 @@ This is a list of numbers. It's easy to see - all the elements are numbers, just
=
=What's the type of an empty list? Let's see:
=
-| Terminal
+| ElmRepl
= > []
= [] : List a
=
@@ -190,13 +190,13 @@ A list of {Code|a}. Obviously {Code|a} is not a type. This means that the type o
=
=Above I said that every value has a type and also that a function is a value on its own. Let's try the following in REPL:
=
-| Terminal
+| ElmRepl
= > fun
= <function> : String -> String
=
=We have asked the REPL to tell as the value referenced by name {Code|fun}. In response the REPL display the value as {Code|<function>}. That's because there is no simple way to represent the value of a function as text. Let's focus our attention on the type (part after the colon {Code|:}). It is {Code|String -> String}. This means that the type is a function (we recognize it by the arrow symbol). What's before the arrow is a type of the value that goes into the function (called the /argument of the function/). The type of the argument is {Code|String}. That shouldn't be a surprise. Remember how we have used the function before to produce the value:
=
-| Terminal
+| ElmRepl
= > fun "Learning Elm"
= "Learning Elm is fun!" : String
=
@@ -206,19 +206,19 @@ The part after the arrow symbol is the type that the function returns. It is als
=
=Not every function returns the same type as it takes. For example the function {Code|String.fromInt} takes a value of type {Code|Int} and returns a value of type {Code|String}. Its type is therefore {Code|Int -> String}. We read it as: /type of String.fromInt is a function from Int to String/. Let's see it in action:
=
-| Terminal
+| ElmRepl
= > String.fromInt 10
= "10" : String
=
=That's right! The value {Code|10} is an {Code|Int}, the value {Code|"10"} is a {Code|String}.
=
-| Terminal
+| ElmRepl
= > String.fromInt
= <function> : Int -> String
=
=But what if we want to say that a certain number (say, {Code|232}) is fun? We have our {Code|fun} function, but it takes a {Code|String} and what we have is an {Code|Int}. We can use the very same {Code|String.fromInt} to first convert it into the {Code|String} and then pass the value to the {Code|fun} function, like this:
=
-| Terminal
+| ElmRepl
= > fun (String.fromInt 232)
= "232 is fun!" : String
=
@@ -226,7 +226,7 @@ We had to put the {Code|String.fromInt 232} expression in parentheses, so that E
=
=Alternatively we can use the pipe operator which looks like this: {Code|\|>}. It has the advantage that the transformations that happen first are on the left side and ones that happen later on the right. We can read our code left to right instead of inside out. Here is how it would look like:
=
-| Terminal
+| ElmRepl
= > 232 |> String.fromInt |> fun
= "232 is fun!" : String
=
@@ -239,12 +239,12 @@ But what are functions good for? They are very good for making similar values th
=
=We don't have to create all the functions that we need. There are thousands of them already defined and we can use them by importing modules. We already did that. First you import a module like this:
=
-| Terminal
+| ElmRepl
= > import String
=
=And then use any name that it exposes, like this
=
-| Terminal
+| ElmRepl
= > String.fromInt 10
= "10" : String
=
@@ -845,7 +845,7 @@ and another is:
=
=Elm won't have that. Fortunately there is an easy way to satisfy the type system. The {Code|String.fromFloat} takes a {Code|Float} and gives a {Code|String}. Try it in the REPL:
=
-| Terminal
+| ElmRepl
= > String.fromFloat
= <function> : Float -> String
=index 5cf6d1a..497fe17 100644
--- a/content/day-4.txt
+++ b/content/day-4.txt
@@ -2823,7 +2823,7 @@ Nice, but what's going on here:
= )
= ]
= []
-
+
=
=There are three new things here:
=
@@ -2840,7 +2840,7 @@ But what if the entry for a given key is not there? For example we have not inse
=
=If there is an entry, we will get a list of records. We want a list of segments. Each of the records can be passed to the {Code|segment} function to produce one segment. That's where {Code|List.map} comes in. Given a list and a function it will call the function with each of the elements in the list and give back the list of produced values. Let's see a simpler example in the REPL:
=
-| Terminal
+| ElmRepl
= > fun something = something ++ " is fun!"
= <function> : String -> String
= > fun "Learning Elm"index 79e54bd..527240c 100644
--- a/content/index.txt
+++ b/content/index.txt
@@ -48,6 +48,6 @@ You can learn more about {Link|our motivation|url=/motivation.html}. Below is ma
=
=I love the creativity of the software development and hope to share that passion with you.
=
-*Sam* is a co-author of the workshop. He is an Elm developer at {Link|itravel|url=https://www.itravel.de/} in Cologne, Germany.
-
=*Fana* is a junior software developer (an ex marine biologist {Icon|name=anchor}) and coordinator of our project. She keeps us on the right track. Also she is taking care of our media presence.
+
+*Sam* is a co-author of the workshop. He is an Elm developer at {Link|itravel|url=https://www.itravel.de/} in Cologne, Germany.index 499cdc9..e4c7f4c 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -799,7 +799,7 @@ document =
=
= widgets =
= [ Mark.Custom.editor
- , Mark.Custom.terminal
+ , Mark.Custom.elmRepl
= , Mark.Custom.note
= ]
=index 745e5af..88c3af4 100644
--- a/src/Mark/Custom.elm
+++ b/src/Mark/Custom.elm
@@ -1,6 +1,7 @@
=module Mark.Custom exposing
= ( colors
= , editor
+ , elmRepl
= , emphasize
= , header
= , icon
@@ -11,7 +12,6 @@ module Mark.Custom exposing
= , note
= , paragraph
= , row
- , terminal
= , text
= , title
= , window
@@ -215,8 +215,8 @@ editor =
= )
=
=
-terminal : Mark.Block (a -> Element msg)
-terminal =
+elmRepl : Mark.Block (a -> Element msg)
+elmRepl =
= let
= render content model =
= Element.column
@@ -250,7 +250,7 @@ terminal =
= , Font.monospace
= ]
= ]
- (Element.text "terminal")
+ (Element.text "Elm Repl")
= ]
= , content
= |> String.split "\n"
@@ -276,7 +276,7 @@ terminal =
= ]
= ]
= in
- Mark.block "Terminal"
+ Mark.block "ElmRepl"
= render
= Mark.multiline
=Remove import String from Elm Repl on day 3.
On by
index e6dd358..7389e27 100644
--- a/content/day-3.txt
+++ b/content/day-3.txt
@@ -237,18 +237,7 @@ But what are functions good for? They are very good for making similar values th
=| Note
= Just like machines for painting eggs are useful if you have a lot of eggs to paint. If you only need one or two painted eggs, then it's probably better to just get them painted. But if you have thousands, maybe it's worth to build a machine for it.
=
-We don't have to create all the functions that we need. There are thousands of them already defined and we can use them by importing modules. We already did that. First you import a module like this:
-
-| ElmRepl
- > import String
-
-And then use any name that it exposes, like this
-
-| ElmRepl
- > String.fromInt 10
- "10" : String
-
-If the name comes from an imported module, you need to prefix it with the name of the module, like we did above.
+We don't have to create all the functions that we need. There are thousands of them already defined and we can use them by importing modules.
=
=Let's look at our code and try to recognize some literal values, lists, names and functions. Here is how it should look after day 2:
=