Clean up String.slice/2/3 impls

Clean up String.slice/2/3 impls

import Kernel, except: [length: 1]

defmodule String do
  @moduledoc ~S"""
  A String in Elixir is a UTF-8 encoded binary.

  ## String and binary operations

  The functions in this module act according to the
  Unicode Standard, version 6.3.0. For example,
  `capitalize/1`, `downcase/1`, `strip/1` are provided by this
  module.

  In addition to this module, Elixir provides more low-level
  operations that work directly with binaries. Some
  of those can be found in the `Kernel` module, as:

    * `Kernel.binary_part/3` - retrieves part of the binary
    * `Kernel.bit_size/1` and `Kernel.byte_size/1` - size related functions
    * `Kernel.is_bitstring/1` and `Kernel.is_binary/1` - type checking function
    * Plus a number of functions for working with binaries (bytes)
      [in the `:binary` module](http://erlang.org/doc/man/binary.html)

  ## Codepoints and graphemes

  As per the Unicode Standard, a codepoint is an Unicode
  Character, which may be represented by one or more bytes.
  For example, the character "é" is represented with two
  bytes:

      iex> byte_size("é")
      2

  However, this module returns the proper length:

      iex> String.length("é")
      1

  Furthermore, this module also presents the concept of
  graphemes, which are multiple characters that may be
  "perceived as a single character" by readers. For example,
  the same "é" character written above could be represented
  by the letter "e" followed by the accent ́:

      iex> string = "\x{0065}\x{0301}"
      iex> byte_size(string)
      3
      iex> String.length(string)
      1

  Although the example above is made of two characters, it is
  perceived by users as one.

  Graphemes can also be two characters that are interpreted
  as one by some languages. For example, some languages may
  consider "ch" as a grapheme. However, since this information
  depends on the locale, it is not taken into account by this
  module.

  In general, the functions in this module rely on the Unicode
  Standard, but does not contain any of the locale specific
  behaviour.

  More information about graphemes can be found in the [Unicode
  Standard Annex #29](http://www.unicode.org/reports/tr29/).
  This current Elixir version implements Extended Grapheme Cluster
  algorithm.

  ## Integer codepoints

  Although codepoints could be represented as integers, this
  module represents all codepoints as strings. For example:

      iex> String.codepoints("josé")
      ["j", "o", "s", "é"]

  There are a couple of ways to retrieve a character integer
  codepoint. One may use the `?` special macro:

      iex> ?j
      106

      iex> ?é
      233

  Or also via pattern matching:

      iex> << eacute :: utf8 >> = "é"
      iex> eacute
      233

  As we have seen above, codepoints can be inserted into
  a string by their hexadecimal code:

      "jos\x{0065}\x{0301}" #=>
      "josé"

  ## Self-synchronization

  The UTF-8 encoding is self-synchronizing. This means that
  if malformed data (i.e., data that is not possible according
  to the definition of the encoding) is encountered, only one
  codepoint needs to be rejected.

  This module relies on this behaviour to ignore such invalid
  characters. For example, `length/1` is going to return
  a correct result even if an invalid codepoint is fed into it.

  In other words, this module expects invalid data to be detected
  when retrieving data from the external source. For example, a
  driver that reads strings from a database will be the one
  responsible to check the validity of the encoding.
  """

  @type t :: binary
  @type codepoint :: t
  @type grapheme :: t

  @doc """
  Checks if a string is printable considering it is encoded
  as UTF-8. Returns `true` if so, `false` otherwise.

  ## Examples

      iex> String.printable?("abc")
      true

  """
  @spec printable?(t) :: boolean

  def printable?(<< h :: utf8, t :: binary >>)
      when h in ?\040..?\176
      when h in 0xA0..0xD7FF
      when h in 0xE000..0xFFFD
      when h in 0x10000..0x10FFFF do
    printable?(t)
  end

  def printable?(<<?\n, t :: binary>>), do: printable?(t)
  def printable?(<<?\r, t :: binary>>), do: printable?(t)
  def printable?(<<?\t, t :: binary>>), do: printable?(t)
  def printable?(<<?\v, t :: binary>>), do: printable?(t)
  def printable?(<<?\b, t :: binary>>), do: printable?(t)
  def printable?(<<?\f, t :: binary>>), do: printable?(t)
  def printable?(<<?\e, t :: binary>>), do: printable?(t)
  def printable?(<<?\d, t :: binary>>), do: printable?(t)
  def printable?(<<?\a, t :: binary>>), do: printable?(t)

  def printable?(<<>>), do: true
  def printable?(b) when is_binary(b), do: false

  @doc """
  Divides a string into substrings at each Unicode whitespace
  occurrence with leading and trailing whitespace ignored.

  ## Examples

      iex> String.split("foo bar")
      ["foo", "bar"]

      iex> String.split("foo" <> <<194, 133>> <> "bar")
      ["foo", "bar"]

      iex> String.split(" foo bar ")
      ["foo", "bar"]

  """
  @spec split(t) :: [t]
  defdelegate split(binary), to: String.Unicode

  @doc ~S"""
  Divides a string into substrings based on a pattern.

  Returns a list of these substrings. The pattern can
  be a string, a list of strings or a regular expression.

  The string is split into as many parts as possible by
  default, but can be controlled via the `parts: num` option.
  If you pass `parts: :infinity`, it will return all possible parts.

  Empty strings are only removed from the result if the
  `trim` option is set to `true`.

  ## Examples

  Splitting with a string pattern:

      iex> String.split("a,b,c", ",")
      ["a", "b", "c"]

      iex> String.split("a,b,c", ",", parts: 2)
      ["a", "b,c"]

      iex> String.split(" a b c ", " ", trim: true)
      ["a", "b", "c"]

  A list of patterns:

      iex> String.split("1,2 3,4", [" ", ","])
      ["1", "2", "3", "4"]

  A regular expression:

      iex> String.split("a,b,c", ~r{,})
      ["a", "b", "c"]

      iex> String.split("a,b,c", ~r{,}, parts: 2)
      ["a", "b,c"]

      iex> String.split(" a b c ", ~r{\s}, trim: true)
      ["a", "b", "c"]

  Splitting on empty patterns returns codepoints:

      iex> String.split("abc", ~r{})
      ["a", "b", "c", ""]

      iex> String.split("abc", "")
      ["a", "b", "c", ""]

      iex> String.split("abc", "", trim: true)
      ["a", "b", "c"]

      iex> String.split("abc", "", parts: 2)
      ["a", "bc"]

  """
  @spec split(t, t | [t] | Regex.t) :: [t]
  @spec split(t, t | [t] | Regex.t, Keyword.t) :: [t]
  def split(binary, pattern, options \\ [])

  def split("", _pattern, _options), do: [""]

  def split(binary, "", options) do
    index =
      case Keyword.get(options, :parts, :infinity) do
        num when is_number(num) and num > 0 -> num
        _ -> 0
      end
    split_codepoints(binary, index - 1, Keyword.get(options, :trim, false))
  end

  def split(binary, pattern, options) do
    if Regex.regex?(pattern) do
      Regex.split(pattern, binary, options)
    else
      splits =
        case Keyword.get(options, :parts, :infinity) do
          num when is_number(num) and num > 0 ->
            split_parts(binary, pattern, num - 1)
          _ ->
            :binary.split(binary, pattern, [:global])
        end

      if Keyword.get(options, :trim, false) do
        for split <- splits, split != "", do: split
      else
        splits
      end
    end
  end

  defp split_codepoints(binary, 0, _trim), do: [binary]
  defp split_codepoints(<<h :: utf8, t :: binary>>, count, trim),
    do: [<<h :: utf8>>|split_codepoints(t, count - 1, trim)]
  defp split_codepoints(<<h, t :: binary>>, count, trim),
    do: [<<h>>|split_codepoints(t, count - 1, trim)]
  defp split_codepoints(<<>>, _, true), do: []
  defp split_codepoints(<<>>, _, false), do: [""]

  defp split_parts("", _pattern, _num),         do: [""]
  defp split_parts(binary, pattern, num),       do: split_parts(binary, pattern, num, [])
  defp split_parts("", _pattern, _num, parts),  do: Enum.reverse([""|parts])
  defp split_parts(binary, _pattern, 0, parts), do: Enum.reverse([binary|parts])
  defp split_parts(binary, pattern, num, parts) do
    case :binary.split(binary, pattern) do
      [head]       -> Enum.reverse([head|parts])
      [head, rest] -> split_parts(rest, pattern, num - 1, [head|parts])
    end
  end

  @doc """
  Splits a string into two at the specified offset. When the offset given is
  negative, location is counted from the end of the string.

  The offset is capped to the length of the string.

  Returns a tuple with two elements.

  ## Examples

      iex> String.split_at "sweetelixir", 5
      {"sweet", "elixir"}

      iex> String.split_at "sweetelixir", -6
      {"sweet", "elixir"}

      iex> String.split_at "abc", 0
      {"", "abc"}

      iex> String.split_at "abc", 1000
      {"abc", ""}

      iex> String.split_at "abc", -1000
      {"", "abc"}

  """
  @spec split_at(t, integer) :: {t, t}
  def split_at(string, offset)

  def split_at(binary, index) when index == 0, do:
    {"", binary}

  def split_at(binary, index) when index > 0, do:
    do_split_at(next_grapheme(binary), 0, index, "")

  def split_at(binary, index) when index < 0, do:
    do_split_at(next_grapheme(binary), 0, max(0, byte_size(binary)+index), "")

  defp do_split_at(nil, _, _, acc), do:
    {acc, ""}

  defp do_split_at({grapheme, rest}, current_pos, target_pos, acc) when current_pos < target_pos, do:
    do_split_at(next_grapheme(rest), current_pos+1, target_pos, acc <> grapheme)

  defp do_split_at({grapheme, rest}, pos, pos, acc), do:
    {acc, grapheme <> rest}

  @doc """
  Convert all characters on the given string to uppercase.

  ## Examples

      iex> String.upcase("abcd")
      "ABCD"

      iex> String.upcase("ab 123 xpto")
      "AB 123 XPTO"

      iex> String.upcase("josé")
      "JOSÉ"

  """
  @spec upcase(t) :: t
  defdelegate upcase(binary), to: String.Unicode

  @doc """
  Convert all characters on the given string to lowercase.

  ## Examples

      iex> String.downcase("ABCD")
      "abcd"

      iex> String.downcase("AB 123 XPTO")
      "ab 123 xpto"

      iex> String.downcase("JOSÉ")
      "josé"

  """
  @spec downcase(t) :: t
  defdelegate downcase(binary), to: String.Unicode

  @doc """
  Converts the first character in the given string to
  uppercase and the remaining to lowercase.

  This relies on the titlecase information provided
  by the Unicode Standard. Note this function makes
  no attempt to capitalize all words in the string
  (usually known as titlecase).

  ## Examples

      iex> String.capitalize("abcd")
      "Abcd"

      iex> String.capitalize("ﬁn")
      "Fin"

      iex> String.capitalize("josé")
      "José"

  """
  @spec capitalize(t) :: t
  def capitalize(string) when is_binary(string) do
    {char, rest} = String.Unicode.titlecase_once(string)
    char <> downcase(rest)
  end

  @doc """
  Returns a string where trailing Unicode whitespace
  has been removed.

  ## Examples

      iex> String.rstrip("   abc  ")
      "   abc"

  """
  @spec rstrip(t) :: t
  defdelegate rstrip(binary), to: String.Unicode

  @doc """
  Returns a string where trailing `char` have been removed.

  ## Examples

      iex> String.rstrip("   abc _", ?_)
      "   abc "

  """
  @spec rstrip(t, char) :: t

  def rstrip("", _char), do: ""

  # Do a quick check before we traverse the whole
  # binary. :binary.last is a fast operation (it
  # does not traverse the whole binary).
  def rstrip(string, char) when char in 0..127 do
    if :binary.last(string) == char do
      do_rstrip(string, "", char)
    else
      string
    end
  end

  def rstrip(string, char) when is_integer(char) do
    do_rstrip(string, "", char)
  end

  defp do_rstrip(<<char :: utf8, string :: binary>>, buffer, char) do
    <<do_rstrip(string, <<char :: utf8, buffer :: binary>>, char) :: binary>>
  end

  defp do_rstrip(<<char :: utf8, string :: binary>>, buffer, another_char) do
    <<buffer :: binary, char :: utf8, do_rstrip(string, "", another_char) :: binary>>
  end

  defp do_rstrip(<<>>, _, _) do
    <<>>
  end

  @doc """
  Returns a string where leading Unicode whitespace
  has been removed.

  ## Examples

      iex> String.lstrip("   abc  ")
      "abc  "

  """
  defdelegate lstrip(binary), to: String.Unicode

  @doc """
  Returns a string where leading `char` have been removed.

  ## Examples

      iex> String.lstrip("_  abc  _", ?_)
      "  abc  _"

  """

  @spec lstrip(t, char) :: t

  def lstrip(<<char :: utf8, rest :: binary>>, char) when is_integer(char) do
    <<lstrip(rest, char) :: binary>>
  end

  def lstrip(other, char) when is_integer(char) do
    other
  end

  @doc """
  Returns a string where leading/trailing Unicode whitespace
  has been removed.

  ## Examples

      iex> String.strip("   abc  ")
      "abc"

  """
  @spec strip(t) :: t

  def strip(string) do
    rstrip(lstrip(string))
  end

  @doc """
  Returns a string where leading/trailing `char` have been
  removed.

  ## Examples

      iex> String.strip("a  abc  a", ?a)
      "  abc  "

  """
  @spec strip(t, char) :: t

  def strip(string, char) do
    rstrip(lstrip(string, char), char)
  end

  @doc ~S"""
  Returns a new string of length `len` with `subject` right justified and
  padded with `padding`. If `padding` is not present, it defaults to
  whitespace. When `len` is less than the length of `subject`, `subject` is
  returned.

  ## Examples

      iex> String.rjust("abc", 5)
      "  abc"

      iex> String.rjust("abc", 5, ?-)
      "--abc"

  """
  @spec rjust(t, pos_integer) :: t
  @spec rjust(t, pos_integer, char) :: t

  def rjust(subject, len) do
    rjust(subject, len, ?\s)
  end

  def rjust(subject, len, padding) when is_integer(padding) do
    do_justify(subject, len, padding, :right)
  end

  @doc ~S"""
  Returns a new string of length `len` with `subject` left justified and padded
  with `padding`. If `padding` is not present, it defaults to whitespace. When
  `len` is less than the length of `subject`, `subject` is returned.

  ## Examples

      iex> String.ljust("abc", 5)
      "abc  "

      iex> String.ljust("abc", 5, ?-)
      "abc--"

  """
  @spec ljust(t, pos_integer) :: t
  @spec ljust(t, pos_integer, char) :: t

  def ljust(subject, len) do
    ljust(subject, len, ?\s)
  end

  def ljust(subject, len, padding) when is_integer(padding) do
    do_justify(subject, len, padding, :left)
  end

  defp do_justify(subject, 0, _padding, _type) do
    subject
  end

  defp do_justify(subject, len, padding, type) when is_integer(padding) do
    subject_len = length(subject)

    cond do
      subject_len >= len ->
        subject
      subject_len < len ->
        fill = duplicate(<<padding :: utf8>>, len - subject_len)

        case type do
          :left  -> subject <> fill
          :right -> fill <> subject
        end
    end
  end

  @doc ~S"""
  Returns a new binary based on `subject` by replacing the parts
  matching `pattern` by `replacement`. By default, it replaces
  all entries, except if the `global` option is set to `false`.

  A `pattern` may be a string or a regex.

  ## Examples

      iex> String.replace("a,b,c", ",", "-")
      "a-b-c"

      iex> String.replace("a,b,c", ",", "-", global: false)
      "a-b,c"

  The pattern can also be a regex. In those cases, one can give `\N`
  in the `replacement` string to access a specific capture in the regex:

      iex> String.replace("a,b,c", ~r/,(.)/, ",\\1\\1")
      "a,bb,cc"

  Notice we had to escape the escape character `\`. By giving `&`,
  one can inject the whole matched pattern in the replacement string.

  When strings are used as a pattern, a developer can also use the
  replaced part inside the `replacement` via the `:insert_replaced` option:

      iex> String.replace("a,b,c", "b", "[]", insert_replaced: 1)
      "a,[b],c"

      iex> String.replace("a,b,c", ",", "[]", insert_replaced: 2)
      "a[],b[],c"

      iex> String.replace("a,b,c", ",", "[]", insert_replaced: [1, 1])
      "a[,,]b[,,]c"

  """
  @spec replace(t, t, t) :: t
  @spec replace(t, t, t, Keyword.t) :: t

  def replace(subject, pattern, replacement, options \\ []) when is_binary(replacement) do
    if Regex.regex?(pattern) do
      Regex.replace(pattern, subject, replacement, global: options[:global])
    else
      opts = translate_replace_options(options)
      :binary.replace(subject, pattern, replacement, opts)
    end
  end

  defp translate_replace_options(options) do
    opts = if Keyword.get(options, :global) != false, do: [:global], else: []

    if insert = Keyword.get(options, :insert_replaced) do
      opts = [{:insert_replaced, insert}|opts]
    end

    opts
  end

  @doc """
  Reverses the given string. Works on graphemes.

  ## Examples

      iex> String.reverse("abcd")
      "dcba"

      iex> String.reverse("hello world")
      "dlrow olleh"

      iex> String.reverse("hello ∂og")
      "go∂ olleh"

  """
  @spec reverse(t) :: t
  def reverse(string) do
    do_reverse(next_grapheme(string), [])
  end

  defp do_reverse({grapheme, rest}, acc) do
    do_reverse(next_grapheme(rest), [grapheme|acc])
  end

  defp do_reverse(nil, acc), do: IO.iodata_to_binary(acc)

  @doc """
  Returns a binary `subject` duplicated `n` times.

  ## Examples

      iex> String.duplicate("abc", 0)
      ""

      iex> String.duplicate("abc", 1)
      "abc"

      iex> String.duplicate("abc", 2)
      "abcabc"

  """
  @spec duplicate(t, pos_integer) :: t
  def duplicate(subject, n) when is_integer(n) and n >= 0 do
    :binary.copy(subject, n)
  end

  @doc """
  Returns all codepoints in the string.

  ## Examples

      iex> String.codepoints("josé")
      ["j", "o", "s", "é"]

      iex> String.codepoints("оптими зации")
      ["о","п","т","и","м","и"," ","з","а","ц","и","и"]

      iex> String.codepoints("ἅἪῼ")
      ["ἅ","Ἢ","ῼ"]

  """
  @spec codepoints(t) :: [codepoint]
  defdelegate codepoints(string), to: String.Unicode

  @doc """
  Returns the next codepoint in a String.

  The result is a tuple with the codepoint and the
  remaining of the string or `nil` in case
  the string reached its end.

  As with other functions in the String module, this
  function does not check for the validity of the codepoint.
  That said, if an invalid codepoint is found, it will
  be returned by this function.

  ## Examples

      iex> String.next_codepoint("josé")
      {"j", "osé"}

  """
  @compile {:inline, next_codepoint: 1}
  @spec next_codepoint(t) :: {codepoint, t} | nil
  defdelegate next_codepoint(string), to: String.Unicode

  @doc ~S"""
  Checks whether `str` contains only valid characters.

  ## Examples

      iex> String.valid?("a")
      true

      iex> String.valid?("ø")
      true

      iex> String.valid?(<<0xffff :: 16>>)
      false

      iex> String.valid?("asd" <> <<0xffff :: 16>>)
      false

  """
  @spec valid?(t) :: boolean

  noncharacters = Enum.to_list(?\x{FDD0}..?\x{FDEF}) ++
    [ ?\x{0FFFE}, ?\x{0FFFF}, ?\x{1FFFE}, ?\x{1FFFF}, ?\x{2FFFE}, ?\x{2FFFF},
      ?\x{3FFFE}, ?\x{3FFFF}, ?\x{4FFFE}, ?\x{4FFFF}, ?\x{5FFFE}, ?\x{5FFFF},
      ?\x{6FFFE}, ?\x{6FFFF}, ?\x{7FFFE}, ?\x{7FFFF}, ?\x{8FFFE}, ?\x{8FFFF},
      ?\x{9FFFE}, ?\x{9FFFF}, ?\x{10FFFE}, ?\x{10FFFF} ]

  for noncharacter <- noncharacters do
    def valid?(<< unquote(noncharacter) :: utf8, _ :: binary >>), do: false
  end

  def valid?(<<_ :: utf8, t :: binary>>), do: valid?(t)
  def valid?(<<>>), do: true
  def valid?(_), do: false

  @doc ~S"""
  Checks whether `str` is a valid character.

  All characters are codepoints, but some codepoints
  are not valid characters. They may be reserved, private,
  or other.

  More info at: http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Noncharacters

  ## Examples

      iex> String.valid_character?("a")
      true

      iex> String.valid_character?("ø")
      true

      iex> String.valid_character?("\x{ffff}")
      false

  """
  @spec valid_character?(t) :: boolean

  def valid_character?(<<_ :: utf8>> = codepoint), do: valid?(codepoint)
  def valid_character?(_), do: false

  @doc ~S"""
  Splits the string into chunks of characters that share a common trait.

  The trait can be one of two options:

    * `:valid` – the string is split into chunks of valid and invalid character
      sequences

    * `:printable` – the string is split into chunks of printable and
      non-printable character sequences

  Returns a list of binaries each of which contains only one kind of
  characters.

  If the given string is empty, an empty list is returned.

  ## Examples

      iex> String.chunk(<<?a, ?b, ?c, 0>>, :valid)
      ["abc\000"]

      iex> String.chunk(<<?a, ?b, ?c, 0, 0x0ffff::utf8>>, :valid)
      ["abc\000", <<0x0ffff::utf8>>]

      iex> String.chunk(<<?a, ?b, ?c, 0, 0x0ffff::utf8>>, :printable)
      ["abc", <<0, 0x0ffff::utf8>>]

  """
  @spec chunk(t, :valid | :printable) :: [t]

  def chunk(string, trait)

  def chunk("", _), do: []

  def chunk(str, trait) when trait in [:valid, :printable] do
    {cp, _} = next_codepoint(str)
    pred_fn = make_chunk_pred(trait)
    do_chunk(str, pred_fn.(cp), pred_fn)
  end

  defp do_chunk(str, flag, pred_fn), do: do_chunk(str, [], <<>>, flag, pred_fn)

  defp do_chunk(<<>>, acc, <<>>, _, _), do: Enum.reverse(acc)

  defp do_chunk(<<>>, acc, chunk, _, _), do: Enum.reverse(acc, [chunk])

  defp do_chunk(str, acc, chunk, flag, pred_fn) do
    {cp, rest} = next_codepoint(str)
    if pred_fn.(cp) != flag do
      do_chunk(rest, [chunk|acc], cp, not flag, pred_fn)
    else
      do_chunk(rest, acc, chunk <> cp, flag, pred_fn)
    end
  end

  defp make_chunk_pred(:valid), do: &valid?/1
  defp make_chunk_pred(:printable), do: &printable?/1

  @doc """
  Returns unicode graphemes in the string as per Extended Grapheme
  Cluster algorithm outlined in the [Unicode Standard Annex #29,
  Unicode Text Segmentation](http://www.unicode.org/reports/tr29/).

  ## Examples

      iex> String.graphemes("Ā̀stute")
      ["Ā̀","s","t","u","t","e"]

  """
  @spec graphemes(t) :: [grapheme]
  defdelegate graphemes(string), to: String.Graphemes

  @doc """
  Returns the next grapheme in a String.

  The result is a tuple with the grapheme and the
  remaining of the string or `nil` in case
  the String reached its end.

  ## Examples

      iex> String.next_grapheme("josé")
      {"j", "osé"}

  """
  @compile {:inline, next_grapheme: 1}
  @spec next_grapheme(t) :: {grapheme, t} | nil
  defdelegate next_grapheme(string), to: String.Graphemes

  @doc """
  Returns the first grapheme from an utf8 string,
  nil if the string is empty.

  ## Examples

      iex> String.first("elixir")
      "e"

      iex> String.first("եոգլի")
      "ե"

  """
  @spec first(t) :: grapheme | nil
  def first(string) do
    case next_grapheme(string) do
      {char, _} -> char
      nil -> nil
    end
  end

  @doc """
  Returns the last grapheme from an utf8 string,
  `nil` if the string is empty.

  ## Examples

      iex> String.last("elixir")
      "r"

      iex> String.last("եոգլի")
      "ի"

  """
  @spec last(t) :: grapheme | nil
  def last(string) do
    do_last(next_grapheme(string), nil)
  end

  defp do_last({char, rest}, _) do
    do_last(next_grapheme(rest), char)
  end

  defp do_last(nil, last_char), do: last_char

  @doc """
  Returns the number of unicode graphemes in an utf8 string.

  ## Examples

      iex> String.length("elixir")
      6

      iex> String.length("եոգլի")
      5

  """
  @spec length(t) :: non_neg_integer
  def length(string) do
    do_length(next_grapheme(string))
  end

  defp do_length({_, rest}) do
    1 + do_length(next_grapheme(rest))
  end

  defp do_length(nil), do: 0

  @doc """
  Returns the grapheme in the `position` of the given utf8 `string`.
  If `position` is greater than `string` length, then it returns `nil`.

  ## Examples

      iex> String.at("elixir", 0)
      "e"

      iex> String.at("elixir", 1)
      "l"

      iex> String.at("elixir", 10)
      nil

      iex> String.at("elixir", -1)
      "r"

      iex> String.at("elixir", -10)
      nil

  """
  @spec at(t, integer) :: grapheme | nil

  def at(string, position) when position >= 0 do
    do_at(next_grapheme(string), position, 0)
  end

  def at(string, position) when position < 0 do
    real_pos = length(string) - abs(position)
    case real_pos >= 0 do
      true  -> do_at(next_grapheme(string), real_pos, 0)
      false -> nil
    end
  end

  defp do_at({_ , rest}, desired_pos, current_pos) when desired_pos > current_pos do
    do_at(next_grapheme(rest), desired_pos, current_pos + 1)
  end

  defp do_at({char, _}, desired_pos, current_pos) when desired_pos == current_pos do
    char
  end

  defp do_at(nil, _, _), do: nil

  @doc """
  Returns a substring starting at the offset given by the first, and
  a length given by the second.

  If the offset is greater than string length, then it returns `""`.

  Remember this function works with unicode codepoints and consider
  the slices to represent codepoints offsets. If you want to split
  on raw bytes, check `Kernel.binary_part/3` instead.

  ## Examples

      iex> String.slice("elixir", 1, 3)
      "lix"

      iex> String.slice("elixir", 1, 10)
      "lixir"

      iex> String.slice("elixir", 10, 3)
      ""

      iex> String.slice("elixir", -4, 4)
      "ixir"

      iex> String.slice("elixir", -10, 3)
      ""

      iex> String.slice("a", 0, 1500)
      "a"

      iex> String.slice("a", 1, 1500)
      ""

      iex> String.slice("a", 2, 1500)
      ""

  """
  @spec slice(t, integer, integer) :: grapheme

  def slice(_, _, 0) do
    ""
  end

  def slice(string, start, len) when start >= 0 and len >= 0 do
    case do_count_bytes(next_grapheme(string), start, 0) do
      {nil, _} -> ""
      {next, start_bytes} ->
        {_, len_bytes} = do_count_bytes(next, len, 0)
        binary_part(string, start_bytes, len_bytes)
    end
  end

  def slice(string, start, len) when start < 0 and len >= 0 do
    start = length(string) + start
    case start >= 0 do
      true  -> slice(string, start, len)
      false -> ""
    end
  end

  defp do_count_bytes(next, 0, acc), do: {next, acc}
  defp do_count_bytes(nil, _, acc),  do: {nil, acc}

  defp do_count_bytes({char, rest}, counter, acc) do
    do_count_bytes(next_grapheme(rest), counter - 1, acc + byte_size(char))
  end

  @doc """
  Returns a substring from the offset given by the start of the
  range to the offset given by the end of the range.

  If the start of the range is not a valid offset for the given
  string or if the range is in reverse order, returns `""`.

  If the start or end of the range are negative, the whole string
  is traversed first in order to convert the negative indexes into
  positive ones.

  Remember this function works with unicode codepoints and consider
  the slices to represent codepoints offsets. If you want to split
  on raw bytes, check `Kernel.binary_part/3` instead.

  ## Examples

      iex> String.slice("elixir", 1..3)
      "lix"

      iex> String.slice("elixir", 1..10)
      "lixir"

      iex> String.slice("elixir", 10..3)
      ""

      iex> String.slice("elixir", -4..-1)
      "ixir"

      iex> String.slice("elixir", 2..-1)
      "ixir"

      iex> String.slice("elixir", -4..6)
      "ixir"

      iex> String.slice("elixir", -1..-4)
      ""

      iex> String.slice("elixir", -10..-7)
      ""

      iex> String.slice("a", 0..1500)
      "a"

      iex> String.slice("a", 1..1500)
      ""

  """
  @spec slice(t, Range.t) :: t

  def slice(string, range)

  def slice("", _.._), do: ""

  def slice(string, first..-1) when first >= 0 do
    case do_count_bytes(next_grapheme(string), first, 0) do
      {nil, _} -> ""
      {_, start_bytes} -> binary_part(string, start_bytes, byte_size(string) - start_bytes)
    end
  end

  def slice(string, first..last) when first >= 0 and last >= 0 do
    if last >= first do
      slice(string, first, last - first + 1)
    else
      ""
    end
  end

  def slice(string, first..last) do
    {bytes, length} = do_acc_bytes(next_grapheme(string), [], 0)

    if first < 0, do: first = length + first
    if last < 0,  do: last  = length + last

    if first < 0 or first > last or first > length do
      ""
    else
      last  = min(last + 1, length)
      bytes = Enum.drop(bytes, length - last)
      first = last - first
      {length_bytes, start_bytes} = Enum.split(bytes, first)
      binary_part(string, Enum.sum(start_bytes), Enum.sum(length_bytes))
    end
  end

  defp do_acc_bytes({char, rest}, bytes, length) do
    do_acc_bytes(next_grapheme(rest), [byte_size(char)|bytes], length + 1)
  end

  defp do_acc_bytes(nil, bytes, length) do
    {bytes, length}
  end

  @doc """
  Returns `true` if `string` starts with any of the prefixes given, otherwise
  `false`. `prefixes` can be either a single prefix or a list of prefixes.

  ## Examples

      iex> String.starts_with? "elixir", "eli"
      true

      iex> String.starts_with? "elixir", ["erlang", "elixir"]
      true

      iex> String.starts_with? "elixir", ["erlang", "ruby"]
      false

  """
  @spec starts_with?(t, t | [t]) :: boolean

  def starts_with?(string, prefixes) when is_list(prefixes) do
    Enum.any?(prefixes, &do_starts_with(string, &1))
  end

  def starts_with?(string, prefix) do
    do_starts_with(string, prefix)
  end

  defp do_starts_with(string, "") when is_binary(string) do
    true
  end

  defp do_starts_with(string, prefix) when is_binary(prefix) do
    Kernel.match?({0, _}, :binary.match(string, prefix))
  end

  @doc """
  Returns `true` if `string` ends with any of the suffixes given, otherwise
  `false`. `suffixes` can be either a single suffix or a list of suffixes.

  ## Examples

      iex> String.ends_with? "language", "age"
      true

      iex> String.ends_with? "language", ["youth", "age"]
      true

      iex> String.ends_with? "language", ["youth", "elixir"]
      false

  """
  @spec ends_with?(t, t | [t]) :: boolean

  def ends_with?(string, suffixes) when is_list(suffixes) do
    Enum.any?(suffixes, &do_ends_with(string, &1))
  end

  def ends_with?(string, suffix) do
    do_ends_with(string, suffix)
  end

  defp do_ends_with(string, "") when is_binary(string) do
    true
  end

  defp do_ends_with(string, suffix) when is_binary(suffix) do
    string_size = byte_size(string)
    suffix_size = byte_size(suffix)
    scope = {string_size - suffix_size, suffix_size}
    (suffix_size <= string_size) and (:nomatch != :binary.match(string, suffix, [scope: scope]))
  end

  @doc """
  Check if `string` matches the given regular expression.

  ## Examples

      iex> String.match?("foo", ~r/foo/)
      true

      iex> String.match?("bar", ~r/foo/)
      false

  """
  @spec match?(t, Regex.t) :: boolean
  def match?(string, regex) do
    Regex.match?(regex, string)
  end

  @doc """
  Check if `string` contains any of the given `contents`.

  `matches` can be either a single string or a list of strings.

  ## Examples

      iex> String.contains? "elixir of life", "of"
      true

      iex> String.contains? "elixir of life", ["life", "death"]
      true

      iex> String.contains? "elixir of life", ["death", "mercury"]
      false

  """
  @spec contains?(t, t | [t]) :: boolean

  def contains?(string, contents) when is_list(contents) do
    Enum.any?(contents, &do_contains(string, &1))
  end

  def contains?(string, content) do
    do_contains(string, content)
  end

  defp do_contains(string, "") when is_binary(string) do
    true
  end

  defp do_contains(string, match) when is_binary(match) do
    :nomatch != :binary.match(string, match)
  end

  @doc """
  Converts a string into a char list.

  ## Examples

      iex> String.to_char_list("æß")
      'æß'

  Notice that this function expect a list of integer representing
  UTF-8 codepoints. If you have a raw binary, you must instead use
  [the `:binary` module](http://erlang.org/doc/man/binary.html).
  """
  @spec to_char_list(t) :: char_list
  def to_char_list(string) when is_binary(string) do
    case :unicode.characters_to_list(string) do
      result when is_list(result) ->
        result

      {:error, encoded, rest} ->
        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :invalid

      {:incomplete, encoded, rest} ->
        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :incomplete
    end
  end

  @doc """
  Converts a string to an atom.

  Currently Elixir does not support conversions from strings
  which contains Unicode codepoints greater than 0xFF.

  Inlined by the compiler.

  ## Examples

      iex> String.to_atom("my_atom")
      :my_atom

  """
  @spec to_atom(String.t) :: atom
  def to_atom(string) do
    :erlang.binary_to_atom(string, :utf8)
  end

  @doc """
  Converts a string to an existing atom.

  Currently Elixir does not support conversions from strings
  which contains Unicode codepoints greater than 0xFF.

  Inlined by the compiler.

  ## Examples

      iex> :my_atom
      iex> String.to_existing_atom("my_atom")
      :my_atom

      iex> String.to_existing_atom("this_atom_will_never_exist")
      ** (ArgumentError) argument error

  """
  @spec to_existing_atom(String.t) :: atom
  def to_existing_atom(string) do
    :erlang.binary_to_existing_atom(string, :utf8)
  end

  @doc """
  Returns a integer whose text representation is `string`.

  Inlined by the compiler.

  ## Examples

      iex> String.to_integer("123")
      123

  """
  @spec to_integer(String.t) :: integer
  def to_integer(string) do
    :erlang.binary_to_integer(string)
  end

  @doc """
  Returns an integer whose text representation is `string` in base `base`.

  Inlined by the compiler.

  ## Examples

      iex> String.to_integer("3FF", 16)
      1023

  """
  @spec to_integer(String.t, pos_integer) :: integer
  def to_integer(string, base) do
    :erlang.binary_to_integer(string, base)
  end

  @doc """
  Returns a float whose text representation is `string`.

  Inlined by the compiler.

  ## Examples

      iex> String.to_float("2.2017764e+0")
      2.2017764

  """
  @spec to_float(String.t) :: float
  def to_float(string) do
    :erlang.binary_to_float(string)
  end
