   @moduledoc """
   A module for working with applications and defining application callbacks.
 
-  In Elixir (actually, in Erlang/OTP), an application is a component
-  implementing some specific functionality, that can be started and stopped
-  as a unit, and which can be re-used in other systems.
-
-  Applications are defined with an application file named `APP.app` where
-  `APP` is the application name, usually in `underscore_case`. The application
-  file must reside in the same `ebin` directory as the compiled modules of the
-  application. In Elixir, the Mix build tool is responsible for compiling your
-  source code and generating your application `.app` file. You can learn more
-  about the generation of `.app` files by typing `mix help compile.app`.
+  Applications are the idiomatic way to package software in Erlang/OTP. To get
+  the idea, they are similar to the "library" concept common in other
+  programming languages, but with some additional characteristics.
+
+  An application is a component implementing some specific functionality, with a
+  standardized directory structure, configuration, and lifecycle. Applications
+  are *loaded*, *started*, and *stopped*.
+
+  ## The application resource file
+
+  Applications are specified in their [*resource
+  file*](http://erlang.org/doc/man/app.html), which is a file called `APP.app`,
+  where `APP` is the application name. For example, the application resource
+  file of the OTP application `ex_unit` is called `ex_unit.app`.
+
+  You'll find the resource file of an application in its `ebin` directory, it is
+  generated automatically by Mix. Some of its keys are taken from the keyword
+  lists returned by the `project/0` and `application/0` functions defined in
+  `mix.exs`, and others are generated by Mix itself.
+
+  You can learn more about the generation of application resource files in the
+  documentation of `Mix.Tasks.Compile.App`, available as well by running `mix
+  help compile.app`.
+
+  ## The application environment
+
+  The key `env` of an application resource file has a list of tuples that map
+  atoms to terms, and its contents are known as the application *environment*.
+  Note that this environment is unrelated to the operating system environment.
+
+  By default, the environment of an application is an empty list. In a Mix
+  project you can set that key in `application/0`:
+
+      def application do
+        [env: [redis_host: "localhost"]]
+      end
+
+  and the generated application resource file is going to have it included.
+
+  The environment is available after loading the application, which is a process
+  explained later:
+
+      Application.load(:APP_NAME)
+      #=> :ok
+
+      Application.get_env(:APP_NAME, :redis_host)
+      #=> "localhost"
+
+  In Mix projects, the environment of the application and its dependencies can
+  be overridden via the `config/config.exs` file. If you start the application
+  with Mix, that configuration is available at compile time, and at runtime too,
+  but take into account it is not included in the generated application resource
+  file, and it is not available if you start the application without Mix.
+
+  For example, someone using your application can override its `:redis_host`
+  environment variable as follows:
+
+      config :APP_NAME, redis_host: "redis.local"
+
+  The function `put_env/3` allows dynamic configuration of the application
+  environment, but as a rule of thumb each application is responsible for its
+  own environment. Please do not use the functions in this module for directly
+  accessing or modifying the environment of other applications.
+
+  The application environment can be overriden via the `-config` option of
+  `erl`, as well as command-line flags, as we are going to see below.
+
+  ## The application callback module
+
+  The `mod` key of an application resource file configures an application
+  callback module and start argument:
+
+      def application do
+        [mod: {MyApp, []}]
+      end
+
+  This key is optional, only needed for applications that start a supervision tree.
+
+  The `MyApp` module given to `:mod` needs to implement the `Application` behaviour.
+  This can be done by putting `use Application` in that module and implementing the
+  `c:start/2` callback, for example:
+
+      defmodule MyApp do
+        use Application
+
+        def start(_type, _args) do
+          children = []
+          Supervisor.start_link(children, strategy: :one_for_one)
+        end
+      end
+
+  The `c:start/2` callback has to spawn and link a supervisor and return `{:ok,
+  pid}` or `{:ok, pid, state}`, where `pid` is the PID of the supervisor, and
+  `state` is an optional application state. `args` is the second element of the
+  tuple given to the `:mod` option.
+
+  The `type` argument passed to `c:start/2` is usually `:normal` unless in a
+  distributed setup where application takeovers and failovers are configured.
+  Distributed applications are beyond the scope of this documentation.
+
+  When an application is shutting down, its `c:stop/1` callback is called after
+  the supervision tree has been stopped by the runtime. This callback allows the
+  application to do any final cleanup. The argument is the state returned by
+  `c:start/2`, if it did, or `[]` otherwise. The return value of `c:stop/1` is
+  ignored.
+
+  By using `Application`, modules get a default implementation of `c:stop/1`
+  that ignores its argument and returns `:ok`, but it can be overridden.
+
+  Application callback modules may also implement the optional callback
+  `c:prep_stop/1`. If present, `c:prep_stop/1` is invoked before the supervision
+  tree is terminated. Its argument is the state returned by `c:start/2`, if it did,
+  or `[]` otherwise, and its return value is passed to `c:stop/1`.
+
+  ## The application lifecycle
+
+  ### Loading applications
+
+  Applications are *loaded*, which means that the runtime finds and processes
+  their resource files:
+
+      Application.load(:ex_unit)
+      #=> :ok
+
+  If an application has included applications, they are also loaded. And the
+  procedure recurses if they in turn have included applications. Included
+  applications are unrelated to applications in Mix umbrella projects, they are
+  an Erlang/OTP concept that has to do with coordinated starts.
+
+  When an application is loaded, the environment specified in its resource file
+  is merged with any overrides from config files passed to `erl` via the
+  `-config` option. It is worth highlighting that releases pass `sys.config`
+  this way. The resulting environment can still be overridden again via specific
+  `-Application` flags passed to `erl`.
+
+  Loading an application *does not* load its modules.
+
+  In practice, you rarely load applications by hand because that is part of the
+  start process, explained next.
+
+  ### Starting applications
+
+  Applications are also *started*:
+
+      Application.start(:ex_unit)
+      #=> :ok
 
   Once your application is compiled, running your system is a matter of starting
   your current application and its dependencies. Differently from other languages,

  when tools must be shared between developers and not as deployment options.
  See `mix help archive.build` and `mix help escript.build` for more detail.

  ## Application environment

  Once an application is started, OTP provides an application environment
  that can be used to configure the application.

  Assuming you are inside a Mix project, you can edit the `application/0`
  function in the `mix.exs` file to the following:

      def application do
        [env: [hello: :world]]
      end

  In the application function, we can define the default environment values
  for our application. By starting your application with `iex -S mix`, you
  can access the default value:

      Application.get_env(:APP_NAME, :hello)
      #=> :world

  Applications and dependencies in Mix projects are typically configured
  via the `config/config.exs` file. For example, someone using your
  application can configure the `:hello` key as follows:

      config :APP_NAME, hello: :brand_new_world

  Keep in mind configuration files are only useful to configure static
  values. For example, if you need to configure your applications based
  on the system environment, the file system or on database entries,
  then those configurations are better placed at runtime. For example,
  one may configure applications dynamically via `put_env/3`.

  Keep in mind that each application is responsible for its environment.
  Do not use the functions in this module for directly accessing or modifying
  the environment of other applications (as it may lead to inconsistent
  data in the application environment).
  """

  @doc """

  system. Instead, you start one or more applications, each with their own
  initialization and termination logic.

  When an application is started, the runtime loads it if it hasn't been loaded
  yet (in the technical sense described above). Then, it checks if the
  dependencies listed in the `applications` key of the resource file are already
  started. Having at least one dependency not started is an error condition, but
  when you start an application with `mix run`, Mix takes care of starting all
  the dependencies for you, so in practice you don't need to worry about it
  unless you are starting applications manually with the API provided by this
  module.

  If the application does not have a callback module configured, starting is
  done at this point. Otherwise, its `c:start/2` callback if invoked. The PID of
  the top-level supervisor returned by this function is stored by the runtime
  for later use, and the returned application state is saved too, if any.

  ### Stopping applications

  Started applications are, finally, *stopped*:

      Application.stop(:ex_unit)
      #=> :ok

  Stopping an application without a callback module is defined, but except for
  some system tracing, it is in practice a no-op.

  Stopping an application with a callback module has three steps:

  1. If present, invoke the optional callback `c:prep_stop/1`.
  2. Terminate the top-level supervisor.
  3. Invoke the required callback `c:stop/1`.

  The arguments passed to the callbacks are related to the state optionally
  returned by `c:start/2`, and are documented in the section about the callback
  module above.

  It is important to highlight that step 2 is a blocking one. Termination of a
  supervisor triggers a recursive chain of children terminations, therefore
  orderly shutting down all descendant processes. The `c:stop/1` callback is
  invoked only after termination of the whole supervision tree.

  Shutting down a live system cleanly can be done by calling `System.stop/1`. It
  will shut down every application in the opposite order they had been started.

  From Erlang/OTP 19.1, a SIGTERM from the operating system will automatically
  translate to `System.stop/0`. Erlang/OTP 20 gives user more explicit control
  over OS signals via the `:os.set_signal/2` function.

  ## Tooling

