added heroku buildpac for html to pdf library

defmodule Resume.Router do
  use Resume.Web, :router
  use Coherence.Router

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

  pipeline :protected do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug Coherence.Authentication.Session, protected: true
  end

  scope "/", Resume do
    pipe_through :browser
    coherence_routes
    # Add public routes below
    get "/", PageController, :index
  end

  scope "/", Resume do
    pipe_through :protected
    coherence_routes :protected
    # Add protected routes below
    resources "/skills", SkillController, except: [:show, :index, :update]
    post "/skills/:id", SkillController, :update, as: :skill
    get "/resume", PdfController, :export
  end
end


Fix nil description for a repo

Fix nil description for a repo

defmodule OpenMirego.Repo.Serializer do
  use Timex
  alias OpenMirego.Repo.Resource

  @hidden_repos ~w(
    heroku-buildpack-bower
    RentThis-iOS
    Feedback-iOS
    mirego-open-web
  )

  @deprecated_repo_description "[Deprecated]"

  # Hide specific repositories
  for name <- @hidden_repos do
    def serialize(%{"name" => unquote(name)}) do
      %Resource{visible: false}
    end
  end

  # Hide it if it’s not visible
  def serialize(%{"visible" => false}), do: %Resource{visible: false}

  # Hide it if it’s a fork
  def serialize(%{"fork" => true}), do: %Resource{visible: false}

  # Hide it if it’s a private repo
  def serialize(%{"private" => true}), do: %Resource{visible: false}

  # Hide it if it’s a deprecated repo
  def serialize(%{"description" => @deprecated_repo_description <> _}), do: %Resource{visible: false}

  # Otherwise, return a resource
  def serialize(%{"name" => name, "description" => description, "language" => language, "html_url" => html_url, "pushed_at" => pushed_at, "stargazers_count" => stargazers_count}) do
    %Resource{
      name: name,
      description: sanitize_description(description),
      language: parsed_language(language),
      pretty_language: parsed_pretty_language(language),
      url: html_url,
      raw_pushed_at: pushed_at,
      pushed_at: parsed_time(pushed_at),
      stargazers_count: stargazers_count,
      visible: true
    }
  end

  # Remove prefix emoji shortname from description
  defp sanitize_description(nil), do: ""
  defp sanitize_description(description), do: Regex.replace(~r/^:[^:]+:\s*/, description, "")

  defp parsed_language("Objective-C"), do: "pod"
  defp parsed_language("Ruby"),        do: "gem"
  defp parsed_language("JavaScript"),  do: "js"
  defp parsed_language("CSS"),         do: "css"
  defp parsed_language("Java"),        do: "java"
  defp parsed_language("Swift"),       do: "swift"
  defp parsed_language("Shell"),       do: "shell"
  defp parsed_language(nil),           do: "none"
  defp parsed_language(lang),          do: lang

  defp parsed_pretty_language("Objective-C"), do: "Obj-C"
  defp parsed_pretty_language("Ruby"),        do: "Ruby"
  defp parsed_pretty_language("JavaScript"),  do: "JS"
  defp parsed_pretty_language("CSS"),         do: "CSS"
  defp parsed_pretty_language("Java"),        do: "Java"
  defp parsed_pretty_language("Swift"),       do: "Swift"
  defp parsed_pretty_language("Shell"),       do: "Shell"
  defp parsed_pretty_language(nil),           do: ""
  defp parsed_pretty_language(lang),          do: lang

  defp parsed_time(time) do
    {:ok, date} = DateFormat.parse(time, "{ISOz}")

    date_secs = date |> Date.to_secs
    Time.now(:secs) - date_secs
  end
end

defmodule OpenMirego.Repo.Serializer do
  use Timex
  alias OpenMirego.Repo.Resource

  @hidden_repos ~w(
    heroku-buildpack-bower
    RentThis-iOS
    Feedback-iOS
    mirego-open-web
  )

  @deprecated_repo_description "[Deprecated]"

  # Hide specific repositories
  for name <- @hidden_repos do
    def serialize(%{"name" => unquote(name)}) do
      %Resource{visible: false}
    end
  end

  # Hide it if it’s not visible
  def serialize(%{"visible" => false}), do: %Resource{visible: false}

  # Hide it if it’s a fork
  def serialize(%{"fork" => true}), do: %Resource{visible: false}

  # Hide it if it’s a private repo
  def serialize(%{"private" => true}), do: %Resource{visible: false}

  # Hide it if it’s a deprecated repo
  def serialize(%{"description" => @deprecated_repo_description <> _}), do: %Resource{visible: false}

  # Otherwise, return a resource
  def serialize(%{"name" => name, "description" => description, "language" => language, "html_url" => html_url, "pushed_at" => pushed_at, "stargazers_count" => stargazers_count}) do
    %Resource{
      name: name,
      description: sanitize_description(description),
      language: parsed_language(language),
      pretty_language: parsed_pretty_language(language),
      url: html_url,
      raw_pushed_at: pushed_at,
      pushed_at: parsed_time(pushed_at),
      stargazers_count: stargazers_count,
      visible: true
    }
  end

  # Remove prefix emoji shortname from description
  defp sanitize_description(description), do: Regex.replace(~r/^:[^:]+:\s*/, description, "")

  defp parsed_language("Objective-C"), do: "pod"
  defp parsed_language("Ruby"),        do: "gem"
  defp parsed_language("JavaScript"),  do: "js"
  defp parsed_language("CSS"),         do: "css"
  defp parsed_language("Java"),        do: "java"
  defp parsed_language("Swift"),       do: "swift"
  defp parsed_language("Shell"),       do: "shell"
  defp parsed_language(nil),           do: "none"
  defp parsed_language(lang),          do: lang

  defp parsed_pretty_language("Objective-C"), do: "Obj-C"
  defp parsed_pretty_language("Ruby"),        do: "Ruby"
  defp parsed_pretty_language("JavaScript"),  do: "JS"
  defp parsed_pretty_language("CSS"),         do: "CSS"
  defp parsed_pretty_language("Java"),        do: "Java"
  defp parsed_pretty_language("Swift"),       do: "Swift"
  defp parsed_pretty_language("Shell"),       do: "Shell"
  defp parsed_pretty_language(nil),           do: ""
  defp parsed_pretty_language(lang),          do: lang

  defp parsed_time(time) do
    {:ok, date} = DateFormat.parse(time, "{ISOz}")

    date_secs = date |> Date.to_secs
    Time.now(:secs) - date_secs
  end
end


dogma again, debugging info

dogma again, debugging info