end

import Kernel, except: [length: 1]

defmodule String do
  @moduledoc ~S"""
  A String in Elixir is a UTF-8 encoded binary.

  ## String and binary operations

  The functions in this module act according to the
  Unicode Standard, version 6.3.0. For example,
  `capitalize/1`, `downcase/1`, `strip/1` are provided by this
  module.

  In addition to this module, Elixir provides more low-level
  operations that work directly with binaries. Some
  of those can be found in the `Kernel` module, as:

    * `Kernel.binary_part/3` - retrieves part of the binary
    * `Kernel.bit_size/1` and `Kernel.byte_size/1` - size related functions
    * `Kernel.is_bitstring/1` and `Kernel.is_binary/1` - type checking function
    * Plus a number of functions for working with binaries (bytes)
      [in the `:binary` module](http://erlang.org/doc/man/binary.html)

  ## Codepoints and graphemes

  As per the Unicode Standard, a codepoint is an Unicode
  Character, which may be represented by one or more bytes.
  For example, the character "é" is represented with two
  bytes:

      iex> byte_size("é")
      2

  However, this module returns the proper length:

      iex> String.length("é")
      1

  Furthermore, this module also presents the concept of
  graphemes, which are multiple characters that may be
  "perceived as a single character" by readers. For example,
  the same "é" character written above could be represented
  by the letter "e" followed by the accent ́:

      iex> string = "\x{0065}\x{0301}"
      iex> byte_size(string)
      3
      iex> String.length(string)
      1

  Although the example above is made of two characters, it is
  perceived by users as one.

  Graphemes can also be two characters that are interpreted
  as one by some languages. For example, some languages may
  consider "ch" as a grapheme. However, since this information
  depends on the locale, it is not taken into account by this
  module.

  In general, the functions in this module rely on the Unicode
  Standard, but does not contain any of the locale specific
  behaviour.

  More information about graphemes can be found in the [Unicode
  Standard Annex #29](http://www.unicode.org/reports/tr29/).
  This current Elixir version implements Extended Grapheme Cluster
  algorithm.

  ## Integer codepoints

  Although codepoints could be represented as integers, this
  module represents all codepoints as strings. For example:

      iex> String.codepoints("josé")
      ["j", "o", "s", "é"]

  There are a couple of ways to retrieve a character integer
  codepoint. One may use the `?` special macro:

      iex> ?j
      106

      iex> ?é
      233

  Or also via pattern matching:

      iex> << eacute :: utf8 >> = "é"
      iex> eacute
      233

  As we have seen above, codepoints can be inserted into
  a string by their hexadecimal code:

      "jos\x{0065}\x{0301}" #=>
      "josé"

  ## Self-synchronization

  The UTF-8 encoding is self-synchronizing. This means that
  if malformed data (i.e., data that is not possible according
  to the definition of the encoding) is encountered, only one
  codepoint needs to be rejected.

  This module relies on this behaviour to ignore such invalid
  characters. For example, `length/1` is going to return
  a correct result even if an invalid codepoint is fed into it.

  In other words, this module expects invalid data to be detected
  when retrieving data from the external source. For example, a
  driver that reads strings from a database will be the one
  responsible to check the validity of the encoding.
  """

  @type t :: binary
  @type codepoint :: t
  @type grapheme :: t

  @doc """
  Checks if a string is printable considering it is encoded
  as UTF-8. Returns `true` if so, `false` otherwise.

  ## Examples

      iex> String.printable?("abc")
      true

  """
  @spec printable?(t) :: boolean

  def printable?(<< h :: utf8, t :: binary >>)
      when h in ?\040..?\176
      when h in 0xA0..0xD7FF
      when h in 0xE000..0xFFFD
      when h in 0x10000..0x10FFFF do
    printable?(t)
  end

  def printable?(<<?\n, t :: binary>>), do: printable?(t)
  def printable?(<<?\r, t :: binary>>), do: printable?(t)
  def printable?(<<?\t, t :: binary>>), do: printable?(t)
  def printable?(<<?\v, t :: binary>>), do: printable?(t)
  def printable?(<<?\b, t :: binary>>), do: printable?(t)
  def printable?(<<?\f, t :: binary>>), do: printable?(t)
  def printable?(<<?\e, t :: binary>>), do: printable?(t)
  def printable?(<<?\d, t :: binary>>), do: printable?(t)
  def printable?(<<?\a, t :: binary>>), do: printable?(t)

  def printable?(<<>>), do: true
  def printable?(b) when is_binary(b), do: false

  @doc """
  Divides a string into substrings at each Unicode whitespace
  occurrence with leading and trailing whitespace ignored.

  ## Examples

      iex> String.split("foo bar")
      ["foo", "bar"]

      iex> String.split("foo" <> <<194, 133>> <> "bar")
      ["foo", "bar"]

      iex> String.split(" foo bar ")
      ["foo", "bar"]

  """
  @spec split(t) :: [t]
  defdelegate split(binary), to: String.Unicode

  @doc ~S"""
  Divides a string into substrings based on a pattern.

  Returns a list of these substrings. The pattern can
  be a string, a list of strings or a regular expression.

  The string is split into as many parts as possible by
  default, but can be controlled via the `parts: num` option.
  If you pass `parts: :infinity`, it will return all possible parts.

  Empty strings are only removed from the result if the
  `trim` option is set to `true`.

  ## Examples

  Splitting with a string pattern:

      iex> String.split("a,b,c", ",")
      ["a", "b", "c"]

      iex> String.split("a,b,c", ",", parts: 2)
      ["a", "b,c"]

      iex> String.split(" a b c ", " ", trim: true)
      ["a", "b", "c"]

  A list of patterns:

      iex> String.split("1,2 3,4", [" ", ","])
      ["1", "2", "3", "4"]

  A regular expression:

      iex> String.split("a,b,c", ~r{,})
      ["a", "b", "c"]

      iex> String.split("a,b,c", ~r{,}, parts: 2)
      ["a", "b,c"]

      iex> String.split(" a b c ", ~r{\s}, trim: true)
      ["a", "b", "c"]

  Splitting on empty patterns returns codepoints:

      iex> String.split("abc", ~r{})
      ["a", "b", "c", ""]

      iex> String.split("abc", "")
      ["a", "b", "c", ""]

      iex> String.split("abc", "", trim: true)
      ["a", "b", "c"]

      iex> String.split("abc", "", parts: 2)
      ["a", "bc"]

  """
  @spec split(t, t | [t] | Regex.t) :: [t]
  @spec split(t, t | [t] | Regex.t, Keyword.t) :: [t]
  def split(binary, pattern, options \\ [])

  def split("", _pattern, _options), do: [""]

  def split(binary, "", options) do
    index =
      case Keyword.get(options, :parts, :infinity) do
        num when is_number(num) and num > 0 -> num
        _ -> 0
      end
    split_codepoints(binary, index - 1, Keyword.get(options, :trim, false))
  end

  def split(binary, pattern, options) do
    if Regex.regex?(pattern) do
      Regex.split(pattern, binary, options)
    else
      splits =
        case Keyword.get(options, :parts, :infinity) do
          num when is_number(num) and num > 0 ->
            split_parts(binary, pattern, num - 1)
          _ ->
            :binary.split(binary, pattern, [:global])
        end

      if Keyword.get(options, :trim, false) do
        for split <- splits, split != "", do: split
      else
        splits
      end
    end
  end

  defp split_codepoints(binary, 0, _trim), do: [binary]
  defp split_codepoints(<<h :: utf8, t :: binary>>, count, trim),
    do: [<<h :: utf8>>|split_codepoints(t, count - 1, trim)]
  defp split_codepoints(<<h, t :: binary>>, count, trim),
    do: [<<h>>|split_codepoints(t, count - 1, trim)]
  defp split_codepoints(<<>>, _, true), do: []
  defp split_codepoints(<<>>, _, false), do: [""]

  defp split_parts("", _pattern, _num),         do: [""]
  defp split_parts(binary, pattern, num),       do: split_parts(binary, pattern, num, [])
  defp split_parts("", _pattern, _num, parts),  do: Enum.reverse([""|parts])
  defp split_parts(binary, _pattern, 0, parts), do: Enum.reverse([binary|parts])
  defp split_parts(binary, pattern, num, parts) do
    case :binary.split(binary, pattern) do
      [head]       -> Enum.reverse([head|parts])
      [head, rest] -> split_parts(rest, pattern, num - 1, [head|parts])
    end
  end

  @doc """
  Splits a string into two at the specified offset. When the offset given is
  negative, location is counted from the end of the string.

  The offset is capped to the length of the string.

  Returns a tuple with two elements.

  ## Examples

      iex> String.split_at "sweetelixir", 5
      {"sweet", "elixir"}

      iex> String.split_at "sweetelixir", -6
      {"sweet", "elixir"}

      iex> String.split_at "abc", 0
      {"", "abc"}

      iex> String.split_at "abc", 1000
      {"abc", ""}

      iex> String.split_at "abc", -1000
      {"", "abc"}

  """
  @spec split_at(t, integer) :: {t, t}
  def split_at(string, offset)

  def split_at(binary, index) when index == 0, do:
    {"", binary}

  def split_at(binary, index) when index > 0, do:
    do_split_at(next_grapheme(binary), 0, index, "")

  def split_at(binary, index) when index < 0, do:
    do_split_at(next_grapheme(binary), 0, max(0, byte_size(binary)+index), "")

  defp do_split_at(nil, _, _, acc), do:
    {acc, ""}

  defp do_split_at({grapheme, rest}, current_pos, target_pos, acc) when current_pos < target_pos, do:
    do_split_at(next_grapheme(rest), current_pos+1, target_pos, acc <> grapheme)

  defp do_split_at({grapheme, rest}, pos, pos, acc), do:
    {acc, grapheme <> rest}

  @doc """
  Convert all characters on the given string to uppercase.

  ## Examples

      iex> String.upcase("abcd")
      "ABCD"

      iex> String.upcase("ab 123 xpto")
      "AB 123 XPTO"

      iex> String.upcase("josé")
      "JOSÉ"

  """
  @spec upcase(t) :: t
  defdelegate upcase(binary), to: String.Unicode

  @doc """
  Convert all characters on the given string to lowercase.

  ## Examples

      iex> String.downcase("ABCD")
      "abcd"

      iex> String.downcase("AB 123 XPTO")
      "ab 123 xpto"

      iex> String.downcase("JOSÉ")
      "josé"

  """
  @spec downcase(t) :: t
  defdelegate downcase(binary), to: String.Unicode

  @doc """
  Converts the first character in the given string to
  uppercase and the remaining to lowercase.

  This relies on the titlecase information provided
  by the Unicode Standard. Note this function makes
  no attempt to capitalize all words in the string
  (usually known as titlecase).

  ## Examples

      iex> String.capitalize("abcd")
      "Abcd"

      iex> String.capitalize("ﬁn")
      "Fin"

      iex> String.capitalize("josé")
      "José"

  """
  @spec capitalize(t) :: t
  def capitalize(string) when is_binary(string) do
    {char, rest} = String.Unicode.titlecase_once(string)
    char <> downcase(rest)
  end

  @doc """
  Returns a string where trailing Unicode whitespace
  has been removed.

  ## Examples

      iex> String.rstrip("   abc  ")
      "   abc"

  """
  @spec rstrip(t) :: t
  defdelegate rstrip(binary), to: String.Unicode

  @doc """
  Returns a string where trailing `char` have been removed.

  ## Examples

      iex> String.rstrip("   abc _", ?_)
      "   abc "

  """
  @spec rstrip(t, char) :: t

  def rstrip("", _char), do: ""

  # Do a quick check before we traverse the whole
  # binary. :binary.last is a fast operation (it
  # does not traverse the whole binary).
  def rstrip(string, char) when char in 0..127 do
    if :binary.last(string) == char do
      do_rstrip(string, "", char)
    else
      string
    end
  end

  def rstrip(string, char) when is_integer(char) do
    do_rstrip(string, "", char)
  end

  defp do_rstrip(<<char :: utf8, string :: binary>>, buffer, char) do
    <<do_rstrip(string, <<char :: utf8, buffer :: binary>>, char) :: binary>>
  end

  defp do_rstrip(<<char :: utf8, string :: binary>>, buffer, another_char) do
    <<buffer :: binary, char :: utf8, do_rstrip(string, "", another_char) :: binary>>
  end

  defp do_rstrip(<<>>, _, _) do
    <<>>
  end

  @doc """
  Returns a string where leading Unicode whitespace
  has been removed.

  ## Examples

      iex> String.lstrip("   abc  ")
      "abc  "

  """
  defdelegate lstrip(binary), to: String.Unicode

  @doc """
  Returns a string where leading `char` have been removed.

  ## Examples

      iex> String.lstrip("_  abc  _", ?_)
      "  abc  _"

  """

  @spec lstrip(t, char) :: t

  def lstrip(<<char :: utf8, rest :: binary>>, char) when is_integer(char) do
    <<lstrip(rest, char) :: binary>>
  end

  def lstrip(other, char) when is_integer(char) do
    other
  end

  @doc """
  Returns a string where leading/trailing Unicode whitespace
  has been removed.

  ## Examples

      iex> String.strip("   abc  ")
      "abc"

  """
  @spec strip(t) :: t

  def strip(string) do
    rstrip(lstrip(string))
  end

  @doc """
  Returns a string where leading/trailing `char` have been
  removed.

  ## Examples

      iex> String.strip("a  abc  a", ?a)
      "  abc  "

  """
  @spec strip(t, char) :: t

  def strip(string, char) do
    rstrip(lstrip(string, char), char)
  end

  @doc ~S"""
  Returns a new string of length `len` with `subject` right justified and
  padded with `padding`. If `padding` is not present, it defaults to
  whitespace. When `len` is less than the length of `subject`, `subject` is
  returned.

  ## Examples

      iex> String.rjust("abc", 5)
      "  abc"

      iex> String.rjust("abc", 5, ?-)
      "--abc"

  """
  @spec rjust(t, pos_integer) :: t
  @spec rjust(t, pos_integer, char) :: t

  def rjust(subject, len) do
    rjust(subject, len, ?\s)
  end

  def rjust(subject, len, padding) when is_integer(padding) do
    do_justify(subject, len, padding, :right)
  end

  @doc ~S"""
  Returns a new string of length `len` with `subject` left justified and padded
  with `padding`. If `padding` is not present, it defaults to whitespace. When
  `len` is less than the length of `subject`, `subject` is returned.

  ## Examples

      iex> String.ljust("abc", 5)
      "abc  "

      iex> String.ljust("abc", 5, ?-)
      "abc--"

  """
  @spec ljust(t, pos_integer) :: t
  @spec ljust(t, pos_integer, char) :: t

  def ljust(subject, len) do
    ljust(subject, len, ?\s)
  end

  def ljust(subject, len, padding) when is_integer(padding) do
    do_justify(subject, len, padding, :left)
  end

  defp do_justify(subject, 0, _padding, _type) do
    subject
  end

  defp do_justify(subject, len, padding, type) when is_integer(padding) do
    subject_len = length(subject)

    cond do
      subject_len >= len ->
        subject
      subject_len < len ->
        fill = duplicate(<<padding :: utf8>>, len - subject_len)

        case type do
          :left  -> subject <> fill
          :right -> fill <> subject
        end
    end
  end

  @doc ~S"""
  Returns a new binary based on `subject` by replacing the parts
  matching `pattern` by `replacement`. By default, it replaces
  all entries, except if the `global` option is set to `false`.

  A `pattern` may be a string or a regex.

  ## Examples

      iex> String.replace("a,b,c", ",", "-")
      "a-b-c"

      iex> String.replace("a,b,c", ",", "-", global: false)
      "a-b,c"

  The pattern can also be a regex. In those cases, one can give `\N`
  in the `replacement` string to access a specific capture in the regex:

      iex> String.replace("a,b,c", ~r/,(.)/, ",\\1\\1")
      "a,bb,cc"

  Notice we had to escape the escape character `\`. By giving `&`,
  one can inject the whole matched pattern in the replacement string.

  When strings are used as a pattern, a developer can also use the
  replaced part inside the `replacement` via the `:insert_replaced` option:

      iex> String.replace("a,b,c", "b", "[]", insert_replaced: 1)
      "a,[b],c"

      iex> String.replace("a,b,c", ",", "[]", insert_replaced: 2)
      "a[],b[],c"

      iex> String.replace("a,b,c", ",", "[]", insert_replaced: [1, 1])
      "a[,,]b[,,]c"

  """
  @spec replace(t, t, t) :: t
  @spec replace(t, t, t, Keyword.t) :: t

  def replace(subject, pattern, replacement, options \\ []) when is_binary(replacement) do
    if Regex.regex?(pattern) do
      Regex.replace(pattern, subject, replacement, global: options[:global])
    else
      opts = translate_replace_options(options)
      :binary.replace(subject, pattern, replacement, opts)
    end
  end

  defp translate_replace_options(options) do
    opts = if Keyword.get(options, :global) != false, do: [:global], else: []

    if insert = Keyword.get(options, :insert_replaced) do
      opts = [{:insert_replaced, insert}|opts]
    end

    opts
  end

  @doc """
  Reverses the given string. Works on graphemes.

  ## Examples

      iex> String.reverse("abcd")
      "dcba"

      iex> String.reverse("hello world")
      "dlrow olleh"

      iex> String.reverse("hello ∂og")
      "go∂ olleh"

  """
  @spec reverse(t) :: t
  def reverse(string) do
    do_reverse(next_grapheme(string), [])
  end

  defp do_reverse({grapheme, rest}, acc) do
    do_reverse(next_grapheme(rest), [grapheme|acc])
  end

  defp do_reverse(nil, acc), do: IO.iodata_to_binary(acc)

  @doc """
  Returns a binary `subject` duplicated `n` times.

  ## Examples

      iex> String.duplicate("abc", 0)
      ""

      iex> String.duplicate("abc", 1)
      "abc"

      iex> String.duplicate("abc", 2)
      "abcabc"

  """
  @spec duplicate(t, pos_integer) :: t
  def duplicate(subject, n) when is_integer(n) and n >= 0 do
    :binary.copy(subject, n)
  end

  @doc """
  Returns all codepoints in the string.

  ## Examples

      iex> String.codepoints("josé")
      ["j", "o", "s", "é"]

      iex> String.codepoints("оптими зации")
      ["о","п","т","и","м","и"," ","з","а","ц","и","и"]

      iex> String.codepoints("ἅἪῼ")
      ["ἅ","Ἢ","ῼ"]

  """
  @spec codepoints(t) :: [codepoint]
  defdelegate codepoints(string), to: String.Unicode

  @doc """
  Returns the next codepoint in a String.

  The result is a tuple with the codepoint and the
  remaining of the string or `nil` in case
  the string reached its end.

  As with other functions in the String module, this
  function does not check for the validity of the codepoint.
  That said, if an invalid codepoint is found, it will
  be returned by this function.

  ## Examples

      iex> String.next_codepoint("josé")
      {"j", "osé"}

  """
  @compile {:inline, next_codepoint: 1}
  @spec next_codepoint(t) :: {codepoint, t} | nil
  defdelegate next_codepoint(string), to: String.Unicode

  @doc ~S"""
  Checks whether `str` contains only valid characters.

  ## Examples

      iex> String.valid?("a")
      true

      iex> String.valid?("ø")
      true

      iex> String.valid?(<<0xffff :: 16>>)
      false

      iex> String.valid?("asd" <> <<0xffff :: 16>>)
      false

  """
  @spec valid?(t) :: boolean

  noncharacters = Enum.to_list(?\x{FDD0}..?\x{FDEF}) ++
    [ ?\x{0FFFE}, ?\x{0FFFF}, ?\x{1FFFE}, ?\x{1FFFF}, ?\x{2FFFE}, ?\x{2FFFF},
      ?\x{3FFFE}, ?\x{3FFFF}, ?\x{4FFFE}, ?\x{4FFFF}, ?\x{5FFFE}, ?\x{5FFFF},
      ?\x{6FFFE}, ?\x{6FFFF}, ?\x{7FFFE}, ?\x{7FFFF}, ?\x{8FFFE}, ?\x{8FFFF},
      ?\x{9FFFE}, ?\x{9FFFF}, ?\x{10FFFE}, ?\x{10FFFF} ]

  for noncharacter <- noncharacters do
    def valid?(<< unquote(noncharacter) :: utf8, _ :: binary >>), do: false
  end

  def valid?(<<_ :: utf8, t :: binary>>), do: valid?(t)
  def valid?(<<>>), do: true
  def valid?(_), do: false

  @doc ~S"""
  Checks whether `str` is a valid character.

  All characters are codepoints, but some codepoints
  are not valid characters. They may be reserved, private,
  or other.

  More info at: http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Noncharacters

  ## Examples

      iex> String.valid_character?("a")
      true

      iex> String.valid_character?("ø")
      true

      iex> String.valid_character?("\x{ffff}")
      false

  """
  @spec valid_character?(t) :: boolean

  def valid_character?(<<_ :: utf8>> = codepoint), do: valid?(codepoint)
  def valid_character?(_), do: false

  @doc ~S"""
  Splits the string into chunks of characters that share a common trait.

  The trait can be one of two options:

    * `:valid` – the string is split into chunks of valid and invalid character
      sequences

    * `:printable` – the string is split into chunks of printable and
      non-printable character sequences

  Returns a list of binaries each of which contains only one kind of
  characters.

  If the given string is empty, an empty list is returned.

  ## Examples

      iex> String.chunk(<<?a, ?b, ?c, 0>>, :valid)
      ["abc\000"]

      iex> String.chunk(<<?a, ?b, ?c, 0, 0x0ffff::utf8>>, :valid)
      ["abc\000", <<0x0ffff::utf8>>]

      iex> String.chunk(<<?a, ?b, ?c, 0, 0x0ffff::utf8>>, :printable)
      ["abc", <<0, 0x0ffff::utf8>>]

  """
  @spec chunk(t, :valid | :printable) :: [t]

  def chunk(string, trait)

  def chunk("", _), do: []

  def chunk(str, trait) when trait in [:valid, :printable] do
    {cp, _} = next_codepoint(str)
    pred_fn = make_chunk_pred(trait)
    do_chunk(str, pred_fn.(cp), pred_fn)
  end

  defp do_chunk(str, flag, pred_fn), do: do_chunk(str, [], <<>>, flag, pred_fn)

  defp do_chunk(<<>>, acc, <<>>, _, _), do: Enum.reverse(acc)

  defp do_chunk(<<>>, acc, chunk, _, _), do: Enum.reverse(acc, [chunk])

  defp do_chunk(str, acc, chunk, flag, pred_fn) do
    {cp, rest} = next_codepoint(str)
    if pred_fn.(cp) != flag do
      do_chunk(rest, [chunk|acc], cp, not flag, pred_fn)
    else
      do_chunk(rest, acc, chunk <> cp, flag, pred_fn)
    end
  end

  defp make_chunk_pred(:valid), do: &valid?/1
  defp make_chunk_pred(:printable), do: &printable?/1

  @doc """
  Returns unicode graphemes in the string as per Extended Grapheme
  Cluster algorithm outlined in the [Unicode Standard Annex #29,
  Unicode Text Segmentation](http://www.unicode.org/reports/tr29/).

  ## Examples

      iex> String.graphemes("Ā̀stute")
      ["Ā̀","s","t","u","t","e"]

  """
  @spec graphemes(t) :: [grapheme]
  defdelegate graphemes(string), to: String.Graphemes

  @doc """
  Returns the next grapheme in a String.

  The result is a tuple with the grapheme and the
  remaining of the string or `nil` in case
  the String reached its end.

  ## Examples

      iex> String.next_grapheme("josé")
      {"j", "osé"}

  """
  @compile {:inline, next_grapheme: 1}
  @spec next_grapheme(t) :: {grapheme, t} | nil
  defdelegate next_grapheme(string), to: String.Graphemes

  @doc """
  Returns the first grapheme from an utf8 string,
  nil if the string is empty.

  ## Examples

      iex> String.first("elixir")
      "e"

      iex> String.first("եոգլի")
      "ե"

  """
  @spec first(t) :: grapheme | nil
  def first(string) do
    case next_grapheme(string) do
      {char, _} -> char
      nil -> nil
    end
  end

  @doc """
  Returns the last grapheme from an utf8 string,
  `nil` if the string is empty.

  ## Examples

      iex> String.last("elixir")
      "r"

      iex> String.last("եոգլի")
      "ի"

  """
  @spec last(t) :: grapheme | nil
  def last(string) do
    do_last(next_grapheme(string), nil)
  end

  defp do_last({char, rest}, _) do
    do_last(next_grapheme(rest), char)
  end

  defp do_last(nil, last_char), do: last_char

  @doc """
  Returns the number of unicode graphemes in an utf8 string.

  ## Examples

      iex> String.length("elixir")
      6

      iex> String.length("եոգլի")
      5

  """
  @spec length(t) :: non_neg_integer
  def length(string) do
    do_length(next_grapheme(string))
  end

  defp do_length({_, rest}) do
    1 + do_length(next_grapheme(rest))
  end

  defp do_length(nil), do: 0

  @doc """
  Returns the grapheme in the `position` of the given utf8 `string`.
  If `position` is greater than `string` length, then it returns `nil`.

  ## Examples

      iex> String.at("elixir", 0)
      "e"

      iex> String.at("elixir", 1)
      "l"

      iex> String.at("elixir", 10)
      nil

      iex> String.at("elixir", -1)
      "r"

      iex> String.at("elixir", -10)
      nil

  """
  @spec at(t, integer) :: grapheme | nil

  def at(string, position) when position >= 0 do
    do_at(next_grapheme(string), position, 0)
  end

  def at(string, position) when position < 0 do
    real_pos = length(string) - abs(position)
    case real_pos >= 0 do
      true  -> do_at(next_grapheme(string), real_pos, 0)
      false -> nil
    end
  end

  defp do_at({_ , rest}, desired_pos, current_pos) when desired_pos > current_pos do
    do_at(next_grapheme(rest), desired_pos, current_pos + 1)
  end

  defp do_at({char, _}, desired_pos, current_pos) when desired_pos == current_pos do
    char
  end

  defp do_at(nil, _, _), do: nil

  @doc """
  Returns a substring starting at the offset given by the first, and
  a length given by the second.

  If the offset is greater than string length, then it returns `""`.

  Remember this function works with unicode codepoints and consider
  the slices to represent codepoints offsets. If you want to split
  on raw bytes, check `Kernel.binary_part/3` instead.

  ## Examples

      iex> String.slice("elixir", 1, 3)
      "lix"

      iex> String.slice("elixir", 1, 10)
      "lixir"

      iex> String.slice("elixir", 10, 3)
      ""

      iex> String.slice("elixir", -4, 4)
      "ixir"

      iex> String.slice("elixir", -10, 3)
      ""

      iex> String.slice("a", 0, 1500)
      "a"

      iex> String.slice("a", 1, 1500)
      ""

      iex> String.slice("a", 2, 1500)
      ""

  """
  @spec slice(t, integer, integer) :: grapheme

  def slice(_, _, 0) do
    ""
  end

  def slice(string, start, len) when start >= 0 and len >= 0 do
    do_slice(next_grapheme(string), string, start, start + len - 1, 0, 0, 0)
  end

  def slice(string, start, len) when start < 0 and len >= 0 do
    real_start_pos = length(string) - abs(start)
    case real_start_pos >= 0 do
      true -> do_slice(next_grapheme(string), string, real_start_pos, real_start_pos + len - 1, 0, 0, 0)
      false -> ""
    end
  end

  @doc """
  Returns a substring from the offset given by the start of the
  range to the offset given by the end of the range.

  If the start of the range is not a valid offset for the given
  string or if the range is in reverse order, returns `""`.

  If the start or end of the range are negative, the whole string
  is traversed first in order to convert the negative indexes into
  positive ones.

  Remember this function works with unicode codepoints and consider
  the slices to represent codepoints offsets. If you want to split
  on raw bytes, check `Kernel.binary_part/3` instead.

  ## Examples

      iex> String.slice("elixir", 1..3)
      "lix"

      iex> String.slice("elixir", 1..10)
      "lixir"

      iex> String.slice("elixir", 10..3)
      ""

      iex> String.slice("elixir", -4..-1)
      "ixir"

      iex> String.slice("elixir", 2..-1)
      "ixir"

      iex> String.slice("elixir", -4..6)
      "ixir"

      iex> String.slice("elixir", -1..-4)
      ""

      iex> String.slice("elixir", -10..-7)
      ""

      iex> String.slice("a", 0..1500)
      "a"

      iex> String.slice("a", 1..1500)
      ""

  """
  @spec slice(t, Range.t) :: t

  def slice(string, range)

  def slice("", _.._), do: ""

  def slice(string, first..-1) when first >= 0 do
    nbytes = count_bytes_until(string, first)
    if nbytes >= 0 do
      binary_part(string, nbytes, byte_size(string) - nbytes)
    else
      ""
    end
  end

  def slice(string, first..last) when first >= 0 and last >= 0 do
    do_slice(next_grapheme(string), string, first, last, 0, 0, 0)
  end

  def slice(string, first..last) when first >= 0 do
    count = abs(last)
    do_slice_neg_lb(next_grapheme(string), string, first, 0, count, init_bytes)
  end

  def slice(string, first..last) when last >= 0 do
    count = abs(first)
    do_slice_neg(next_grapheme(string), string, first, last, count, 0, init_bytes)
  end

  def slice(string, first..last) when first < 0 and last < 0 do
    if first > last do
      ""
    else
      count = abs(first)
      do_slice_neg(next_grapheme(string), string, first, last, count, 0, init_bytes)
    end
  end

  defp count_bytes_until(string, index) do
    count_bytes_until(next_grapheme(string), index, 0, 0)
  end

  defp count_bytes_until({char, rest}, index, pos, nbytes) when pos < index do
    count_bytes_until(next_grapheme(rest), index, pos+1, nbytes+byte_size(char))
  end

  defp count_bytes_until(nil, _, _, _) do
    -1
  end

  defp count_bytes_until({_, _}, index, index, nbytes) do
    nbytes
  end

  # "lb" stands for known lower bound
  defp do_slice_neg_lb(nil, str, first, pos, count, bytes) do
    cond do
      pos < first+1 ->
        # starting position is out of bounds
        ""
      pos-count < first ->
        # the negative right bound is out of bounds
        ""
      true ->
        {bytes, _, start_bytes} = bytes
        len_bytes = sum_bytes(bytes, count-1)
        binary_part(str, start_bytes, byte_size(str)-start_bytes-len_bytes)
    end
  end

  defp do_slice_neg_lb({char, rest}, str, first, pos, count, bytes) do
    bytes = update_bytes(bytes, char, first, pos, count)
    do_slice_neg_lb(next_grapheme(rest), str, first, pos+1, count, bytes)
  end

  # both bounds are negative
  defp do_slice_neg(nil, str, first, last, count, pos, bytes) do
    # get positive bounds
    if first < 0, do: first = pos + first
    if last < 0, do: last = pos + last
    cond do
      first < 0 or first > last ->
        # negative left bound is out of bounds
        ""
      true ->
        {bytes, _, _} = bytes
        str_bytes = byte_size(str)
        start_bytes = str_bytes - sum_bytes(bytes, count)
        last = min(last, pos-1)
        len_bytes =
          bytes |> drop_bytes(pos-last-1) |> sum_bytes(last-first+1)
        binary_part(str, start_bytes, min(len_bytes, str_bytes-start_bytes))
    end
  end

  defp do_slice_neg({char, rest}, str, first, last, count, pos, bytes) do
    bytes = update_bytes(bytes, char, 0, 0, count)
    do_slice_neg(next_grapheme(rest), str, first, last, count, pos+1, bytes)
  end

  defp init_bytes(), do: {[], 0, 0}

  defp sum_bytes(bytes, count) do
    bytes |> Enum.take(count) |> Enum.sum
  end

  defp drop_bytes(bytes, count) do
    Enum.drop(bytes, count)
  end

  defp update_bytes({bytes, n, start_bytes}, char, first, pos, cnt) do
    char_bytes = byte_size(char)
    if pos < first do
      start_bytes = start_bytes + char_bytes
    end
    if n < cnt do
      n = n + 1
    end
    {[char_bytes|bytes], n, start_bytes}
  end

  defp do_slice(_, _, start_pos, last_pos, _, _, _) when start_pos > last_pos do
    ""
  end

  defp do_slice({char, rest}, str, start_pos, last_pos, current_pos, start_bytes, len_bytes)
    when current_pos < start_pos
  do
    do_slice(next_grapheme(rest), str, start_pos, last_pos, current_pos + 1, start_bytes+byte_size(char), len_bytes)
  end

  defp do_slice({char, rest}, str, start_pos, last_pos, current_pos, start_bytes, len_bytes)
    when current_pos >= start_pos and current_pos < last_pos
  do
    do_slice(next_grapheme(rest), str, start_pos, last_pos, current_pos + 1, start_bytes, len_bytes+byte_size(char))
  end

  defp do_slice({char, _}, str, start_pos, last_pos, current_pos, start_bytes, len_bytes)
    when current_pos >= start_pos and current_pos == last_pos
  do
    binary_part(str, start_bytes, len_bytes+byte_size(char))
  end

  defp do_slice(nil, str, _, _, _, start_bytes, len_bytes) do
    binary_part(str, start_bytes, len_bytes)
  end

  @doc """
  Returns `true` if `string` starts with any of the prefixes given, otherwise
  `false`. `prefixes` can be either a single prefix or a list of prefixes.

  ## Examples

      iex> String.starts_with? "elixir", "eli"
      true

      iex> String.starts_with? "elixir", ["erlang", "elixir"]
      true

      iex> String.starts_with? "elixir", ["erlang", "ruby"]
      false

  """
  @spec starts_with?(t, t | [t]) :: boolean

  def starts_with?(string, prefixes) when is_list(prefixes) do
    Enum.any?(prefixes, &do_starts_with(string, &1))
  end

  def starts_with?(string, prefix) do
    do_starts_with(string, prefix)
  end

  defp do_starts_with(string, "") when is_binary(string) do
    true
  end

  defp do_starts_with(string, prefix) when is_binary(prefix) do
    Kernel.match?({0, _}, :binary.match(string, prefix))
  end

  @doc """
  Returns `true` if `string` ends with any of the suffixes given, otherwise
  `false`. `suffixes` can be either a single suffix or a list of suffixes.

  ## Examples

      iex> String.ends_with? "language", "age"
      true

      iex> String.ends_with? "language", ["youth", "age"]
      true

      iex> String.ends_with? "language", ["youth", "elixir"]
      false

  """
  @spec ends_with?(t, t | [t]) :: boolean

  def ends_with?(string, suffixes) when is_list(suffixes) do
    Enum.any?(suffixes, &do_ends_with(string, &1))
  end

  def ends_with?(string, suffix) do
    do_ends_with(string, suffix)
  end

  defp do_ends_with(string, "") when is_binary(string) do
    true
  end

  defp do_ends_with(string, suffix) when is_binary(suffix) do
    string_size = byte_size(string)
    suffix_size = byte_size(suffix)
    scope = {string_size - suffix_size, suffix_size}
    (suffix_size <= string_size) and (:nomatch != :binary.match(string, suffix, [scope: scope]))
  end

  @doc """
  Check if `string` matches the given regular expression.

  ## Examples

      iex> String.match?("foo", ~r/foo/)
      true

      iex> String.match?("bar", ~r/foo/)
      false

  """
  @spec match?(t, Regex.t) :: boolean
  def match?(string, regex) do
    Regex.match?(regex, string)
  end

  @doc """
  Check if `string` contains any of the given `contents`.

  `matches` can be either a single string or a list of strings.

  ## Examples

      iex> String.contains? "elixir of life", "of"
      true

      iex> String.contains? "elixir of life", ["life", "death"]
      true

      iex> String.contains? "elixir of life", ["death", "mercury"]
      false

  """
  @spec contains?(t, t | [t]) :: boolean

  def contains?(string, contents) when is_list(contents) do
    Enum.any?(contents, &do_contains(string, &1))
  end

  def contains?(string, content) do
    do_contains(string, content)
  end

  defp do_contains(string, "") when is_binary(string) do
    true
  end

  defp do_contains(string, match) when is_binary(match) do
    :nomatch != :binary.match(string, match)
  end

  @doc """
  Converts a string into a char list.

  ## Examples

      iex> String.to_char_list("æß")
      'æß'

  Notice that this function expect a list of integer representing
  UTF-8 codepoints. If you have a raw binary, you must instead use
  [the `:binary` module](http://erlang.org/doc/man/binary.html).
  """
  @spec to_char_list(t) :: char_list
  def to_char_list(string) when is_binary(string) do
    case :unicode.characters_to_list(string) do
      result when is_list(result) ->
        result

      {:error, encoded, rest} ->
        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :invalid

      {:incomplete, encoded, rest} ->
        raise UnicodeConversionError, encoded: encoded, rest: rest, kind: :incomplete
    end
  end

  @doc """
  Converts a string to an atom.

  Currently Elixir does not support conversions from strings
  which contains Unicode codepoints greater than 0xFF.

  Inlined by the compiler.

  ## Examples

      iex> String.to_atom("my_atom")
      :my_atom

  """
  @spec to_atom(String.t) :: atom
  def to_atom(string) do
    :erlang.binary_to_atom(string, :utf8)
  end

  @doc """
  Converts a string to an existing atom.

  Currently Elixir does not support conversions from strings
  which contains Unicode codepoints greater than 0xFF.

  Inlined by the compiler.

  ## Examples

      iex> :my_atom
      iex> String.to_existing_atom("my_atom")
      :my_atom

      iex> String.to_existing_atom("this_atom_will_never_exist")
      ** (ArgumentError) argument error

  """
  @spec to_existing_atom(String.t) :: atom
  def to_existing_atom(string) do
    :erlang.binary_to_existing_atom(string, :utf8)
  end

  @doc """
  Returns a integer whose text representation is `string`.

  Inlined by the compiler.

  ## Examples

      iex> String.to_integer("123")
      123

  """
  @spec to_integer(String.t) :: integer
  def to_integer(string) do
    :erlang.binary_to_integer(string)
  end

  @doc """
  Returns an integer whose text representation is `string` in base `base`.

  Inlined by the compiler.

  ## Examples

      iex> String.to_integer("3FF", 16)
      1023

  """
  @spec to_integer(String.t, pos_integer) :: integer
  def to_integer(string, base) do
    :erlang.binary_to_integer(string, base)
  end

  @doc """
  Returns a float whose text representation is `string`.

  Inlined by the compiler.

  ## Examples

      iex> String.to_float("2.2017764e+0")
      2.2017764

  """
  @spec to_float(String.t) :: float
  def to_float(string) do
    :erlang.binary_to_float(string)
  end
