object WorkingWithList {
  /* From 99 problem */
  /* Find the last element of a list
  * scala> last(List(1, 1, 2, 3, 5, 8))
  * res0: Int = 8
  */
  def last[A](l: List[A]) : A = ???

  /* Find the penultimate element of a list
  * scala> penultimate(List(1, 1, 2, 3, 5, 8))
  * res0: Int = 5
  */
  def penultimate[A](l : List[A]) : A = ???

  /* Find the nth element of a list
  * The first element is element 0
  * scala> nth(2, List(1, 1, 2, 3, 5, 8))
  * res0: Int = 2*/
  def nth[A](x:Int, list : List[A]) : A = ???

  /* return the length of the list. Do not use lenght builtin function
  * scala> nth(2, List(1, 1, 2, 3, 5, 8))
  * res0: Int = 2
  * */
  def length[A](list : List[A]) : Int = ???

  /* Reverse a list
   * scala> reverse(List(1, 1, 2, 3, 5, 8))
   * res0: List[Int] = List(8, 5, 3, 2, 1, 1) */
  def reverse[A](list : List[A]) : List[A] = ???

  /* Find out whether list is a palindrome
  * scala> isPalindrome(List(1, 2, 3, 2, 1))
  * res0: Boolean = true*/
  def isPalindrome[A] (list : List[A]) : Boolean = ???

  /* Flatten a nested list
  * scala> flatten(List(List(1, 1), 2, List(3, List(5, 8))))
  * res0: List[Any] = List(1, 1, 2, 3, 5, 8)*/
  def flatten(list : List[Any]) : List[Any] = ???

  /* Apply a function on a list
   * scala> apply[Int,Int](x => x+10)(List(1,2,3,4,5))
   *  */
  def myMap[A,B](f : A=>B)(l : List[A]) : List[B] = ???

  /* Eliminate consecutive duplicates of list elements, the order should be conserved
  * scala> compress(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
  * res0: List[Symbol] = List('a, 'b, 'c, 'a, 'd, 'e)*/
  def compress[A] (list : List[A]) : List[A] = ???

  /* pack consecutive duplicates of list elements into sublists
  * scala> pack(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
  * res0: List[List[Symbol]] = List(List('a, 'a, 'a, 'a), List('b), List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))*/
  def pack[A](list : List[A]) : List[List[A]] = ???

  /* Run-length encoding of a list.
  * Use the result of packs
  * cala> encode(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
  * res0: List[(Int, Symbol)] = List((4,'a), (1,'b), (2,'c), (2,'a), (1,'d), (4,'e))
  */
  def encode[A](list : List[A]) : List[(Int, A)] = ???

  /* Modified run-length encoding.
  * Modify the result of encode  in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N, E) terms.scala> encodeModified(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))res0: List[Any] = List((4,'a), 'b, (2,'c), (2,'a), 'd, (4,'e))
  */
  def encodeModified[A] (list : List[A]): List[Any] = ???

  /* Decode a run-length encoded list.
    Given a run-length code list generated as specified in problem encode, construct its uncompressed version.
    scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)))
    res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
  */
  def decode[A] (list : List[(Int, A)]) : List[A] = ???


  /*  Run-length encoding of a list (direct solution).
    Implement the so-called run-length encoding data compression method directly. I.e. don't use other methods you've written (like pack); do all the work directly.

    scala> encodeDirect(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
  res0: List[(Int, Symbol)] = List((4,'a), (1,'b), (2,'c), (2,'a), (1,'d), (4,'e))
  */
  def encodeDirect[A](list : List[A]) : List[(Int,A)] =  ???

  /* Duplicate the elements of a list.

    scala> duplicate(List('a, 'b, 'c, 'c, 'd))
  res0: List[Symbol] = List('a, 'a, 'b, 'b, 'c, 'c, 'c, 'c, 'd, 'd)
  */
  def duplicate[A](list: List[A]): List[A] = ???

  /*Duplicate the elements of a list a given number of times.

    scala> duplicateN(3, List('a, 'b, 'c, 'c, 'd))
  res0: List[Symbol] = List('a, 'a, 'a, 'b, 'b, 'b, 'c, 'c, 'c, 'c, 'c, 'c, 'd, 'd, 'd)
  */
  def duplicateN[A](n: Int, list: List[A]): List[A] = ???

  /*
  Drop every Nth element from a list.

    scala> drop(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))
  res0: List[Symbol] = List('a, 'b, 'd, 'e, 'g, 'h, 'j, 'k)*/
  def drop[A](n: Int, list: List[A]): List[A] = ???

  /* Split a list into two parts.
    The length of the first part is given. Use a Tuple for your result.
    Hint : think terminal

    scala> split(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))
  res0: (List[Symbol], List[Symbol]) = (List('a, 'b, 'c),List('d, 'e, 'f, 'g, 'h, 'i, 'j, 'k))
  */
  def split[A](n: Int, ls: List[A]): (List[A], List[A]) = ???

  /* Extract a slice from a list.
    Given two indices, I and K, the slice is the list containing the elements from and including the Ith element up to but not including the Kth element of the original list. Start counting the elements with 0.

    scala> slice(3, 7, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))
  res0: List[Symbol] = List('d, 'e, 'f, 'g)
  */
  def slice[A](start: Int, end: Int, ls: List[A]): List[A] = ???

}
