Calling an external API from Phoenix app

Last week I wrote about how to extend your Ecto model. I wanted to figure it out because I thought this week, I’ll add to mother other flight related data. Turns out, I did it in completely different way. Not sure if this is the correct approach, so feel free to bash mi in comments (in a constructive way!).

One of the data I have on my flights so far is a departure and destination airport IATA code. Those are 3 letters code, commonly used in civil aviation (SFO = San Francisco, CPH = Copenhagen etc.).  I wanted to use some simple API to get more data based on this code. So I decided to write my own using Azure Functions and F#. It became a separate adventure. I’ll write another post about it.

When I had my API ready, I started figuring out, how to put it in Phoenix app. My first approach was a bit like you do stuff in ASP.NET MVC – adding those extra fields to the model, and trying to update them from within the controller. Unfortunately, I couldn’t make it work. I couldn’t even access fields of the model.

The solution I ended up doing, is putting all the web calls and logic for parsing them within the view file. It feels dirty for me. It would be very dirty in ASP.NET MVC. So my intuition is, that it’s not the best way to do it. But so far the only one I made working. After those changes my Flight view file looks like that:

https://gist.github.com/mlusiak/b00a756b891e701354cba66fae55bd78

And then I use those functions within the template that renders the view:

https://gist.github.com/mlusiak/ecb3acf26baaad25d32f78af89080319

Immediately you can see another problem with the code – for every information that I want to show, I’m making a separate web request. But it works, which is a huge improvement. Done is better than perfect.

Screenshot to prove that it does, what it should:

Screen Shot 2017-04-16 at 01.52.21.png

 

That’s all for today. Tune in next week for another part. Also, check previous episodesAnd if you’re interested in machine learning, look into my weekly link drop.

Weekly ML drop #7

I’ve become more and more interested in machine learning during last year. This is my way of collecting and sharing interesting reads on the topic I stumble upon. Those posts are published each Friday, they are divided into few categories and the format is constantly evolving.

News
In this part, I share interesting news from machine learning and artificial intelligence world. Those are mostly not very scientific articles about interesting applications,  predictions and controversies that AI causes.

Exploring the mysteries of Go with AlphaGo and China’s top players
AlphaGo together with Chinese Go Association is bringing together the most talented Go players and computer scientist to explore deeper into the game. Turns out, that last year victory of AlphaGo over human player totally changed how humans play this game.

Who will pay insurance in the era of self-driving cars?
This article discusses impact self-driving cars may have on the insurance industry. As it is suggested currently by analysts, and some first legislation follows, car makers may be responsible for that cost.

Why deep learning is suddenly changing your life?
Just another article that discusses what exactly happened in recent years, that machine learning seems to be everywhere and changing everything. It also explains basic terms and methods used in the field.

AI based hedge fund created a new currency
The article, with a bit sensationalist title, discuss new fintech startup Numerai, that uses open market for AI algorithms to make its trading decisions and rewarding authors of the best algorithms.

How predictive AI will change shopping
The author of this texts brings up few examples how AI revolution impacts the retail world. Thanks to better data collections, connected devices and putting this data together, retail companies can offer better suggestions, increasing their profits.


Learning materials

Here I’m sharing material for learning ML that I found useful – online courses, blogs, books etc. This is usually rather technical stuff.

Artificial Intelligence and the Growing Importance of Soft Skills
Very interesting read about which skills are endangered and which not by AI. If you want to prepare for robots taking your job, that’s a good start.

Introduction to Machine Learning
This short video from Intel Nervana AI academy explains basic terms of Machine Learning and most popular types of it.

Stanford series on Natural Language Processing with Deep Learning
Another academic source of knowledge. I haven’t had time to dig into it, but quick skimming suggests, that’s another amazing 20hrs of the content of ML knowledge, this time targeted at NLP.


This is it for today, thanks for reading. If you liked the post, let me know and please check other parts of the series.

Extending your Ecto model

Last week I used Ecto models to quickly created the database and I was very surprised how all got generated for me. But the model I build was very simplistic, and now I need to extend it. I started working on first serious functionality for the project, and I’ll have to do some changes. For start, I’m just testing by adding one field.