defmodule Askbywho.PageController do
  require Logger
  @moduledoc """
   Add documentation
  """

  use Askbywho.Web, :controller
  alias Askbywho.Email
  alias Askbywho.Brand
  import Ecto.Query
  import Ecto.Changeset

  plug :put_layout, "site.html"

  def index(conn, params) do
    changeset = Email.changeset(%Email{})
    render(conn, "index.html", changeset: changeset, action: page_path(conn, :create), name_brands: [])
  end

  def create(conn, %{"email" => email_params}) do
    # email_params is a map, "email" => %{"email" => "ilona.mooney@gmail.com", "name" => "Ilona", "name_brands" => ["le"]}

    # fetching location
    %{location: location, latitude: latitude, longitude: longitude} = look_up_location(conn)

    email_object = Repo.get_by(Email, email: email_params["email"] || "") || %Email{}
    email = email_object
      |> Repo.preload([:brands])
      |> Map.put(:latitude, latitude)
      |> Map.put(:longitude, longitude)
      |> Map.put(:location, location)

    # IO.puts("inspecting email: #{inspect email}")
    old_name_brands = %{"name_brands" => email.brands |> Enum.map(fn(x) -> x.name end)}

    email_params = Map.merge(email_params, old_name_brands, fn _k, v1, v2 -> v1 ++ v2 end)
    Map.put(email_params, "latitude", latitude)
    Map.put(email_params, "longitude", longitude)
    Map.put(email_params, "location", location)

    # IO.puts("env is #{Application.get_env(:askbywho, :env)}")

    result =
      email
      |> Email.changeset(email_params)
      |> Repo.insert_or_update

    case result do
      {:ok, email} -> # Inserted or updated with success
        redirect(conn, to: page_path(conn, :share, email.id))
      {:error, changeset} -> # Something went wrong
        brands = email_params["name_brands"] || []
        name_brands = brands |> Enum.map(&{&1, &1})
        render(conn, "index.html", changeset: changeset, action: page_path(conn, :create), name_brands: name_brands)
    end
  end

  def share(conn, %{"id" => id}) do
    email = Repo.get!(Email, id)
    brands = Repo.preload(email, :brands).brands
    render(conn, "share.html", email: email, brands: brands)
  end

  defp look_up_location(conn) do
    {:ok, %GeoIP.Location{:city => city, :region_name => region,
      :country_name => country, :latitude => latitude, :longitude => longitude}} =
      # this is for testing on localhost
      if conn.remote_ip == {127, 0, 0, 1} do
        GeoIP.lookup({Enum.random(1..255), Enum.random(1..255), Enum.random(1..255), Enum.random(1..254)})
      else
        GeoIP.lookup(conn)
      end
      IO.puts("inspecting ip: #{conn.remote_ip}")
      IO.puts("inspecting geoIP result: #{inspect GeoIP.lookup(conn)}")

    location = formatted_location(%{city: city, region: region, country: country})

    if latitude == 0 && longitude == 0 do
      %{location: "n/a", latitude: 0.0, longitude: 0.0}
    else
      %{location: location, latitude: latitude, longitude: longitude}
    end
  end

  defp formatted_location(%{city: "", region: "", country: country}) do
    country
  end
  defp formatted_location(%{city: "", region: region, country: country}) do
    region <> ", " <> country
  end
  defp formatted_location(%{city: city, region: region, country: country}) do
    city <> ", " <> region <> ", " <> country
  end

end

defmodule Askbywho.PageController do
  require Logger
  @moduledoc """
   Add documentation
  """

  use Askbywho.Web, :controller
  alias Askbywho.Email
  alias Askbywho.Brand
  import Ecto.Query
  import Ecto.Changeset

  plug :put_layout, "site.html"

  def index(conn, params) do
    changeset = Email.changeset(%Email{})
    render(conn, "index.html", changeset: changeset, action: page_path(conn, :create), name_brands: [])
  end

  def create(conn, %{"email" => email_params}) do
    # email_params is a map, "email" => %{"email" => "ilona.mooney@gmail.com", "name" => "Ilona", "name_brands" => ["le"]}

    # fetching location
    %{location: location, latitude: latitude, longitude: longitude} = look_up_location(conn)

    email_object = Repo.get_by(Email, email: email_params["email"] || "") || %Email{}
    email = email_object
      |> Repo.preload([:brands])
      |> Map.put(:latitude, latitude)
      |> Map.put(:longitude, longitude)
      |> Map.put(:location, location)

    # IO.puts("inspecting email: #{inspect email}")
    old_name_brands = %{"name_brands" => email.brands |> Enum.map(fn(x) -> x.name end)}

    email_params = Map.merge(email_params, old_name_brands, fn _k, v1, v2 -> v1 ++ v2 end)
    Map.put(email_params, "latitude", latitude)
    Map.put(email_params, "longitude", longitude)
    Map.put(email_params, "location", location)

    # IO.puts("env is #{Application.get_env(:askbywho, :env)}")

    result =
      email
      |> Email.changeset(email_params)
      |> Repo.insert_or_update

    case result do
      {:ok, email} -> # Inserted or updated with success
        redirect(conn, to: page_path(conn, :share, email.id))
      {:error, changeset} -> # Something went wrong
        brands = email_params["name_brands"] || []
        name_brands = brands |> Enum.map(&{&1, &1})
        render(conn, "index.html", changeset: changeset, action: page_path(conn, :create), name_brands: name_brands)
    end
  end

  def share(conn, %{"id" => id}) do
    email = Repo.get!(Email, id)
    brands = Repo.preload(email, :brands).brands
    render(conn, "share.html", email: email, brands: brands)
  end

  defp look_up_location(conn) do
    {:ok, %GeoIP.Location{:city => city, :region_name => region,
      :country_name => country, :latitude => latitude, :longitude => longitude}} =
      # this is for testing on localhost
      if conn.remote_ip == {127, 0, 0, 1} do
        GeoIP.lookup({Enum.random(1..255), Enum.random(1..255), Enum.random(1..255), Enum.random(1..254)})
      else
        GeoIP.lookup(conn)
      end

    location = formatted_location(%{city: city, region: region, country: country})

    if latitude == 0 && longitude == 0 do
      %{location: "n/a", latitude: 0.0, longitude: 0.0}
    else
      %{location: location, latitude: latitude, longitude: longitude}
    end
  end

  defp formatted_location(%{city: "", region: "", country: country}) do
    country
  end
  defp formatted_location(%{city: "", region: region, country: country}) do
    region <> ", " <> country
  end
  defp formatted_location(%{city: city, region: region, country: country}) do
    city <> ", " <> region <> ", " <> country
  end

end


More documentation improvements.

More documentation improvements.

defexception File.Exception, reason: nil, action: "", path: nil do
  def message(exception) do
    "could not " <> exception.action <> " " <> exception.path <> ": " <> list_to_binary(:file.format_error(exception.reason))
  end
end

defrecord FileInfo, Record.extract(:file_info, from_lib: "kernel/include/file.hrl")