end


Document support for :do blocks in link/2

defmodule Phoenix.HTML.Link do
  @moduledoc """
  Conveniences for working with links and URLs in HTML.
  """

  import Phoenix.HTML.Tag

  @doc """
  Generates a link to the given URL.

  ## Examples

      link("hello", to: "/world")
      #=> hello

      link("<hello>", to: "/world")
      #=> <hello>

      link("<hello>", to: "/world", class: "btn")
      #=> <hello>

      # You can use a `do ... end` block too:
      link to: "/hello" do
        "world"
      end

  ## Options

    * `:to` - the page to link to. This option is required

    * `:method` - the method to use with the link. In case the
      method is not `:get`, the link is generated inside the form
      which sets the proper information. In order to submit the
      form, JavaScript must be enabled

    * `:form` - customize the underlying form when the method
      is not `:get`

  All other options are forwarded to the underlying `<a>` tag.
  """
  def link(text, opts)

  def link(opts, do: contents) when is_list(opts) do
    link(contents, opts)
  end

  def link(text, opts) do
    {to, opts} = Keyword.pop(opts, :to)
    {method, opts} = Keyword.pop(opts, :method, :get)

    unless to do
      raise ArgumentError, "option :to is required in link/2"
    end

    if method == :get do
      content_tag(:a, text, [href: to] ++ opts)
    else
      {form, opts} = form_options(opts, method, "link")
      form_tag(to, form) do
        content_tag(:a, text, [href: "#", onclick: "this.parentNode.submit(); return false;"] ++ opts)
      end
    end
  end

  @doc false
  # No docs since this function is only called when a `do` block is passed as
  # `do:` instead of `do...end` (and that case is documented in `link/2`). No
  # need to confuse users.
  def link(opts) do
    {contents, opts} = Keyword.pop(opts, :do)

    unless contents do
      raise ArgumentError, "link/2 requires some contents in the :do block"
    end

    link(contents, opts)
  end

  @doc """
  Generates a button that uses a regular HTML form to submit to the given URL.

  Useful to ensure that links that change data are not triggered by
  search engines and other spidering software.

  ## Examples

      button("hello", to: "/world")
      #=> <form action="/world" class="button" method="post">
            <input name="_csrf_token" value=""><input type="submit" value="hello">
          </form>

      button("hello", to: "/world", method: "get", class: "btn")
      #=> <form action="/world" class="btn" method="post">
            <input type="submit" value="hello">
          </form>

  ## Options

    * `:to` - the page to link to. This option is required

    * `:method` - the method to use with the button. Defaults to :post.

    * `:form` - the options for the form. Defaults to
      `[class: "button", enforce_utf8: false]`

  All other options are forwarded to the underlying button input.
  """
  def button(text, opts) do
    {to, opts} = Keyword.pop(opts, :to)
    {method, opts} = Keyword.pop(opts, :method, :post)

    {form, opts} = form_options(opts, method, "button")

    opts =
      opts
      |> Keyword.put_new(:type, "submit")
      |> Keyword.put_new(:value, text)

    unless to do
      raise ArgumentError, "option :to is required in button/2"
    end

    form_tag(to, form) do
      tag(:input, opts)
    end
  end

  defp form_options(opts, method, class) do
    {form, opts} = Keyword.pop(opts, :form, [])

    form =
      form
      |> Keyword.put_new(:class, class)
      |> Keyword.put_new(:method, method)
      |> Keyword.put_new(:enforce_utf8, false)

    {form, opts}
  end