I generated new migrations file in /priv/repo/migrations folder and a bit by trial and error I end up with file like that:

defmodule Flightlog.Repo.Migrations.CreateFlight do
  use Ecto.Migration

  def change do
    alter table(:flights) do
      add :plane_type, :string
    end

  end
end

And after running mix ecto.migrate, I actually got some results:

Michals-MBP:flightlog michal$ mix ecto.migrate
01:01:37.663 [info]  == Running Flightlog.Repo.Migrations.CreateFlight.change/0 forward
01:01:37.663 [info]  alter table flights
01:01:37.666 [info]  == Migrated in 0.0s

This worked for adding fields to the database but didn’t automagically update all the access layers. There’s probably some way to it, but this time I did it manually.

First I updated the views, for example added following into show.html.eex:

https://gist.github.com/mlusiak/0979cb46187ee75cd724190e09aa96c1

This solved the visuals but still didn’t work. The crucial were changes in the model:

  defmodule Flightlog.Flight do
  use Flightlog.Web, :model

  schema "flights" do
    field :date, Ecto.DateTime
    field :flight_number, :string
    field :plane_type, :string
    field :from, :string
    field :to, :string

    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:date, :flight_number, :plane_type, :from, :to])
    |> validate_required([:date, :flight_number, :plane_type, :from, :to])
  end
end

I added new field both in schema part and in changeset. Cast is responsible for things being updated. I didn’t have to add it to be validates as required.

So this was actually a bit tedious, but I’m probably missing something here. Hopefully I’ll figure it out by the time I’ll need to make bigger changes.

I also found this post, that’s deal with similar problem.

That’s all for today. Tune in next week for another part. Also, check previous episodesAnd if you’re interested in machine learning, look into my weekly link drop.

Weekly ML drop #6

I’ve become more and more interested in machine learning during last year. This is my way of collecting and sharing interesting reads on the topic I stumble upon. Those posts are published each Friday, they are divided into few categories and the format is constantly evolving.

Accidentally this week, I also have a theme. Most articles are related to impact on workplaces and how companies work.

News
In this part, I share interesting news from machine learning and artificial intelligence world. Those are mostly not very scientific articles about interesting applications,  predictions and controversies that AI causes.

Axa is using ML to predict big car accident with 78% accuracy
In this article on Google Platform blog, the case of a big insurance company is discussed. What technology was used and how it worked.

How automation impacts economy?
This post discusses potential outcomes of more and more automation in modern economies.

Artificial intelligence could dramatically improve the economy and aspects of everyday life, but we need to invent ways to make sure everyone benefits.

How AI is transforming workplace
Discussion of multiple aspects of workplace and how machine learning and other AI-related technologies may change them.

How AI is changing the way companies are organised
This article brings up some examples how introducing ml tools may change how companies are structured and how internal communication is performed.

Machine learning used to smart compression of videos
Netflix uses new machine learning based algorithm to compress video scene by scene for better results.

Opinions of 17 experts, how worried we should be about AI


Learning materials

Here I’m sharing material for learning ML that I found useful – online courses, blogs, books etc. This is usually rather technical stuff.

In-depth, non-technical guide to machine learning
This five-part article goes through terms and techniques used in machine learning in human-friendly language. Very good first contact with anything machine-learning related.


This is it for today, thanks for reading. If you liked the post, let me know and please check other parts of the series.

Connecting to database with Ecto

In the last episode of my Elixir adventures, I messed with own-made Views and Controller to display hardcoded flight information for my FlightLog. This week I’ll try to show data based on the content of the database.

Phoenix doesn’t have built-in data access capabilities. But there’s awesome Ecto project, that’s sort of beefed up ORM. It reminds me Entity Framework (or good parts of it) in .NET or Rails. It supports multiple databases, although the default is Postgres. If you generated your Phoenix project by default and didn’t exclude Ecto, you should have everything you need to start. If no, refer to this guide

To add data access to FlightLog, I started the way, I would usually do in a web project. I installed the database (I went with Postgres), created some table, inserted some sample data. It was proven later, that it wasn’t a necessary step.