defmodule File do
  require Erlang.file, as: F
  require Erlang.filename, as: FN
  require Erlang.filelib,  as: FL

  def expand_path(path) do
    normalize FN.absname(path)
  end

  def expand_path(path, relative_to) do
    normalize FN.absname(FN.absname(path, relative_to))
  end

  def regular?(filename) do
    Erlang.filelib.is_regular(filename)
  end

  @doc """
  Returns the last component of the `filename` or the file
  name itself if it does not contain any directory separators.

  ## Examples

      File.basename("foo")
      #=> "foo"

      File.basename("foo/bar")
      #=> "bar"

      File.basename("/")
      #=> ""

  """
  def basename(path) do
    FN.basename(path)
  end

  @doc """
  Returns the last component of `filename` with the `extension`
  stripped. This function should be used to remove a specific extension
  which might, or might not, be there.

  ## Examples

      File.basename("~/foo/bar.ex", ".ex")
      #=> "bar"
      File.basename("~/foo/bar.exs", ".ex")
      #=> "bar.ecs"
      File.basename("~/foo/bar.old.ex", ".ex")
      #=> "kalle.old"

  """
  def basename(path, extension) do
    FN.basename(path, extension)
  end

  @doc """
  Returns a string with one or more paths components joint by the path separator.
  This function should be used to convert a list of strings in a path.

  ## Examples

      File.join(["~", "foo"])
      #=> "~/foo"
      File.join(["foo"])
      #=> "foo"
      File.join(["/", "foo", "bar"])
      #=> "/foo/bar"
  """
  def join(paths) do
    FN.join(paths)
  end

  @doc """
  Returns `{:ok, binary}`, where `binary` is a binary data object that contains the contents
  of `filename`, or `{:error, reason}` if an error occurs.

  Typical error reasons:

  * :enoent - The file does not exist.
  * :eacces - Missing permission for reading the file,
              or for searching one of the parent directories.
  * :eisdir - The named file is a directory.
  * :enotdir - A component of the file name is not a directory.
               On some platforms, enoent is returned instead.
  * :enomem - There is not enough memory for the contents of the file.

  You can use `Erlang.file.format_error(reason)` to get a descriptive string of the error.
  """
  def read(filename) do
    F.read_file(filename)
  end

  @doc """
  Returns binary with the contents of the given filename or raises
  File.Exception if an error occurs.
  """
  def read!(filename) do
    result = read(filename)

    case result do
    match: { :ok, binary }
      binary
    match: { :error, reason }
      raise File.Exception, reason: reason, action: "read file", path: filename
    end
  end

  @doc """
  Returns a list with the path splitted by the path separator. If an empty string
  is given, then it returns the root path.

  ## Examples

     File.split("")
     #=> ["/"]
     File.split("foo")
     #=> ["foo"]
     File.split("/foo/bar")
     #=> ["/", "foo", "bar"]

  """
  def split(path) do
    FN.split(path)
  end

  @doc """
  Traverses files and directories according to the given glob expression.

  The wildcard string looks like an ordinary filename, except that certain
  "wildcard characters" are interpreted in a special way. The following
  characters are special:

  * `?` - Matches one character.
  * `*` - Matches any number of characters up to the end of
          the filename, the next dot, or the next slash.
  * `**` - Two adjacent <c>*</c>'s used as a single pattern will
           match all files and zero or more directories and subdirectories.
  * `[char1,char2,...]` - Matches any of the characters listed. Two characters
                          separated by a hyphen will match a range of characters.
  * `{item1,item2,...}` - Matches one of the alternatives.

  Other characters represent themselves. Only filenames that have exactly
  the same character in the same position will match. Note that matching
  is case-sensitive; i.e. "a" will not match "A".

  ## Examples

  Imagine you have a directory called `projects` with three Elixir projects
  inside of it: `elixir`, `exdoc` and `dynamo`. You can find all `.beam` files
  inside their ebin directories all projects as follows:

      File.wildcard("projects/*/ebin/**/*.beam")

  If you want to search for both `.beam` and `.app` files, you could do:

      File.wildcard("projects/*/ebin/**/*.{beam,app}")

  """
  def wildcard(glob) when is_binary(glob) do
    paths = Erlang.elixir_glob.wildcard binary_to_list(glob)
    Enum.map paths, list_to_binary(&1)
  end

  def wildcard(path) when is_list(path) do
    Erlang.elixir_glob.wildcard(path)
  end

  @doc """
  Returns information about a file. Info is returned
  as a `FileInfo` record containing the following elements:

  * `size` - Size of file in bytes.
  * `type` - `:device`, `:directory`, `:regular`, `:other`. The type of the file.
  * `access` - `:read`, `:write`, `:read_write`, `:none`. The current system access to
               the file.
  * `atime` - The last time the file was read.
  * `mtime` - The last time the file was written.
  * `ctime` - The interpretation of this time field depends on the operating
              system. On Unix, it is the last time the file or the inode was
              changed. in Windows, it is the create time.
  * `mode` - The file permissions.
  * `links` - The number of links to this file. This is always 1 for file
              systems which have no concept of links.
  * `major_device` - Identifies the file system where the file is located.
                     In windows, the number indicates a drive as follows:
                     0 means A:, 1 means B:, and so on.
  * `minor_device` - Only valid for character devices on Unix. In all other
                     cases, this field is zero.
  * `inode` - Gives the inode number. On non-Unix file systems, this field
              will be zero.
  * `uid` - Indicates the owner of the file.
  * `gid` - Gives the group that the owner of the file belongs to. Will be
            zero for non-Unix file systems.

  The time type returned in `atime`, `mtime`, and `ctime` is dependent on the
  time type set in options. `{:time, type}` where type can be `:local`,
  `:universal`, or `:posix`. Default is `:local`.
  """
  def read_info(path, opts // []) do
    case :file.read_file_info(path, opts) do
    match: {:ok, fileinfo}
      {:ok, FileInfo.new fileinfo}
    match: error
      error
    end
  end

  @doc """
  Same as `read_info` but returns only the FileInfo and
  throws an exception if an error occurs.
  """
  def read_info!(path, opts // []) do
    case read_info(path, opts) do
    match: {:ok, info}
      info
    match: {:error, reason}
      raise File.Exception, reason: reason, action: "read info of file", path: path
    end
  end

  ## Helpers

  # Normalize the given path by removing "..".
  defp normalize(path), do: normalize(split(path), [])

  defp normalize([top|t], [_|acc]) when top == ".." or top == '..' do
    normalize t, acc
  end

  defp normalize([top|t], acc) when top == "." or top == '.' do
    normalize t, acc
  end

  defp normalize([h|t], acc) do
    normalize t, [h|acc]
  end

  defp normalize([], acc) do
    join List.reverse(acc)
  end
end

defexception File.Exception, reason: nil, action: "", path: nil do
  def message(exception) do
    "could not " <> exception.action <> " " <> exception.path <> ": " <> list_to_binary(:file.format_error(exception.reason))
  end
end

defrecord FileInfo, Record.extract(:file_info, from_lib: "kernel/include/file.hrl")

defmodule File do
  require Erlang.file, as: F
  require Erlang.filename, as: FN
  require Erlang.filelib,  as: FL

  def expand_path(path) do
    normalize FN.absname(path)
  end

  def expand_path(path, relative_to) do
    normalize FN.absname(FN.absname(path, relative_to))
  end

  def regular?(filename) do
    Erlang.filelib.is_regular(filename)
  end

  @doc """
  Returns the last component of the `filename` or the file
  name itself if it does not contain any directory separators.

  ## Examples

      File.basename("foo")
      #=> "foo"

      File.basename("foo/bar")
      #=> "bar"

      File.basename("/")
      #=> ""

  """
  def basename(path) do
    FN.basename(path)
  end

  @doc """
  Returns the last component of `filename` with the `extension`
  stripped. This function should be used to remove a specific extension
  which might, or might not, be there.

  ## Examples

      File.basename("~/foo/bar.ex", ".ex")
      #=> "bar"
      File.basename("~/foo/bar.exs", ".ex")
      #=> "bar.ecs"
      File.basename("~/foo/bar.old.ex", ".ex")
      #=> "kalle.old"

  """
  def basename(path, extension) do
    FN.basename(path, extension)
  end

  @doc """
  Returns a string with one or more paths components joint by the path separator.
  This function should be used to convert a list of strings in a path.

  ## Examples

      File.join(["~", "foo"])
      #=> "~/foo"
      File.join(["foo"])
      #=> "foo"
      File.join(["/", "foo", "bar"])
      #=> "/foo/bar"
  """
  def join(paths) do
    FN.join(paths)
  end

  @doc """
  Returns `{:ok, binary}`, where `binary` is a binary data object that contains the contents
  of `filename`, or `{:error, reason}` if an error occurs.

  Typical error reasons:

  * :enoent - The file does not exist.
  * :eacces - Missing permission for reading the file,
              or for searching one of the parent directories.
  * :eisdir - The named file is a directory.
  * :enotdir - A component of the file name is not a directory.
               On some platforms, enoent is returned instead.
  * :enomem - There is not enough memory for the contents of the file.

  You can use `Erlang.file.format_error(reason)` to get a descriptive string of the error.
  """
  def read(filename) do
    F.read_file(filename)
  end

  @doc """
  Returns binary with the contents of the given filename or raises
  File.Exception if an error occurs.
  """
  def read!(filename) do
    result = read(filename)

    case result do
    match: { :ok, binary }
      binary
    match: { :error, reason }
      raise File.Exception, reason: reason, action: "read file", path: filename
    end
  end

  @doc """
  Returns a list with the path splitted by the path separator. If an empty string
  is given, then it returns the root path.

  ## Examples

     File.split("")
     #=> ["/"]
     File.split("foo")
     #=> ["foo"]
     File.split("/foo/bar")
     #=> ["/", "foo", "bar"]

  """
  def split(path) do
    FN.split(path)
  end

  @doc """
  Traverses files and directories according to the given glob expression.

  The wildcard string looks like an ordinary filename, except that certain
  "wildcard characters" are interpreted in a special way. The following
  characters are special:

  * `?` - Matches one character.
  * `*` - Matches any number of characters up to the end of
          the filename, the next dot, or the next slash.
  * `**` - Two adjacent <c>*</c>'s used as a single pattern will
           match all files and zero or more directories and subdirectories.
  * `[char1,char2,...]` - Matches any of the characters listed. Two characters
                          separated by a hyphen will match a range of characters.
  * `{item1,item2,...}` - Matches one of the alternatives.

  Other characters represent themselves. Only filenames that have exactly
  the same character in the same position will match. Note that matching
  is case-sensitive; i.e. "a" will not match "A".

  ## Examples

  Imagine you have a directory called `projects` with three Elixir projects
  inside of it: `elixir`, `exdoc` and `dynamo`. You can find all `.beam` files
  inside their ebin directories all projects as follows:

      File.wildcard("projects/*/ebin/**/*.beam")

  If you want to search for both `.beam` and `.app` files, you could do:

      File.wildcard("projects/*/ebin/**/*.{beam,app}")

  """
  def wildcard(glob) when is_binary(glob) do
    paths = Erlang.elixir_glob.wildcard binary_to_list(glob)
    Enum.map paths, list_to_binary(&1)
  end

  def wildcard(path) when is_list(path) do
    Erlang.elixir_glob.wildcard(path)
  end

  @doc """
  Returns information about a file. Info is returned
  as a `FileInfo` record containing the following elements:

  `size` - Size of file in bytes.
  `type` - `:device`, `:directory`, `:regular`, `:other`. The type of the file.
  `access` - `:read`, `:write`, `:read_write`, `:none`. The current system access to
             the file.
  `atime` - The last time the file was read.
  `mtime` - The last time the file was written.
  `ctime` - The interpretation of this time field depends on the operating
            system. On Unix, it is the last time the file or the inode was
            changed. in Windows, it is the create time.
  `mode` - The file permissions.
  `links` - The number of links to this file. This is always 1 for file
            systems which have no concept of links.
  `major_device` - Identifies the file system where the file is located.
                   In windows, the number indicates a drive as follows:
                   0 means A:, 1 means B:, and so on.
  `minor_device` - Only valid for character devices on Unix. In all other
                   cases, this field is zero.
  `inode` - Gives the inode number. On non-Unix file systems, this field
            will be zero.
  `uid` - Indicates the owner of the file.
  `gid` - Gives the group that the owner of the file belongs to. Will be
          zero for non-Unix file systems.

  The time type returned in atime, mtime, and ctime is dependent on the
  time type set in options. `{:time, type}` where type can be local,
  universal, or posix. Default is local.
  """
  def read_info(path, opts // []) do
    case :file.read_file_info(path, opts) do
    match: {:ok, fileinfo}
      {:ok, FileInfo.new fileinfo}
    match: error
      error
    end
  end

  @doc """
  Same as `read_info` but returns only the FileInfo and
  throws an exception if an error occurs.
  """
  def read_info!(path, opts // []) do
    case read_info(path, opts) do
    match: {:ok, info}
      info
    match: {:error, reason}
      raise File.Exception, reason: reason, action: "read info of file", path: path
    end
  end

  ## Helpers

  # Normalize the given path by removing "..".
  defp normalize(path), do: normalize(split(path), [])

  defp normalize([top|t], [_|acc]) when top == ".." or top == '..' do
    normalize t, acc
  end

  defp normalize([top|t], acc) when top == "." or top == '.' do
    normalize t, acc
  end

  defp normalize([h|t], acc) do
    normalize t, [h|acc]
  end

  defp normalize([], acc) do
    join List.reverse(acc)
  end
end


lots more functions

lots more functions

defmodule Expyplot.Plot do
  @moduledoc """
  This is the end-user API for pyplot.

  http://matplotlib.org/api/pyplot_api.html

  Most of these functions are UNTESTED. I know. That's terrible. But you can test them by using them! Then, if they don't work, open an issue on the github:
  https://github.com/MaxStrange/expyplot/issues

  Or better yet, you could write some tests or a patch and open a pull request!
  """

  @doc """
  Plot the autocorrelation of x.
  """
  def acorr(x, opts \\ [hold: nil, data: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axis", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Plot the angle spectrum.

  Compute the angle spectrum (wrapped phase spectrum) of x. Data is padded to a length of pad_to and the windowing function window Not used yet
  in Expyplot is applied to the signal.
  """
  def angle_spectrum(x, opts \\ [fs: 2, fc: 0, pad_to: nil, sides: :default], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.angle_spectrum", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Annotate the point xy with text s.

  Additional kwargs are passed to Text.
  """
  def annotate(opts \\ [], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.annotate", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Add an arrow to the axes.

  Draws arrow on specified axis from (x, y) to (x + dx, y + dy). Uses FancyArrow patch to construct the arrow.
  """
  def arrow(x, y, dx, dy, opts \\ [hold: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.arrow", nonnamed: [x, y, dx, dy], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Autoscale the axis view to the data (toggle).

  Convenience method for simple axis view autoscaling. It turns autoscaling on or off, and then, if autoscaling for either axis is on, it
  performs the autoscaling on the specified axis or axes.
  """
  def autoscale(opts \\ [enable: true, axis: :both, tight: nil]) do
    Codebuilder.build_code(funcname: "plt.autoscale", nonnamed: [], named: opts) |> Server.Commapi.add_code
  end

  @doc """
  Set the default colormap to autumn and apply to current image if any. See help(colormaps) for more information
  """
  def autumn do
    Codebuilder.build_code(funcname: "plt.autumn", nonnamed: [], named: []) |> Server.Commapi.add_code
  end

  @doc """
  Add an axes to the figure.

  The axes is added at position rect specified by:

  - axes() by itself creates a default full subplot(111) window axis.
  - axes(rect, [facecolor: :w]), where rect = [left, bottom, width, height] in normalized (0, 1) units. facecolor is the background
    color for the axis, default white.
  - axes(h) where h is an axes instance makes h the current axis.
  """
  def axes(opts \\ [], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axes", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Add a horizontal line across the axis.
  """
  def axhline(opts \\ [y: 0, xmin: 0, xmax: 1, hold: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axhline", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Add a horizontal span (rectangle) across the axis.

  Draw a horizontal span (rectangle) from ymin to ymax. With the default values of xmin = 0 and xmax = 1, this always spans the xrange,
  regardless of the xlim settings, even if you change them, e.g., with the set_xlim() command. That is, the horizontal extent is in axes
  coords: 0=left, 0.5=middle, 1.0=right but the y location is in data coordinates.
  """
  def axhspan(ymin, ymax, opts \\ [xmin: 0, xmax: 1, hold: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axhspan", nonnamed: [ymin, ymax], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  This is how axis has been implemented in this library: as two functions - a get and a set, rather than just the one
  Convenience method to get or set axis properties.
  """
  def axis_get(kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axis", nonnamed: [], named: kwargs) |> Server.Commapi.add_code
  end

  @doc """
  This is how axis has been implemented in this library: as two functions - a get and a set, rather than just the one
  Convenience method to get or set axis properties.
  """
  def axis_set(v, kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axis", nonnamed: [v], named: kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Turn the axes grids on or off.

  Set the axes grids on or off; b is a boolean. (For MATLAB compatibility, b may also be a string, ‘on’ or ‘off’.)

  If b is None and len(kwargs)==0, toggle the grid state. If kwargs are supplied, it is assumed that you want a grid and b is thus set to True.

  which can be ‘major’ (default), ‘minor’, or ‘both’ to control whether major tick grids, minor tick grids, or both are affected.

  axis can be ‘both’ (default), ‘x’, or ‘y’ to control which set of gridlines are drawn.
  """
  def grid(opts \\ [b: nil, which: :major, axis: :both], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.grid", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Add a vertical line across the axes.
  """
  def axvline(opts \\ [x: 0, ymin: 0, ymax: 1, hold: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axvline", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Add a vertical span (rectangle) across the axes.

  Draw a vertical span (rectangle) from xmin to xmax. With the default values of ymin = 0 and ymax = 1. This always spans the yrange,
  regardless of the ylim settings, even if you change them, e.g., with the set_ylim() command. That is, the vertical extent is in axes
  coords: 0=bottom, 0.5=middle, 1.0=top but the y location is in data coordinates.
  """
  def axvspan(xmin, xmax, opts \\ [ymin: 0, ymax: 1, hold: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.axvspan", nonnamed: [xmin, xmax], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Make a bar plot.

  Make a bar plot with rectangles bounded by: left, left + width, bottom, bottom + height
  (left, right, bottom and top edges).
  """
  def bar(left, height, opts \\ [width: 0.8, bottom: nil, hold: nil, data: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.bar", nonnamed: [left, height], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Plot a 2-D field of barbs.
  """
  def barbs(opts \\ [], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.barbs", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Make a horizontal bar plot.

  Make a horizontal bar plot with rectangles bounded by: left, left + width, bottom, bottom + height

  (lft, right, bottom and top edges).

  bottom, width, height, and left can be either scalars or sequences
  """
  def barh(bottom, width, opts \\ [height: 0.8, left: nil, hold: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.barh", nonnamed: [bottom, width], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Set the default colormap to bone and apply to current image if any.
  """
  def bone do
    Codebuilder.build_code(funcname: "plt.bone", nonnamed: [], named: []) |> Server.Commapi.add_code
  end

  @doc """
  Make a box and whisker plot.

  Make a box and whisker plot for each column of x or each vector in sequence x. The box extends from the lower to upper quartile values
  of the data, with a line at the median. The whiskers extend from the box to show the range of the data. Flier points are those past the end
  of the whiskers.
  """
  def boxplot(x, opts \\ [notch: nil, sym: nil, vert: nil, whis: nil, positions: nil, widths: nil, patch_artist: nil, bootstrap: nil, usermedians: nil,
                          conf_intervals: nil, meanline: nil, showmeans: nil, showcaps: nil, showbox: nil, showfliers: nil, boxprops: nil, labels: nil,
                          flierprops: nil, medianprops: nil, meanprops: nil, capprops: nil, whiskerprops: nil, manage_xticks: true, autorange: false,
                          zorder: nil, hold: nil, data: nil]) do
    Codebuilder.build_code(funcname: "plt.boxplot", nonnamed: [x], named: opts) |> Server.Commapi.add_code
  end

  @doc """
  Plot horizontal bars.

  A collection of horizontal bars spanning yrange with a sequence of xranges.
  """
  def broken_barh(xranges, yrange, opts \\ [hold: nil, data: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.broken_barh", nonnamed: [xranges, yrange], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Clear the current axes.
  """
  def cla do
    Codebuilder.build_code(funcname: "plt.cla", nonnamed: [], named: []) |> Server.Commapi.add_code
  end

  @doc """
  Label a contour plot.
  """
  def clabel(cs, opts \\ [], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.clabel", nonnamed: [cs], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Clear the current figure.
  """
  def clf do
    Codebuilder.build_code(funcname: "plt.clf", nonnamed: [], named: []) |> Server.Commapi.add_code
  end

  @doc """
  Set the color limits of the current image.

  To apply clim to all axes images do:
  ```elixir
  clim(0, 0.5)
  ```
  If either vmin or vmax is nil, the image min/max respectively will be used for color scaling.
  """
  def clim(opts \\ [vmin: nil, vmax: nil]) do
    Codebuilder.build_code(funcname: "plt.clim", nonnamed: [], named: opts) |> Server.Commapi.add_code
  end

  @doc """
  Close a figure window.

  close() by itself closes the current figure

  close(num) closes figure number num

  close(name) where name is a string, closes figure with that label

  close(:all) closes all the figure windows
  """
  def close(opts \\ []) do
    Codebuilder.build_code(funcname: "plt.close", nonnamed: opts) |> Server.Commapi.add_code
  end

  @doc """
  Plot the coherence between x and y.

  Plot the coherence between x and y. Coherence is the normalized cross spectral density.
  """
  def cohere(x, y, opts \\ [nfft: 256, fs: 2, fc: 0, noverlap: 0, pad_to: nil, sides: :default, scale_by_freq: nil, hold: nil, data: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.cohere", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Add a colorbar to a plot.
  """
  def colorbar(opts \\ [mappable: nil, cax: nil, ax: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.colorbar", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  This is a do-nothing function to provide you with help on how matplotlib handles colors.
  """
  def colors do
    Codebuilder.build_code(funcname: "plt.colors", nonnamed: [], named: []) |> Server.Commapi.add_code
  end

  @doc """
  Plot contours.

  contour() and contourf() draw contour lines and filled contours, respectively. Except as noted, function signatures and return values
  are the same for both versions.

  contourf() differs from the MATLAB version in that it does not draw the polygon edges. To draw edges, add line contours with calls to contour().
  """
  def contour(opts \\ [], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.contour", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Plot contours.

  contour() and contourf() draw contour lines and filled contours, respectively. Except as noted, function signatures and return values
  are the same for both versions.

  contourf() differs from the MATLAB version in that it does not draw the polygon edges. To draw edges, add line contours with calls to contour().
  """
  def contourf(opts \\ [], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.contourf", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Set the default colormap to cool and apply to current image if any.
  """
  def cool do
    Codebuilder.build_code(funcname: "plt.cool", nonnamed: [], named: []) |> Server.Commapi.add_code
  end

  @doc """
  Set the default colormap to copper and apply to current image if any.
  """
  def copper do
    Codebuilder.build_code(funcname: "plt.copper", nonnamed: [], named: []) |> Server.Commapi.add_code
  end

  @doc """
  Plot the cross-spectral density.
  """
  def csd(x, y, opts \\ [nfft: 256, fs: 2, fc: 0, noverlap: 0, pad_to: nil, sides: :default, scale_by_freq: nil, return_line: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.csd", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Remove an axes from the current figure. If ax doesn't exist, an error will be raised.
  """
  def delaxes(opts \\ []) do
    Codebuilder.build_code(funcname: "plt.delaxes", nonnamed: [], named: opts) |> Server.Commapi.add_code
  end

  @doc """
  Redraw the current figure.

  This is used to update a figure that has been altered, but not automatically re-drawn. If interactive mode is on (ion()), this should be only
  rarely needed, but there may be ways to modify the state of a figure without marking it as stale.
  """
  def draw do
    Codebuilder.build_code(funcname: "plt.draw", nonnamed: [], name: []) |> Server.Commapi.add_code
  end

  @doc """
  Plot an errorbar graph.

  Plot x versus y with error deltas in yerr and xerr. Vertical errorbars are plotted if yerr is not nil. Horizontal errorbars are plotted if xerr is
  not nil.

  x, y, xerr, and yerr can all be scalars, which plots a single error bar at x, y.
  """
  def errorbar(x, y, opts \\ [yerr: nil, xerr: nil, fmt: "", ecolor: nil, elinewidth: nil, capsize: nil, barsabove: false, lolims: false, uplims: false,
                              xlolims: false, xuplims: false, errorevery: 1, capthick: nil, hold: nil, data: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.errorbar", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Plot identical parallel lines at specific positions.

  Plot parallel lines at the given positions. positions should be a 1D or 2D array-like object, with each row corresponding to a row or
  column of lines.

  This type of plot is commonly used in neuroscience for representing neural events, where it is commonly called a spike raster, dot raster, or raster plot.

  However, it is useful in any situation where you wish to show the timing or position of multiple sets of discrete events, such as the arrival
  times of people to a business on each day of the month or the date of hurricanes each year of the last century.
  """
  def eventplot(positions, opts \\ [orientation: :horizontal, lineoffsets: 1, linelengths: 1, linewidths: nil, colors: nil, linestyles: :solid,
                                    hold: nil, data: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.eventplot", nonnamed: [positions], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Histogram function. See matplotlib docs for hist:
  http://matplotlib.org/api/pyplot_api.html
  """
  def hist(x, opts \\ [bins: nil, range: nil, normed: false, weights: nil, cumulative: false, bottom: nil, histtype: :bar, align: :mid, orientation: :vertical,
                       rwidth: nil, log: false, color: nil, label: nil, stacked: false, hold: nil, data: nil], kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.hist", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Set a title of the current axes.

  Set one of hte three available axes titles. The available titles are positioned above the aces in the center, flush with the left edge, and flush
  with the right edge.
  """
  def title(s, kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.title", nonnamed: [s], named: kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Set the x axis label of the current axis.
  """
  def xlabel(s, kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.xlabel", nonnamed: [s], named: kwargs) |> Server.Commapi.add_code
  end

  @doc """
  Set the y axis label of the current axis.
  """
  def ylabel(s, kwargs \\ []) do
    Codebuilder.build_code(funcname: "plt.ylabel", nonnamed: [s], named: kwargs) |> Server.Commapi.add_code
  end

  def show do
    Codebuilder.build_code(funcname: "plt.show", nonnamed: [], named: []) |> Server.Commapi.add_code
  end
end

defmodule Expyplot.Plot do
  @moduledoc """
  This is the end-user API for pyplot.

  http://matplotlib.org/api/pyplot_api.html

  Most of these functions are UNTESTED. I know. That's terrible. But you can test them by using them! Then, if they don't work, open an issue on the github:
  https://github.com/MaxStrange/expyplot/issues

  Or better yet, you could write some tests or a patch and open a pull request!
  """

  @doc """
  Plot the autocorrelation of x.
  """
  def acorr(x, opts \\ [hold: nil, data: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axis", nonnamed: [x], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Plot the angle spectrum.

  Compute the angle spectrum (wrapped phase spectrum) of x. Data is padded to a length of pad_to and the windowing function window Not used yet
  in Expyplot is applied to the signal.
  """
  def angle_spectrum(x, opts \\ [fs: 2, fc: 0, pad_to: nil, sides: :default], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.angle_spectrum", nonnamed: [x], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Annotate the point xy with text s.

  Additional kwargs are passed to Text.
  """
  def annotate(opts \\ [], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.annotate", nonnamed: [], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Add an arrow to the axes.

  Draws arrow on specified axis from (x, y) to (x + dx, y + dy). Uses FancyArrow patch to construct the arrow.
  """
  def arrow(x, y, dx, dy, opts \\ [hold: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.arrow", nonnamed: [x, y, dx, dy], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Autoscale the axis view to the data (toggle).

  Convenience method for simple axis view autoscaling. It turns autoscaling on or off, and then, if autoscaling for either axis is on, it
  performs the autoscaling on the specified axis or axes.
  """
  def autoscale(opts \\ [enable: true, axis: :both, tight: nil]) do
    code = Codebuilder.build_code(funcname: "plt.autoscale", nonnamed: [], named: opts)
    Server.Commapi.add_code code
  end

  @doc """
  Set the default colormap to autumn and apply to current image if any. See help(colormaps) for more information
  """
  def autumn do
    code = Codebuilder.build_code(funcname: "plt.autumn", nonnamed: [], named: [])
    Server.Commapi.add_code code
  end

  @doc """
  Add an axes to the figure.

  The axes is added at position rect specified by:

  - axes() by itself creates a default full subplot(111) window axis.
  - axes(rect, [facecolor: :w]), where rect = [left, bottom, width, height] in normalized (0, 1) units. facecolor is the background
    color for the axis, default white.
  - axes(h) where h is an axes instance makes h the current axis.
  """
  def axes(opts \\ [], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axes", nonnamed: [], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Add a horizontal line across the axis.
  """
  def axhline(opts \\ [y: 0, xmin: 0, xmax: 1, hold: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axhline", nonnamed: [], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Add a horizontal span (rectangle) across the axis.

  Draw a horizontal span (rectangle) from ymin to ymax. With the default values of xmin = 0 and xmax = 1, this always spans the xrange,
  regardless of the xlim settings, even if you change them, e.g., with the set_xlim() command. That is, the horizontal extent is in axes
  coords: 0=left, 0.5=middle, 1.0=right but the y location is in data coordinates.
  """
  def axhspan(ymin, ymax, opts \\ [xmin: 0, xmax: 1, hold: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axhspan", nonnamed: [ymin, ymax], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  This is how axis has been implemented in this library: as two functions - a get and a set, rather than just the one
  Convenience method to get or set axis properties.
  """
  def axis_get(kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axis", nonnamed: [], named: kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  This is how axis has been implemented in this library: as two functions - a get and a set, rather than just the one
  Convenience method to get or set axis properties.
  """
  def axis_set(v, kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axis", nonnamed: [v], named: kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Turn the axes grids on or off.

  Set the axes grids on or off; b is a boolean. (For MATLAB compatibility, b may also be a string, ‘on’ or ‘off’.)

  If b is None and len(kwargs)==0, toggle the grid state. If kwargs are supplied, it is assumed that you want a grid and b is thus set to True.

  which can be ‘major’ (default), ‘minor’, or ‘both’ to control whether major tick grids, minor tick grids, or both are affected.

  axis can be ‘both’ (default), ‘x’, or ‘y’ to control which set of gridlines are drawn.
  """
  def grid(opts \\ [b: nil, which: :major, axis: :both], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.grid", nonnamed: [], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Add a vertical line across the axes.
  """
  def axvline(opts \\ [x: 0, ymin: 0, ymax: 1, hold: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axvline", nonnamed: [], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Add a vertical span (rectangle) across the axes.

  Draw a vertical span (rectangle) from xmin to xmax. With the default values of ymin = 0 and ymax = 1. This always spans the yrange,
  regardless of the ylim settings, even if you change them, e.g., with the set_ylim() command. That is, the vertical extent is in axes
  coords: 0=bottom, 0.5=middle, 1.0=top but the y location is in data coordinates.
  """
  def axvspan(xmin, xmax, opts \\ [ymin: 0, ymax: 1, hold: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.axvspan", nonnamed: [xmin, xmax], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Make a bar plot.

  Make a bar plot with rectangles bounded by: left, left + width, bottom, bottom + height
  (left, right, bottom and top edges).
  """
  def bar(left, height, opts \\ [width: 0.8, bottom: nil, hold: nil, data: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.bar", nonnamed: [left, height], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Histogram function. See matplotlib docs for hist:
  http://matplotlib.org/api/pyplot_api.html
  """
  def hist(x, opts \\ [bins: nil, range: nil, normed: false, weights: nil, cumulative: false, bottom: nil, histtype: :bar, align: :mid, orientation: :vertical,
                       rwidth: nil, log: false, color: nil, label: nil, stacked: false, hold: nil, data: nil], kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.hist", nonnamed: [x], named: opts ++ kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Set a title of the current axes.

  Set one of hte three available axes titles. The available titles are positioned above the aces in the center, flush with the left edge, and flush
  with the right edge.
  """
  def title(s, kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.title", nonnamed: [s], named: kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Set the x axis label of the current axis.
  """
  def xlabel(s, kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.xlabel", nonnamed: [s], named: kwargs)
    Server.Commapi.add_code code
  end

  @doc """
  Set the y axis label of the current axis.
  """
  def ylabel(s, kwargs \\ []) do
    code = Codebuilder.build_code(funcname: "plt.ylabel", nonnamed: [s], named: kwargs)
    Server.Commapi.add_code code
  end

  def show do
    code = Codebuilder.build_code(funcname: "plt.show", nonnamed: [], named: [])
    Server.Commapi.add_code code
  end
end


Add special processing of disconnected event

# Copyright 2014 LKC Technologies, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

defmodule WpaSupplicant.Decode do
  @doc """
  Decode notifications from the wpa_supplicant
  """
  def notif(<< "CTRL-REQ-", rest::binary >>) do
    [field, net_id, text] = String.split(rest, "-", parts: 3, trim: true)
    {String.to_atom("CTRL-REQ-" <> field), String.to_integer(net_id), text}
  end
  def notif(<< "CTRL-EVENT-BSS-ADDED", rest::binary >>) do
    [entry_id, bssid] = String.split(rest, " ", trim: true)
    {:"CTRL-EVENT-BSS-ADDED", String.to_integer(entry_id), bssid}
  end
  def notif(<< "CTRL-EVENT-BSS-REMOVED", rest::binary >>) do
    [entry_id, bssid] = String.split(rest, " ", trim: true)
    {:"CTRL-EVENT-BSS-REMOVED", String.to_integer(entry_id), bssid}
  end
  def notif(<< "CTRL-EVENT-CONNECTED", _rest::binary >>) do
    :"CTRL-EVENT-CONNECTED"
  end
  def notif(<< "CTRL-EVENT-DISCONNECTED", _rest::binary >>) do
    :"CTRL-EVENT-DISCONNECTED"
  end
  def notif(<< "CTRL-EVENT-", _type::binary>> = event) do
    event |> String.rstrip |> String.to_atom
  end
  def notif(<< "WPS-", _type::binary>> = event) do
    event |> String.rstrip |> String.to_atom
  end
  def notif(<< "AP-STA-CONNECTED ", mac::binary>>) do
    {:"AP-STA-CONNECTED", String.rstrip(mac)}
  end
  def notif(<< "AP-STA-DISCONNECTED ", mac::binary>>) do
    {:"AP-STA-DISCONNECTED", String.rstrip(mac)}
  end
  def notif(string) do
    {:INFO, String.rstrip(string)}
  end

  @doc """
  Decode responses from the wpa_supplicant

  The decoding of a response depends on the request, so pass the request as
  the first argument and the response as the second one.
  """
  def resp(req, resp) do
    # Strip the response of whitespace before trying to parse it.
    tresp(req, String.strip(resp))
  end

  defp tresp(:PING, "PONG"), do: :PONG
  defp tresp(:MIB, resp), do: kv_resp(resp)
  defp tresp(:STATUS, resp), do: kv_resp(resp)
  defp tresp(:"STATUS-VERBOSE", resp), do: kv_resp(resp)
  defp tresp({:BSS, _}, ""), do: nil
  defp tresp({:BSS, _}, resp), do: kv_resp(resp)
  defp tresp(:INTERFACES, resp), do: String.split(resp, "\n")
  defp tresp(:ADD_NETWORK, netid), do: String.to_integer(netid)
  defp tresp(_, "OK"), do: :ok
  defp tresp(_, "FAIL"), do: :FAIL
  defp tresp(_, << "\"", string::binary >>), do: String.rstrip(string, ?")
  defp tresp(_, resp), do: resp

  defp kv_resp(resp) do
    resp
      |> String.split("\n", trim: true)
      |> List.foldl(%{}, fn(pair, acc) ->
           [key, value] = String.split(pair, "=")
           Dict.put(acc, String.to_atom(key), kv_value(String.rstrip(value)))
         end)
  end

  defp kv_value("TRUE"), do: true
  defp kv_value("FALSE"), do: false
  defp kv_value(""), do: nil
  defp kv_value(<< "0x", hex::binary >>), do: kv_value(hex, 16)
  defp kv_value(str), do: kv_value(str, 10)

  defp kv_value(value, base) do
    try do
      String.to_integer(value, base)
    rescue
      ArgumentError -> value
    end
  end

end

# Copyright 2014 LKC Technologies, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

defmodule WpaSupplicant.Decode do
  @doc """
  Decode notifications from the wpa_supplicant
  """
  def notif(<< "CTRL-REQ-", rest::binary >>) do
    [field, net_id, text] = String.split(rest, "-", parts: 3, trim: true)
    {String.to_atom("CTRL-REQ-" <> field), String.to_integer(net_id), text}
  end
  def notif(<< "CTRL-EVENT-BSS-ADDED", rest::binary >>) do
    [entry_id, bssid] = String.split(rest, " ", trim: true)
    {:"CTRL-EVENT-BSS-ADDED", String.to_integer(entry_id), bssid}
  end
  def notif(<< "CTRL-EVENT-BSS-REMOVED", rest::binary >>) do
    [entry_id, bssid] = String.split(rest, " ", trim: true)
    {:"CTRL-EVENT-BSS-REMOVED", String.to_integer(entry_id), bssid}
  end
  def notif(<< "CTRL-EVENT-CONNECTED", _rest::binary >>) do
    :"CTRL-EVENT-CONNECTED"
  end
  def notif(<< "CTRL-EVENT-", _type::binary>> = event) do
    event |> String.rstrip |> String.to_atom
  end
  def notif(<< "WPS-", _type::binary>> = event) do
    event |> String.rstrip |> String.to_atom
  end
  def notif(<< "AP-STA-CONNECTED ", mac::binary>>) do
    {:"AP-STA-CONNECTED", String.rstrip(mac)}
  end
  def notif(<< "AP-STA-DISCONNECTED ", mac::binary>>) do
    {:"AP-STA-DISCONNECTED", String.rstrip(mac)}
  end
  def notif(string) do
    {:INFO, String.rstrip(string)}
  end

  @doc """
  Decode responses from the wpa_supplicant

  The decoding of a response depends on the request, so pass the request as
  the first argument and the response as the second one.
  """
  def resp(req, resp) do
    # Strip the response of whitespace before trying to parse it.
    tresp(req, String.strip(resp))
  end

  defp tresp(:PING, "PONG"), do: :PONG
  defp tresp(:MIB, resp), do: kv_resp(resp)
  defp tresp(:STATUS, resp), do: kv_resp(resp)
  defp tresp(:"STATUS-VERBOSE", resp), do: kv_resp(resp)
  defp tresp({:BSS, _}, ""), do: nil
  defp tresp({:BSS, _}, resp), do: kv_resp(resp)
  defp tresp(:INTERFACES, resp), do: String.split(resp, "\n")
  defp tresp(:ADD_NETWORK, netid), do: String.to_integer(netid)
  defp tresp(_, "OK"), do: :ok
  defp tresp(_, "FAIL"), do: :FAIL
  defp tresp(_, << "\"", string::binary >>), do: String.rstrip(string, ?")
  defp tresp(_, resp), do: resp

  defp kv_resp(resp) do
    resp
      |> String.split("\n", trim: true)
      |> List.foldl(%{}, fn(pair, acc) ->
           [key, value] = String.split(pair, "=")
           Dict.put(acc, String.to_atom(key), kv_value(String.rstrip(value)))
         end)
  end

  defp kv_value("TRUE"), do: true
  defp kv_value("FALSE"), do: false
  defp kv_value(""), do: nil
  defp kv_value(<< "0x", hex::binary >>), do: kv_value(hex, 16)
  defp kv_value(str), do: kv_value(str, 10)

  defp kv_value(value, base) do
    try do
      String.to_integer(value, base)
    rescue
      ArgumentError -> value
    end
  end

end


Doc formatting

Doc formatting

defmodule Trot.Router do
  @moduledoc """
  Module for creating routes based on the URL path.
  Routes are specified using one of the HTTP method macros:
  `get/2 post/2 put/2 patch/2 delete/2 options/2`.
  The first argument is a the path to route to, and the second argument is the
  block of code to execute. See examples below.

  ## Module attributes
  `@path_root`: URL path to prefix to all routes in the module. Defaults to "/".

  `@static_root`: File path to use as the root when looking for static files.
  Defaults to "priv/static".
  """

  alias Plug.Conn.Status
  require Logger

  @doc false
  defmacro __using__(_opts) do
    quote do
      import Trot.Router
      use Plug.Builder

      plug Plug.Logger
      plug :match
      plug :dispatch

      defp match(conn, _opts) do
        Plug.Conn.put_private(conn,
          :trot_route,
          do_match(conn.method, Enum.map(conn.path_info, &URI.decode/1), conn.host))
      end

      defp dispatch(%Plug.Conn{assigns: assigns} = conn, _opts) do
        Map.get(conn.private, :trot_route).(conn)
      end

      def call(conn, opts) do
        super(conn, opts)
        |> Trot.not_found(opts)
        |> assign(:called_all_plugs, true)
      end

      @static_root Path.relative_to_cwd("priv/static")
      @path_root "/"

      @before_compile Trot.Router
    end
  end

  defmacro __before_compile__(_env) do
    quote do
      def do_match(_method, _path, _host) do
        fn(conn) -> conn end
      end
    end
  end

  @doc ~S"""
  Encodes HTTP responses as appropriate and passes them to Plug.Conn.

  ## Examples

      # Sets status code to 200 with an empty body
      get "/" do
        200
      end

      # Returns an empty body with a status code of 404
      get "/bad" do
        :bad_request
      end

      # Sets the status code to 200 with a text body
      get "/text" do
        "Thank you for your question."
      end

      # Sets the status code to 201 with a text body
      get "/text/body" do
        {201, "Thank you for your question."}
      end

      # Sets status code to 200 with a JSON-encoded body
      get "/json" do
        %{"hyper" => "social"}
      end

      # Sets the status code to 201 with a JSON-encoded body
      get "/json/code" do
        {201, %{"hyper" => "social"}}
      end

      # Set the response manually as when using Plug directly
      get "/conn" do
        send_resp(conn, 200, "optimal tip-to-tip efficiency")
      end

      # Pattern match part of the path into a variable
      get "/presenter/:name" do
        "The presenter is #{name}"
      end

      # Redirect the incoming request
      get "/redirect" do
        {:redirect, "/text/body"}
      end
  """
  def make_response(%Plug.Conn{state: :set}, _conn) do
    raise ArgumentError, message: "conn must be sent before being returned"
  end
  def make_response(conn = %Plug.Conn{}, _conn), do: conn
  def make_response({:redirect, to}, conn), do: do_redirect(to, conn)
  def make_response(body, conn) when is_binary(body), do: make_response({:ok, body}, conn)
  def make_response(code, conn) when is_number(code), do: make_response({code, ""}, conn)
  def make_response(code, conn) when is_atom(code), do: make_response({Status.code(code), ""}, conn)
  def make_response({code, body}, conn) when is_atom(code), do: make_response({Status.code(code), body}, conn)
  def make_response({code, body}, conn) when is_number(code) and is_binary(body) do
    Plug.Conn.send_resp(conn, code, body)
  end
  def make_response({code, body}, conn) when is_number(code) do
    body = Poison.encode!(body)
    make_response({code, body}, conn)
  end
  def make_response(body, conn) do
    body = Poison.encode!(body)
    make_response({:ok, body}, conn)
  end

  @doc """
  Redirect the request to another location.
  """
  def do_redirect(path, conn) when is_binary(path) do
    Logger.info "Redirecting to #{path}"
    URI.parse(path) |> do_redirect(conn)
  end
  def do_redirect(uri = %URI{}, conn) do
    conn
    |> Plug.Conn.put_resp_header("Location", to_string(uri))
    |> Plug.Conn.send_resp(Status.code(:temporary_redirect), "")
  end

  defmacro get(path, options \\ [], do: body), do: compile(:get, path, options, body)
  defmacro post(path, options \\ [], do: body), do: compile(:post, path, options, body)
  defmacro put(path, options \\ [], do: body), do: compile(:put, path, options, body)
  defmacro patch(path, options \\ [], do: body), do: compile(:patch, path, options, body)
  defmacro delete(path, options \\ [], do: body), do: compile(:delete, path, options, body)
  defmacro options(path, options \\ [], do: body), do: compile(:options, path, options, body)

  @doc """
  Redirects all incoming requests for "from" to "to". The value of "to" will be put into the Location response header.
  """
  defmacro redirect(from, to) do
    body = quote do: {:redirect, unquote(to)}
    compile(:get, from, [], body)
  end

  @doc """
  Sets up a route to static assets. All requests beginning with "at" will look for a matching file under "from".
  @static_root will be prepended to "from" and defaults to "priv/static".

  ## Examples
      static "/js", "assets/js"

      @static_root "priv/assets/static"
      static "/css", "css"
  """
  defmacro static(at, from), do: static_plug(at, from)
  @doc """
  Sets up a route for static to path at the @static_root, which defaults to "priv/static".
  """
  defmacro static(at), do: static_plug(at, "/")

  defp static_plug(at, from) do
    quote do
      path = Path.join(@static_root, unquote(from))
      @plugs {Plug.Static, [at: unquote(at), from: path], true}
    end
  end

  # Entry point for both forward and match that is actually
  # responsible to compile the route.
  defp compile(method, expr, options, body) do
    options = sanitize_options(options)

    quote bind_quoted: [method: method,
                        options: options,
                        expr: expr,
                        body: Macro.escape(body, unquote: true)] do

      path = Path.join(@path_root, expr)
      {path, guards} = Trot.Router.extract_path_and_guards(path)
      {method, match, host, guards} = Plug.Router.__route__(method, path, guards, options)

      def do_match(unquote(method), unquote(match), unquote(host)) when unquote(guards) do
        fn var!(conn) -> unquote(body) |> Trot.Router.make_response(var!(conn)) end
      end
    end
  end

  defp sanitize_options(options), do: Enum.map(options, &default_keyword/1)

  defp default_keyword(item = {_key, _value}), do: item
  defp default_keyword(key) when is_atom(key), do: {key, true}

  @doc """
  Extract the path and guards from the path.
  """
  def extract_path_and_guards({:when, _, [path, guards]}), do: {extract_path(path), guards}
  def extract_path_and_guards(path), do: {extract_path(path), true}

  defp extract_path({:_, _, var}) when is_atom(var), do: "/*_path"
  defp extract_path(path), do: path
end