end

defmodule Phoenix.HTML.Link do
  @moduledoc """
  Conveniences for working with links and URLs in HTML.
  """

  import Phoenix.HTML.Tag

  @doc """
  Generates a link to the given URL.

  ## Examples

      link("hello", to: "/world")
      #=> hello

      link("<hello>", to: "/world")
      #=> <hello>

      link("<hello>", to: "/world", class: "btn")
      #=> <hello>

  ## Options

    * `:to` - the page to link to. This option is required

    * `:method` - the method to use with the link. In case the
      method is not `:get`, the link is generated inside the form
      which sets the proper information. In order to submit the
      form, JavaScript must be enabled

    * `:form` - customize the underlying form when the method
      is not `:get`

  All other options are forwarded to the underlying `<a>` tag.
  """
  def link(text, opts)

  def link(opts, do: contents) when is_list(opts) do
    link(contents, opts)
  end

  def link(text, opts) do
    {to, opts} = Keyword.pop(opts, :to)
    {method, opts} = Keyword.pop(opts, :method, :get)

    unless to do
      raise ArgumentError, "option :to is required in link/2"
    end

    if method == :get do
      content_tag(:a, text, [href: to] ++ opts)
    else
      {form, opts} = form_options(opts, method, "link")
      form_tag(to, form) do
        content_tag(:a, text, [href: "#", onclick: "this.parentNode.submit(); return false;"] ++ opts)
      end
    end
  end

  @doc false
  # No docs since this function is only called when a `do` block is passed as
  # `do:` instead of `do...end` (and that case is documented in `link/2`). No
  # need to confuse users.
  def link(opts) do
    {contents, opts} = Keyword.pop(opts, :do)

    unless contents do
      raise ArgumentError, "link/2 requires some contents in the :do block"
    end

    link(contents, opts)
  end

  @doc """
  Generates a button that uses a regular HTML form to submit to the given URL.

  Useful to ensure that links that change data are not triggered by
  search engines and other spidering software.

  ## Examples

      button("hello", to: "/world")
      #=> <form action="/world" class="button" method="post">
            <input name="_csrf_token" value=""><input type="submit" value="hello">
          </form>

      button("hello", to: "/world", method: "get", class: "btn")
      #=> <form action="/world" class="btn" method="post">
            <input type="submit" value="hello">
          </form>

  ## Options

    * `:to` - the page to link to. This option is required

    * `:method` - the method to use with the button. Defaults to :post.

    * `:form` - the options for the form. Defaults to
      `[class: "button", enforce_utf8: false]`

  All other options are forwarded to the underlying button input.
  """
  def button(text, opts) do
    {to, opts} = Keyword.pop(opts, :to)
    {method, opts} = Keyword.pop(opts, :method, :post)

    {form, opts} = form_options(opts, method, "button")

    opts =
      opts
      |> Keyword.put_new(:type, "submit")
      |> Keyword.put_new(:value, text)

    unless to do
      raise ArgumentError, "option :to is required in button/2"
    end

    form_tag(to, form) do
      tag(:input, opts)
    end
  end

  defp form_options(opts, method, class) do
    {form, opts} = Keyword.pop(opts, :form, [])

    form =
      form
      |> Keyword.put_new(:class, class)
      |> Keyword.put_new(:method, method)
      |> Keyword.put_new(:enforce_utf8, false)

    {form, opts}
  end