To build your first model, go to your project root and type for example:

$ mix phoenix.gen.html Flight flights date:datetime flight_number:string from:string to:string
* creating priv/repo/migrations/20150409213440_create_flight.exs
* creating web/models/flight.ex
* creating test/models/flight_test.exs
* creating web/controllers/flight_controller.ex
* creating web/templates/flight/edit.html.eex
* creating web/templates/flight/form.html.eex
* creating web/templates/flight/index.html.eex
* creating web/templates/flight/new.html.eex
* creating web/templates/flight/show.html.eex
* creating web/views/flight_view.ex
* creating test/controllers/flight_controller_test.exs

Add the resource to your browser scope in web/router.ex:

    resources "/flights", FlightController

and then update your repository by running migrations:

    $ mix ecto.migrate

As you can see, this gave me a lot of stuff – a migration, a controller, a controller test, a model, a model test, a view, and a number of templates. It also instructs as to add new Controller to the router. Let’s do that.

I also removed recent additions, because they served the same purpose. I initially though I’ll just edit them, but Ecto surprised me by doing everything for me. Updated route file looks like that:

defmodule Flightlog.Router do
  use Flightlog.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", Flightlog do
    pipe_through :browser # Use the default browser stack

    resources "/flights", FlightController
  end

  # Other scopes may use custom stacks.
  # scope "/api", Flightlog do
  #   pipe_through :api
  # end
end


After that I run mix ecto.migrate which executed migration file:

defmodule Flightlog.Repo.Migrations.CreateFlight do
  use Ecto.Migration

  def change do
    create table(:flights) do
      add :date, :datetime
      add :flight_number, :string
      add :from, :string
      add :to, :string

      timestamps()
    end

  end
end


This created tables for me as defined in phoenix.gen.html. I noticed that database has some extra fields for basic journaling like inserted_at and updated_at. I logged into the database and added some data just to have something to show and fired up my project again:

mix phoenix.server

When you browse to the site, you’ll notice that not only I have a list of flights, but also buttons for actions like Edit, Delete or Add a new item. All generated for me and even with decent styling. That was a very nice surprise.

Screen Shot 2017-04-06 at 13.00.42.png

So first look at Ecto is very positively surprising. It created all the boilerplate code for me, but it is also a code that’s understandable and easy to edit. There seem not to be any underlying magic. If I need to change default behaviour I feel I wouldn’t have much problem doing that. We’ll see in future if practice will support those claims.

I haven’t covered any of the internals how Ecto works, so if you’re interested I suggest you peek into this guide and official documentation.

That’s all for today. Tune in next week for another part. Also, check previous episodesAnd if you’re interested in machine learning, look into my weekly link drop.

Weekly ML drop #5

I’ve become more and more interested in machine learning during last year. This is my way of collecting and sharing interesting reads on the topic I stumble upon. Those posts are published each Friday, they are divided into few categories and the format is constantly evolving.

This week I gathered a lot of articles on the topic of AI for self-driving cars and this will be a theme for this edition.

News
In this part, I share interesting news from machine learning and artificial intelligence world. Those are mostly not very scientific articles about interesting applications,  predictions and controversies that AI causes.

Artificial Intelligence will enable jobs too
Usually, in the context of AI, you can hear predictions of people losing jobs. In this story about IBM “new collar” jobs, we can read that company is aiming at hiring people uneducated in cyber security who have necessary set of natural skills, and augment them with technology to fill lackings in professional skills.

Intel forms new AI division
Intel’s been behind Nvidia in developments of processing units that power AI revolution. Recent acquisitions mentioned last week and forming new group shows that they’re not gonna give up easily. In a similar move, YCombinator is gonna run experimental vertical group focused on AI in next batch of founded startups.

Andrew Ng leaves Baidu
He’ll now focus on “shepherding this important societal change”. He also wants to support ML community around the world. I love the quote from his blog.

Just as electricity transformed many industries roughly 100 years ago, AI will also now change nearly every major industry — healthcare, transportation, entertainment, manufacturing — enriching the lives of countless people. I am more excited than ever about where AI can take us. — Andrew Ng