end


Fix warning.

Fix warning.

defmodule SlackCoder.Slack do
  use Slack
  import StubAlias
  import SlackCoder.Slack.Helper
  alias SlackCoder.Slack.Routing
  stub_alias SlackCoder.Users.Supervisor, as: Users
  stub_alias SlackCoder.Users.User
  alias SlackCoder.Models.Message
  alias SlackCoder.Models.User, as: UserModel
  alias SlackCoder.Services.UserService
  alias SlackCoder.Repo
  require Logger
  @online_message """
  :slack: *Slack* :computer: *Coder* online!
  Reporting on any PRs since last online...
  """

  @doc """
  Sends the message to `user` to be processed and delivered.
  Two types accepted:
      send_to(:user, %SlackCoder.Github.Notification{})
      send_to(:user, "message")
  The first delivers the message to `user` process where based upon
  its logic and the `user`'s configuration it will either be delivered or
  discarded. The second is meant to be used only by the User processes, so
  that they may deliver messages to `:slack` through the RTM service.
  """
  def send_to(user, message)
  def send_to(user, message) when is_atom(user), do: user |> to_string() |> send_to(message)
  def send_to(user, notification = %SlackCoder.Github.Notification{}) do
    user_pid = user |> String.to_atom() |> Users.user()
    if user_pid do
      User.notification user_pid, notification
    else
      Logger.error "Attempt to deliver message to #{inspect user}, but pid cannot be found. Notification: #{inspect notification}"
    end
  end
  def send_to(user, message) when is_binary(message), do: send_to(user, %{text: message})
  def send_to(user, raw_message) when is_map(raw_message) do
    send :slack, {user, if Mix.env == :dev do
                          Map.put(raw_message, :text, (raw_message[:text] || "") <> "\n*DEV MESSAGE*")
                        else
                          raw_message
                        end}
  end

  @doc """
  Retrieves the current slack data. Useful for inspecting the running process.
  """
  def slack() do
    send :slack, {:slack, self()}
    receive do
      data -> data
    end
  end

  @doc false
  def handle_info({:slack, pid}, slack, state) when is_pid(pid) do
    send pid, slack
    {:ok, state}
  end

  def handle_info({user, message}, slack, %{caretaker_id: caretaker_id} = state) do
    user = if(Mix.env == :dev, do: Application.get_env(:slack_coder, :caretaker) |> to_string(), else: user)
    {:ok, "@" <> user
          |> Slack.Lookups.lookup_user_id(slack)
          |> send_message_to_slack_user(user, message, caretaker_id, slack)
          |> case do
              :ok -> state
              {:update, user} -> Map.put(state, :undeliverable, Enum.uniq([{user, message} | Map.get(state, :undeliverable, [])]))
            end
          }
  end
  def handle_info(message, _slack, state) do
    Logger.warn "Got unhandled (handle_info) message: #{inspect message}"
    {:ok, state}
  end

  defp send_message_to_slack_user(nil, user, _message, caretaker_id, slack) do
    send_message("I can't find a user named `@#{user}`, can you tell me what their slack name is?", im(slack, caretaker_id).id, slack)
    {:update, user}
  end
  defp send_message_to_slack_user(slack_user_id, user, message, _caretaker_id, slack) when is_map(message) do
    message = message |> Map.merge(%{channel: Slack.Lookups.lookup_direct_message_id(slack_user_id, slack), type: "message"})

    Task.Supervisor.start_child SlackCoder.TaskSupervisor, __MODULE__, :record_message, [user, message]

    deliver_message(user, message, slack)

    :ok
  end

  @new_message_timeout 1_000
  defp deliver_message(user, %{channel: nil} = message, slack) do
    "@" <> user
    |> Slack.Lookups.lookup_user_id(slack)
    |> case do
      nil ->
        Logger.error "Unable to send message to #{inspect user}!"
      user ->
        case Slack.Web.Im.open(user) do
          %{"ok" => true, "channel" => %{"id" => dm}} when is_binary(dm) ->
            Task.start fn ->
              Process.sleep(@new_message_timeout)
              send_to(user, message) # Need slack data to update
            end
          error ->
            Logger.warn("Unable to open direct message to #{inspect user}! API Response: #{inspect error}")
        end
    end
  end
  defp deliver_message(_user, %{attachments: attachments, channel: channel} = message, _slack) do
    Task.start fn ->
      payload = %{attachments: Poison.encode!(attachments),
                  username: "zombie-bot",
                  icon_url: "https://ca.slack-edge.com/T02UFCF23-U0B5HU9U0-e6e946e40c02-72"}
      Slack.Web.Chat.post_message channel, message[:text], payload
    end
  end
  defp deliver_message(_user, message, slack) when is_map(message) do
    message
    |> Poison.encode!()
    |> send_raw(slack)
  end

  @doc false
  def record_message(user, message) when is_map(message) do
    record_message(user, Poison.encode!(message))
  end
  def record_message(user, message) do
    import Ecto.Query

    github = UserModel.by_slack(user) |> select([u], u.github) |> Repo.one

    Logger.info "Sending message (#{user}): #{message}"

    %Message{}
    |> Message.changeset(%{slack: to_string(user), user: github, message: message |> String.trim})
    |> Repo.insert!
  end

  @doc false
  def handle_close(reason, slack, _state) do
    caretaker = user(slack, Application.get_env(:slack_coder, :caretaker))
    caretaker_im = Routing.route_message(slack, caretaker)
    if caretaker_im do
      send_message("Crashing: #{inspect reason}", caretaker_im.id, slack)
    end
    {:error, reason}
  end

  @doc false
  def handle_connect(slack, _state) do
    try do
      Process.register(self(), :slack)
      channel = Routing.channel(slack)
      if channel, do: send_message(@online_message, channel.id, slack)
    rescue
      e ->
        Logger.error "Unable to connect to slack!\n#{inspect e}"
    end
    caretaker = user(slack, Application.get_env(:slack_coder, :caretaker))
    {:ok, %{caretaker_id: caretaker.id, undeliverable: []}}
  end

  # TODO: Would like to extract this to a separate module and/or process
  @doc false
  # Caretaker says yes to confirm name
  def handle_event(%{type: "message", text: yes, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{:user, username, {github, message}} | users]} = state) when yes in ["yes", "y", "YES", "Y"] do
    resolve_user_update(github, username)
    send_message("Confirmed!", im(slack, user_id).id, slack)
    send_to(username, message)
    {:ok, Map.put(state, :undeliverable, users)}
  end
  # Caretaker says no to confirm name
  def handle_event(%{type: "message", text: no, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{:user, _username, {github, _message} = undeliverable} | users]} = state) when no in ["no", "n", "NO", "N"] do
    send_message("Whops! So then who is #{github}?", im(slack, user_id).id, slack)
    {:ok, Map.put(state, :undeliverable, [undeliverable | users])}
  end
  # Caretaker answers incorrectly
  def handle_event(%{type: "message", text: _wrong_username, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{:user, username, {github_user, _message}} | _]} = state) do
    send_message("I'm sorry, I'm not following... Just to confirm, the Github user `#{github_user}` is named `@#{username}` on slack? (yes/no)", im(slack, user_id).id, slack)
    {:ok, state}
  end
  # Caretaker answers slack name
  def handle_event(%{type: "message", text: username, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{github_user, _message} = undeliverable | users]} = state) do
    send_message("Great! Just to confirm, the Github user `#{github_user}` is named `@#{username}` on slack? (yes/no)", im(slack, user_id).id, slack)
    {:ok, Map.put(state, :undeliverable, [{:user, username, undeliverable} | users])}
  end
  # Any other incoming message
  def handle_event(%{type: "message", text: message, user: user_id, channel: channel} = payload, slack, state) do
    Logger.info [IO.ANSI.green, IO.ANSI.bright, "[Slack] ", IO.ANSI.cyan, IO.ANSI.normal, "Processing Event: #{inspect payload}"]
    user_help(user_id, channel, message, payload, slack)
    {:ok, state}
  end
  def handle_event(payload, _slack, state) do
    Logger.debug [IO.ANSI.green, IO.ANSI.bright, "[Slack] ", IO.ANSI.cyan, IO.ANSI.normal, "Ignoring Event: #{inspect payload}"]
    {:ok, state}
  end

  defp resolve_user_update(github, slack) do
    github
    |> UserModel.by_github()
    |> Repo.one()
    |> UserModel.changeset(%{slack: slack})
    |> UserService.save()
  end

  defp user_help(user_id, channel, message, payload, slack) do
    if should_respond_to_message?(user_id, channel, slack) && payload[:subtype] == nil do
      slack_name = slack[:users][user_id][:name]
      user_pid = Users.user(slack_name)
      if user_pid do
        User.help(user_pid, message)
      else
        send_to slack_name, """
        Sorry, but I can't chat until you've registered!

        Please register at http://slack-coder.nanoapp.io
        """
        Logger.warn "User #{inspect slack_name || user_id} sent us a message but it was ignored because the user_pid could not be found."
      end
    end
  end

  defp should_respond_to_message?(user_id, channel, slack) do
    # As long as its not a message from me and it was sent via a DM
    slack[:me][:id] != user_id && slack[:ims][channel]
  end

end

defmodule SlackCoder.Slack do
  use Slack
  import StubAlias
  import SlackCoder.Slack.Helper
  alias SlackCoder.Slack.Routing
  stub_alias SlackCoder.Users.Supervisor, as: Users
  stub_alias SlackCoder.Users.User
  alias SlackCoder.Models.Message
  alias SlackCoder.Models.User, as: UserModel
  alias SlackCoder.Services.UserService
  alias SlackCoder.Repo
  require Logger
  @online_message """
  :slack: *Slack* :computer: *Coder* online!
  Reporting on any PRs since last online...
  """

  @doc """
  Sends the message to `user` to be processed and delivered.
  Two types accepted:
      send_to(:user, %SlackCoder.Github.Notification{})
      send_to(:user, "message")
  The first delivers the message to `user` process where based upon
  its logic and the `user`'s configuration it will either be delivered or
  discarded. The second is meant to be used only by the User processes, so
  that they may deliver messages to `:slack` through the RTM service.
  """
  def send_to(user, message)
  def send_to(user, message) when is_atom(user), do: user |> to_string() |> send_to(message)
  def send_to(user, notification = %SlackCoder.Github.Notification{}) do
    user_pid = user |> String.to_atom() |> Users.user()
    if user_pid do
      User.notification user_pid, notification
    else
      Logger.error "Attempt to deliver message to #{inspect user}, but pid cannot be found. Notification: #{inspect notification}"
    end
  end
  def send_to(user, message) when is_binary(message), do: send_to(user, %{text: message})
  def send_to(user, raw_message) when is_map(raw_message) do
    send :slack, {user, if Mix.env == :dev do
                          Map.put(raw_message, :text, (raw_message[:text] || "") <> "\n*DEV MESSAGE*")
                        else
                          raw_message
                        end}
  end

  @doc """
  Retrieves the current slack data. Useful for inspecting the running process.
  """
  def slack() do
    send :slack, {:slack, self()}
    receive do
      data -> data
    end
  end

  @doc false
  def handle_info({:slack, pid}, slack, state) when is_pid(pid) do
    send pid, slack
    {:ok, state}
  end

  def handle_info({user, message}, slack, %{caretaker_id: caretaker_id} = state) do
    user = if(Mix.env == :dev, do: Application.get_env(:slack_coder, :caretaker) |> to_string(), else: user)
    {:ok, "@" <> user
          |> Slack.Lookups.lookup_user_id(slack)
          |> send_message_to_slack_user(user, message, caretaker_id, slack)
          |> case do
              :ok -> state
              {:update, user} -> Map.put(state, :undeliverable, Enum.uniq([{user, message} | Map.get(state, :undeliverable, [])]))
            end
          }
  end
  def handle_info(message, _slack, state) do
    Logger.warn "Got unhandled (handle_info) message: #{inspect message}"
    {:ok, state}
  end

  defp send_message_to_slack_user(nil, user, _message, caretaker_id, slack) do
    send_message("I can't find a user named `@#{user}`, can you tell me what their slack name is?", im(slack, caretaker_id).id, slack)
    {:update, user}
  end
  defp send_message_to_slack_user(slack_user_id, user, message, _caretaker_id, slack) when is_map(message) do
    message = message |> Map.merge(%{channel: Slack.Lookups.lookup_direct_message_id(slack_user_id, slack), type: "message"})

    Task.Supervisor.start_child SlackCoder.TaskSupervisor, __MODULE__, :record_message, [user, message]

    deliver_message(user, message, slack)

    :ok
  end

  @new_message_timeout 1_000
  defp deliver_message(user, %{channel: nil} = message, slack) do
    "@" <> user
    |> Slack.Lookups.lookup_user_id(slack)
    |> case do
      nil ->
        Logger.error "Unable to send message to #{inspect user}!"
      user ->
        case Slack.Web.Im.open(user) do
          %{"ok" => true, "channel" => %{"id" => dm}} when is_binary(dm) ->
            Task.start fn ->
              Process.sleep(@new_message_timeout)
              send_to(user, message) # Need slack data to update
            end
          error ->
            Logger.warn("Unable to open direct message to #{inspect user}! API Response: #{inspect error}")
        end
    end
  end
  defp deliver_message(_user, %{attachments: attachments, channel: channel} = message, _slack) do
    Task.start fn ->
      payload = %{attachments: Poison.encode!(attachments),
                  username: "zombie-bot",
                  icon_url: "https://ca.slack-edge.com/T02UFCF23-U0B5HU9U0-e6e946e40c02-72"}
      Slack.Web.Chat.post_message channel, message[:text], payload
    end
  end
  defp deliver_message(_user, message, slack) when is_map(message) do
    message
    |> Poison.encode!()
    |> send_raw(slack)
  end

  @doc false
  def record_message(user, message) when is_map(message) do
    record_message(user, Poison.encode!(message))
  end
  def record_message(user, message) do
    import Ecto.Query

    github = UserModel.by_slack(user) |> select([u], u.github) |> Repo.one

    Logger.info "Sending message (#{user}): #{message}"

    %Message{}
    |> Message.changeset(%{slack: to_string(user), user: github, message: message |> String.strip})
    |> Repo.insert!
  end

  @doc false
  def handle_close(reason, slack, _state) do
    caretaker = user(slack, Application.get_env(:slack_coder, :caretaker))
    caretaker_im = Routing.route_message(slack, caretaker)
    if caretaker_im do
      send_message("Crashing: #{inspect reason}", caretaker_im.id, slack)
    end
    {:error, reason}
  end

  @doc false
  def handle_connect(slack, _state) do
    try do
      Process.register(self(), :slack)
      channel = Routing.channel(slack)
      if channel, do: send_message(@online_message, channel.id, slack)
    rescue
      e ->
        Logger.error "Unable to connect to slack!\n#{inspect e}"
    end
    caretaker = user(slack, Application.get_env(:slack_coder, :caretaker))
    {:ok, %{caretaker_id: caretaker.id, undeliverable: []}}
  end

  # TODO: Would like to extract this to a separate module and/or process
  @doc false
  # Caretaker says yes to confirm name
  def handle_event(%{type: "message", text: yes, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{:user, username, {github, message}} | users]} = state) when yes in ["yes", "y", "YES", "Y"] do
    resolve_user_update(github, username)
    send_message("Confirmed!", im(slack, user_id).id, slack)
    send_to(username, message)
    {:ok, Map.put(state, :undeliverable, users)}
  end
  # Caretaker says no to confirm name
  def handle_event(%{type: "message", text: no, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{:user, _username, {github, _message} = undeliverable} | users]} = state) when no in ["no", "n", "NO", "N"] do
    send_message("Whops! So then who is #{github}?", im(slack, user_id).id, slack)
    {:ok, Map.put(state, :undeliverable, [undeliverable | users])}
  end
  # Caretaker answers incorrectly
  def handle_event(%{type: "message", text: _wrong_username, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{:user, username, {github_user, _message}} | _]} = state) do
    send_message("I'm sorry, I'm not following... Just to confirm, the Github user `#{github_user}` is named `@#{username}` on slack? (yes/no)", im(slack, user_id).id, slack)
    {:ok, state}
  end
  # Caretaker answers slack name
  def handle_event(%{type: "message", text: username, user: user_id}, slack, %{caretaker_id: user_id, undeliverable: [{github_user, _message} = undeliverable | users]} = state) do
    send_message("Great! Just to confirm, the Github user `#{github_user}` is named `@#{username}` on slack? (yes/no)", im(slack, user_id).id, slack)
    {:ok, Map.put(state, :undeliverable, [{:user, username, undeliverable} | users])}
  end
  # Any other incoming message
  def handle_event(%{type: "message", text: message, user: user_id, channel: channel} = payload, slack, state) do
    Logger.info [IO.ANSI.green, IO.ANSI.bright, "[Slack] ", IO.ANSI.cyan, IO.ANSI.normal, "Processing Event: #{inspect payload}"]
    user_help(user_id, channel, message, payload, slack)
    {:ok, state}
  end
  def handle_event(payload, _slack, state) do
    Logger.debug [IO.ANSI.green, IO.ANSI.bright, "[Slack] ", IO.ANSI.cyan, IO.ANSI.normal, "Ignoring Event: #{inspect payload}"]
    {:ok, state}
  end

  defp resolve_user_update(github, slack) do
    github
    |> UserModel.by_github()
    |> Repo.one()
    |> UserModel.changeset(%{slack: slack})
    |> UserService.save()
  end

  defp user_help(user_id, channel, message, payload, slack) do
    if should_respond_to_message?(user_id, channel, slack) && payload[:subtype] == nil do
      slack_name = slack[:users][user_id][:name]
      user_pid = Users.user(slack_name)
      if user_pid do
        User.help(user_pid, message)
      else
        send_to slack_name, """
        Sorry, but I can't chat until you've registered!

        Please register at http://slack-coder.nanoapp.io
        """
        Logger.warn "User #{inspect slack_name || user_id} sent us a message but it was ignored because the user_pid could not be found."
      end
    end
  end

  defp should_respond_to_message?(user_id, channel, slack) do
    # As long as its not a message from me and it was sent via a DM
    slack[:me][:id] != user_id && slack[:ims][channel]
  end

end


Update mix.exs to include :mochiweb in application configuration