Agents in OpenAI research develop their own language
In this blog post, OpenAi discusses some results from the research that aimed at teaching AIs developing a new language of communication “by dropping them into a set of simple words, giving them the ability to communicate, and then giving them goals that can be best achieved by communicating with other agents”.

Learning materials
Here I’m sharing material for learning ML that I found useful – online courses, blogs, books etc. This is usually rather technical stuff.

Algorithmia’s not very heavy intro to Deep Learning
This is not very heavy article explaining on a high level what Deep Learning is.

Convolutional Neural Networks
Recently in my learnings, I was exploring the topic of CNNs. This is a type of neural networks that are very good at image recognition tasks. This series of articles going through interesting papers on the field and this papers were especially interesting. I highly recommend them if you’re interested in the topic.

This is it for today, thanks for reading. If you liked the post, let me know and please check other parts of the series.

Weekly ML drop #4 – self-driving cars

I’ve become more and more interested in machine learning during last year. This is my way of collecting and sharing interesting reads on the topic I stumble upon. Those posts are published each Friday, they are divided into few categories and the format is constantly evolving.

This week I gathered a lot of articles on the topic of AI for self-driving cars and this will be a theme for this edition.

News
In this part, I share interesting news from machine learning and artificial intelligence world. Those are mostly not very scientific articles about interesting applications,  predictions and controversies that AI causes.

Some of those are not “news” anymore, as I have a long backlog of them saved. They are all very interesting, though!

Would you buy a car that’s programmed to kill you?
In this article, the author discusses some moral issues related to how self-driving cars will behave in death-threatening situations. If you want to test how your set of morals compare to others, check out this survey.

How Drive.ai Is Mastering Autonomous Driving With Deep Learning
This interesting piece takes a ride with drive.ai. This Silicon Valley company has a different approach than most others autonomous drive providers. Instead of using AI just for vision and understanding surrounding and using a rule-based approach to making decisions, they apply deep learning to the whole process of driving.

Self-driving trucks
I recently learned, that truck driver is the most common occupation in the United States. Over 1.7 million people drive all sizes of trucks to deliver goods across the country. The article looks into how knowledge gathered by testing self-driving cars translate to trucks and how the rise of this technology will affect the truckers.

Tesla Drivers Are Paying Big Bucks to Test Flawed Self-Driving Software
Looks like the reality of Tesla’s autopilot is slightly more complicated than promotional videos show. And you need to pay extra to take part in the test program. It may be due to fact that Tesla opted out from using Lidar technology and their autopilot is based solely on cameras. Also check out this youtube channel, that documents evolution of the Autopilot on the same local road.

Intel, Mobileye, and Smiling Curves
Read how recent Intel’s acquisition of Israeli self-driving technology startup fits into technology economy theory called “Smiling Curves”.

Learning materials
Here I’m sharing material for learning ML that I found useful – online courses, blogs, books etc. This is usually rather technical stuff.

Deep Learning for Self-driving Cars @ MIT
This winter MIT offered open lectures about Deep Learning for self-driving cars. If you were in the area, you could sign-up and come for free. Those lectures were recorded and successively published. Now the whole series is complete and available online.

This is it for today, thanks for reading. If you liked the post, let me know and please check other parts of the series.

Adding new routes in Phoenix

This is another part of my series on learning Elixir.

Last week I mixed new Phoenix project and looked how different parts of framework fit together. This week I started adding my own routes and pages. I followed the official guide but altered it a bit to better fit my application.

Adding a Route
First things to change, when you’re adding new pages, is the router.ex file, that sits in the web folder in your project. All of the work today will be contained within web folder. To add a new route, simply add a new line within the existing scope. We’ll talk more about scopes in one of the future episodes.

  scope "/", Flightlog do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    get "/flights", FlightsController, :index
  end

What the new Route says is, when browser hits /flights path, index action of FlightsController controller will be executed. Or in other words, this routes maps GET request for /flights to the index action of FlightsConroller. This won’t work because this controller doesn’t exist yet. Let’s fix it!

Adding a Controller
The Controller is very similar to the one I created last week. Nothing new here. We have index function that renders index.html view.

defmodule Flightlog.FlightsController do
  use Flightlog.Web, :controller

  def index(conn, _params) do
    render conn, "index.html"
  end
end


Adding a View and a Template
As you can see below, I added some code to the Template. I’m quite sure that it should be handled in View, but for now, I hard coded it this way. Below flights_view.ex and index.html.eex:

defmodule Flightlog.FlightsView do
  use Flightlog.Web, :view
end

https://gist.github.com/mlusiak/059a840dcf17493e50c215b54f2dcdc4

You can also see reference to the path /flights/1 that has not been declared. Let’s do it now.

Adding another Route, Controller and Template
I pasted below the code for all three files, marking changes in bold.

defmodule Flightlog.Router do
  use Flightlog.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", Flightlog do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    get "/flights", FlightsController, :index
    get "/flights/:id", FlightsController, :show
  end

  # Other scopes may use custom stacks.
  # scope "/api", Flightlog do
  #   pipe_through :api
  # end
end
defmodule Flightlog.FlightsController do
  use Flightlog.Web, :controller

  def index(conn, _params) do
    render conn, "index.html"
  end

  def show(conn, %{"id" => id}) do
    render conn, "show.html", id: id
  end
end

https://gist.github.com/mlusiak/91f2ab3d668f89d2f8056eb0582a32ca

There were no changes in flights_view.ex.

There are some important things happening here. In Router, I pattern match against the params passed into the show function so that the id variable is bound to the value we put in the :id position in the URL. For example, if our URL is http://localhost:4000/flights/1, the id variable would be bound to 1.

In Template, I again hard coded some logic. There are for sure better ways to do it, but it works for now. It’s worth mentioning, that id passed is a string! I debugged this for an hour while comparing to integer 1 and couldn’t figure out why it doesn’t work ;). Everyday you learn something new. And the effects:

http://localhost:4000/flights/1

Screen Shot 2017-03-21 at 23.51.09.png

http://localhost:4000/flights/2

Screen Shot 2017-03-21 at 23.51.29.png

As you can see it’s all rendered within parent template. I’m not gonna get bothered by this at this point.

If you want to read more about Templates, again official guide is fantastic. I also stumbled upon this very interesting blog post that explains that Templates are just functions.

Thanks for reading this another part of my adventures with Elixir and Phoenix. Come next week for more. And if you’re interested in machine learning, look into my weekly link drop. on that topic.

First look at Phoenix

This week I decided to push some things in the project. Instead of looking into the internals of Elixir and Erlang VM, let’s actually do something. My project for DSP competition is a web application, and most popular framework for web development in Elixir is called Phoenix. Phoenix use as it’s foundation Erlang’s HTTP server – Cowboy. I’m not gonna look into it right now, I don’t think it will be necessary at this point.

More important for now will be knowledge what is Plug. It is a specification for constructing modules, that can be composed together and configure how web applications behave. Modules and functions that are built to this specification are called Plugs. Plugs can be chained together to create pipelines and can handle nearly everything, i.e. authentication or parameter pre-processing. To learn more look into this guide.

Thanks to Plugs, Phoenix doesn’t have a need for a monolithic middleware. And you can customise every step of handling a request. Let’s look at the elements that handle a request up to rendering, step by step.

The Endpoint is responsible for handling request until the moment that routes take over. Which includes starting server, applying the configuration and also applying a set of plugs that are common for all requests.

The Router is responsible for a few things. First of all, it parses incoming requests and sends them to appropriate Controller and Action. You can also create Pipelines here, which are sequences of Plugs, that can be easily applied to routes. So on top of common plugs, you can add your own. For example, to differently handle requests that will be rendered in a browser, vs. API requests.

Controllers do what they usually do in MVC model. They provide actions, which may prepare data for views, render stuff (through Views) on screen or do redirects.

Views are presentation layer. They’re rendered based on Templates. Templates in Elixir are precompiled, which makes them very fast.


Code
Armed with those basics, let’s look at some code that’s generated when you start Phoenix project.

First what I did is mix new Phoenix project instead of previous one.

$ mix phoenix.new hello_phoenix

This caused some havoc in my repository but  I managed to clean it up. After this and few other steps, like setting up a database, I could start it up.

$ mix phoenix.server

After that I could navigate to http://localhost:4000/ to see my first Phoenix application:

phoenix after start.png

Let’s take a look, how default Router looks like:

defmodule Flightlog.Router do
  use Flightlog.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", Flightlog do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  # scope "/api", Flightlog do
  #   pipe_through :api
  # end
end

You can notice declared separate pipelines for browser and API. The one for browsers has accept-headers for HTML, handles session and adds anti-forgery tokens. One for API is much simpler. Then inside of scope (which is out of the scope of this post :P) you can see this pipeline applied and route for “/” declared that will trigger PageController’s action named :index.

defmodule Flightlog.PageController do
  use Flightlog.Web, :controller

  def index(conn, _params) do
    render conn, "index.html"
  end
end


This renders a view based on template located in file index.html.eex.

Next week I’ll start working on the code and adjust the routes for my own needs.


More resources

If you interested into looking Phoenix yourself, their documentation is very good, especially the guides. I also watched this video from 2015 NDC Oslo by the creator of Phoenix, Chris McCord. It gave me good overview how things work in Phoenix.

Thanks for reading this another part of my adventures with Elixir and Phoenix. Come next week for more. And if you’re interested in machine learning, look into my weekly link drop.

Weekly Machine Learning drop #3

I’ve become more and more interested in machine learning during last year. This is my way of collecting and sharing interesting reads on the topic I stumble upon. Those posts are published each Friday, they are divided into few categories and the format is constantly evolving.

News
In this part, I share interesting news from machine learning and artificial intelligence world. Those are mostly not very scientific articles about interesting applications,  predictions and controversies that AI causes.

Some of those are not “news” anymore, as I have a long backlog of them saved. They are all very interesting, though!

Google acquires Kaggle
Kaggle is a platform for solving machine learning problems. As a company, you can publish your problem with sample dataset and pay people the or best solution of your problem. There are also practice tasks, for example analysing Titanic data. Last week Google bought Kaggle, most likely to access 800’000 community of machine learning developers.

Poker is another game, AI can beat humans in
Two independent researcher groups’ AIs managed to beat professional players in Texas Hold’em Poker, the most complicated version of poker. It’s another game at which computers are getting better.  Will those teams now play against each other?

Facebook wants to predict and prevent suicide attempts
Using machine learning and tens of thousands of reported posts, facebook build a model to predict people who plan to commit suicide. On a similar note, there is a map, that tries to predict crimes in London. Are we getting closer to Minority Report?

Is AI going to kill us all?
When you see a movie about AI, it usually tries to whipe out humanity. But there are also people thinking otherwise with solid philosophical arguments.

JPMorgan Software Does in Seconds What Took Lawyers 360,000 Hours
Big banks feeling more and more competition from fintech sector, are turning into ML to streamline their processes and help replace layers of redundant software.

Video
I pick one or two videos every week that touches an interesting subject in AI and ML field. Sometimes it’s more scientific and the other it’s about real life applications.

AI experts panel from Beneficial AI conference
Watch Elon Musk, Ray Kurzweil, Nick Bostrom and few others discuss their outlooks for incoming artificial intelligence.

Learning materials
Here I’m sharing material for learning ML that I found useful – online courses, blogs, books etc. This is usually rather technical stuff.

Google’s Depp Learning course on Udacity
This 3 months course goes through fundamentals of Deep Learning. Starting from building simple neural networks from a linear regression model, up to exploring Convolutional Neural Networks for image recognition and Long Term Short Memory algorithms for text analysis. It’s based on Tensorflow so basic knowledge of htis library will be helpful. It also assumes some basic knowledge in Machine Learning.

Pytorch tutorial on Github
Pytorch is another tensor-based python library for machine learning. It has its fans among the academic world and some upsides over Tensorflow.

This is it for today, thanks for reading. If you liked the post, let me know and please check other parts of the series.