From e0d646213d04815a0591ee87301fa50010387076 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 18:09:49 +0800 Subject: [PATCH 01/17] chore: completed Task 1 --- src/Chapter1.hs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 04fed0db4..a47cc1ee1 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -209,31 +209,31 @@ So, the output in this example means that 'False' has type 'Bool'. > Try to guess first and then compare your expectations with GHCi output >>> :t True - +True :: Bool >>> :t 'a' - +'a' :: Char >>> :t 42 - +42 :: Num a => a A pair of boolean and char: >>> :t (True, 'x') - +(True, 'x') :: (Bool, Char) Boolean negation: >>> :t not - +not :: Bool -> Bool Boolean 'and' operator: >>> :t (&&) - +(&&) :: Bool -> Bool -> Bool Addition of two numbers: >>> :t (+) - +(+) :: Num a => a -> a -> a Maximum of two values: >>> :t max - +max :: Ord a => a -> a -> a You might not understand each type at this moment, but don't worry! You've only started your Haskell journey. Types will become your friends soon. From 0d9b2fabc713a53b30437585e6aeb5de6457a543 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 20:38:38 +0800 Subject: [PATCH 02/17] chore: completed Task 2 --- src/Chapter1.hs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index a47cc1ee1..27c5aa36f 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -301,43 +301,43 @@ expressions in GHCi functions and operators first. Remember this from the previous task? ;) >>> 1 + 2 - +3 >>> 10 - 15 - +-5 >>> 10 - (-5) -- negative constants require () - +15 >>> (3 + 5) < 10 - +True >>> True && False - +False >>> 10 < 20 || 20 < 5 - +True >>> 2 ^ 10 -- power - +1024 >>> not False - +True >>> div 20 3 -- integral division - +6 >>> mod 20 3 -- integral division remainder - +2 >>> max 4 10 - +10 >>> min 5 (max 1 2) - +2 >>> max (min 1 10) (min 5 7) - +5 Because Haskell is a __statically-typed__ language, you see an error each time you try to mix values of different types in situations where you are not From cf1058d6e63645e878c17fcd246e9e7eac963e86 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 20:51:10 +0800 Subject: [PATCH 03/17] chore: completed Task 3 --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 27c5aa36f..787ab9f84 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -428,7 +428,7 @@ task is to specify the type of this function. >>> squareSum 3 4 49 -} - +squareSum :: Int -> Int -> Int squareSum x y = (x + y) * (x + y) From 51dfa5228e799886cb41c4b4c668274ec1cdbe03 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 21:44:58 +0800 Subject: [PATCH 04/17] chore: completed Task 4 --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 787ab9f84..13ef4095f 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -449,7 +449,7 @@ Implement the function that takes an integer value and returns the next 'Int'. function body with the proper implementation. -} next :: Int -> Int -next x = error "next: not implemented!" +next x = x + 1 {- | After you've implemented the function (or even during the implementation), you From 598f085559c41216b1baeb40bd4babfd03db0cab Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 21:54:01 +0800 Subject: [PATCH 05/17] chore: completed Task 5 --- src/Chapter1.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 13ef4095f..70ed6d428 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -489,8 +489,8 @@ Implement a function that returns the last digit of a given number. results. Or you can try to guess the function name, search for it and check whether it works for you! -} --- DON'T FORGET TO SPECIFY THE TYPE IN HERE -lastDigit n = error "lastDigit: Not implemented!" +lastDigit :: Int -> Int +lastDigit n = mod (abs n) 10 {- | From 144f6964c4045c04f491880e0b39c911490bf6fd Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 21:59:30 +0800 Subject: [PATCH 06/17] chore: completed Task 6 --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 70ed6d428..6c934d2f9 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -520,7 +520,7 @@ branches because it is an expression and it must always return some value. satisfying the check will be returned and, therefore, evaluated. -} closestToZero :: Int -> Int -> Int -closestToZero x y = error "closestToZero: not implemented!" +closestToZero x y = if abs x < abs y then x else y {- | From ea6da157684b4c89bd2e208e86da0dc9834e392a Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:04:01 +0800 Subject: [PATCH 07/17] chore: completed Task 7 --- src/Chapter1.hs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 6c934d2f9..5f595d85e 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -553,8 +553,11 @@ value after "=" where the condition is true. Casual reminder about adding top-level type signatures for all functions :) -} - -mid x y z = error "mid: not implemented!" +mid :: Int -> Int -> Int -> Int +mid x y z + | (x > y && x < z) || (x < y && x > z) = x + | (y > x && y < z) || (y < x && y > z) = y + | otherwise = z {- | =⚔️= Task 8 From 457aff61ad1f62c734d915f90ef81afebaafc77d Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:15:51 +0800 Subject: [PATCH 08/17] chore: completed Task 8 --- src/Chapter1.hs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 5f595d85e..75aa48306 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -571,7 +571,14 @@ True >>> isVowel 'x' False -} -isVowel c = error "isVowel: not implemented!" +isVowel :: Char -> Bool +isVowel c + | c == 'a' || c == 'A' = True + | c == 'e' || c == 'E' = True + | c == 'i' || c == 'I' = True + | c == 'o' || c == 'O' = True + | c == 'u' || c == 'U' = True + | otherwise = False {- | From bb37053333af4fea98f882e7d75c4846871eaf12 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:41:09 +0800 Subject: [PATCH 09/17] chore: completed Task 9 --- src/Chapter1.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 75aa48306..64ffc9a33 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -641,9 +641,11 @@ Implement a function that returns the sum of the last two digits of a number. Try to introduce variables in this task (either with let-in or where) to avoid specifying complex expressions. -} - -sumLast2 n = error "sumLast2: Not implemented!" - +sumLast2 :: Int -> Int +sumLast2 n = + let (remaining, last1) = divMod (abs n) 10 + last2 = mod remaining 10 + in (last1 + last2) {- | =💣= Task 10* From 9da85e4a17427de099957cb7de59e19176db5903 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Mon, 17 Oct 2022 22:47:49 +0800 Subject: [PATCH 10/17] chore: completed Task 10* --- src/Chapter1.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 64ffc9a33..ba91fc037 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -664,8 +664,8 @@ Implement a function that returns the first digit of a given number. You need to use recursion in this task. Feel free to return to it later, if you aren't ready for this boss yet! -} - -firstDigit n = error "firstDigit: Not implemented!" +firstDigit :: Int -> Int +firstDigit n = if abs n < 10 then abs n else firstDigit (div n 10) {- From 11749ee990931c3a9805fff52ebece1aa0f7a54f Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Tue, 18 Oct 2022 09:36:12 +0800 Subject: [PATCH 11/17] fix: fixed failing test --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index ba91fc037..4c08e59a0 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -213,7 +213,7 @@ True :: Bool >>> :t 'a' 'a' :: Char >>> :t 42 -42 :: Num a => a +42 :: Num p => p A pair of boolean and char: >>> :t (True, 'x') From a7b313f9f11186f379ed31fbdd99f8d5e5910822 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Tue, 18 Oct 2022 10:48:32 +0800 Subject: [PATCH 12/17] fix: fixed failing tests --- src/Chapter1.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 4c08e59a0..3d718fd54 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -557,7 +557,8 @@ mid :: Int -> Int -> Int -> Int mid x y z | (x > y && x < z) || (x < y && x > z) = x | (y > x && y < z) || (y < x && y > z) = y - | otherwise = z + | (z > x && z < y) || (z < x && z > y) = z + | otherwise = if x == y then x else z {- | =⚔️= Task 8 From 7f4a275b1a193749a6dbc90d4eb31b1e1e3d413b Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Sun, 23 Oct 2022 01:22:08 +0800 Subject: [PATCH 13/17] chore: completed Chapter 2 --- src/Chapter2.hs | 90 ++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/src/Chapter2.hs b/src/Chapter2.hs index f7c02ce2e..1d89e3d40 100644 --- a/src/Chapter2.hs +++ b/src/Chapter2.hs @@ -136,43 +136,43 @@ functions in GHCi and insert the corresponding resulting output below: List of booleans: >>> :t [True, False] - +[True, False] :: [Bool] String is a list of characters: >>> :t "some string" - +"some string" :: String Empty list: >>> :t [] - +[] :: [a] Append two lists: >>> :t (++) - +(++) :: [a] -> [a] -> [a] Prepend an element at the beginning of a list: >>> :t (:) - +(:) :: a -> [a] -> [a] Reverse a list: >>> :t reverse - +reverse :: [a] -> [a] Take first N elements of a list: >>> :t take - +take :: Int -> [a] -> [a] Create a list from N same elements: >>> :t replicate - +replicate :: Int -> a -> [a] Split a string by line breaks: >>> :t lines - +lines :: String -> [String] Join a list of strings with line breaks: >>> :t unlines - +unlines :: [String] -> String -} @@ -186,31 +186,31 @@ Evaluate the following expressions in GHCi and insert the answers. Try to guess first, what you will see. >>> [10, 2] ++ [3, 1, 5] - +[10,2,3,1,5] >>> [] ++ [1, 4] -- [] is an empty list - +[1,4] >>> 3 : [1, 2] - +[3,1,2] >>> 4 : 2 : [5, 10] -- prepend multiple elements - +[4,2,5,10] >>> [1 .. 10] -- list ranges - +[1,2,3,4,5,6,7,8,9,10] >>> [10 .. 1] - +[] >>> [10, 9 .. 1] -- backwards list with explicit step - +[10,9,8,7,6,5,4,3,2,1] >>> length [4, 10, 5] -- list length - +3 >>> replicate 5 True - +[True,True,True,True,True] >>> take 5 "Hello, World!" - +"Hello" >>> drop 5 "Hello, World!" - +", World!" >>> zip "abc" [1, 2, 3] -- convert two lists to a single list of pairs - +[('a',1),('b',2),('c',3)] >>> words "Hello Haskell World!" -- split the string into the list of words - +["Hello","Haskell","World!"] 👩‍🔬 Haskell has a lot of syntax sugar. In the case with lists, any @@ -336,7 +336,9 @@ from it! ghci> :l src/Chapter2.hs -} subList :: Int -> Int -> [a] -> [a] -subList = error "subList: Not implemented!" +subList start end list + | start < 0 || end < 0 || end < start = [] + | otherwise = drop start (take (end + 1) list) {- | =⚔️= Task 4 @@ -348,8 +350,8 @@ Implement a function that returns only the first half of a given list. >>> firstHalf "bca" "b" -} --- PUT THE FUNCTION TYPE IN HERE -firstHalf l = error "firstHalf: Not implemented!" +firstHalf :: [a] -> [a] +firstHalf l = take (div (length l) 2) l {- | @@ -501,7 +503,9 @@ True >>> isThird42 [42, 42, 0, 42] False -} -isThird42 = error "isThird42: Not implemented!" +isThird42 :: [Int] -> Bool +isThird42 (_:_:42:_) = True +isThird42 _ = False {- | @@ -606,7 +610,8 @@ Implement a function that duplicates each element of the list -} duplicate :: [a] -> [a] -duplicate = error "duplicate: Not implemented!" +duplicate [] = [] +duplicate (x:xs) = x : x : duplicate xs {- | @@ -621,7 +626,10 @@ Write a function that takes elements of a list only in even positions. >>> takeEven [2, 1, 3, 5, 4] [2,3,4] -} -takeEven = error "takeEven: Not implemented!" +takeEven :: [a] -> [a] +takeEven [] = [] +takeEven (x:_:xs) = x : takeEven xs +takeEven (x:xs) = x : takeEven xs {- | =🛡= Higher-order functions @@ -728,7 +736,7 @@ value of the element itself 🕯 HINT: Use combination of 'map' and 'replicate' -} smartReplicate :: [Int] -> [Int] -smartReplicate l = error "smartReplicate: Not implemented!" +smartReplicate l = concat (map (\x -> replicate x x) l) {- | =⚔️= Task 9 @@ -741,7 +749,8 @@ the list with only those lists that contain a passed element. 🕯 HINT: Use the 'elem' function to check whether an element belongs to a list -} -contains = error "contains: Not implemented!" +contains :: (Foldable t, Eq a) => a -> [t a] -> [t a] +contains n l = filter (elem n ) l {- | @@ -781,12 +790,14 @@ Let's now try to eta-reduce some of the functions and ensure that we mastered the skill of eta-reducing. -} divideTenBy :: Int -> Int -divideTenBy x = div 10 x +divideTenBy = div 10 -- TODO: type ;) -listElementsLessThan x l = filter (< x) l +listElementsLessThan :: Int -> [Int] -> [Int] +listElementsLessThan x = filter (< x) -- Can you eta-reduce this one??? +pairMul :: [Int] -> [Int] -> [Int] pairMul xs ys = zipWith (*) xs ys {- | @@ -842,7 +853,11 @@ list. 🕯 HINT: Use the 'cycle' function -} -rotate = error "rotate: Not implemented!" +rotate :: Int -> [a] -> [a] +rotate n l + | n < 0 = [] + | n == 0 = l + | otherwise = take (length l) (drop (n `mod` (length l)) (cycle l)) {- | =💣= Task 12* @@ -858,7 +873,12 @@ and reverses it. function, but in this task, you need to implement it manually. No cheating! -} -rewind = error "rewind: Not Implemented!" +rewind :: [a] -> [a] +rewind l = go l [] + where + go :: [a] -> [a] -> [a] + go [] z = z + go (x:xs) z = go xs (x:z) {- From bf665a62905474c58d8baea9e0688c3fc052df57 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Sun, 23 Oct 2022 01:29:43 +0800 Subject: [PATCH 14/17] fix: fixed failing doctest job --- src/Chapter2.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter2.hs b/src/Chapter2.hs index fb1f54be3..3ed3d2386 100644 --- a/src/Chapter2.hs +++ b/src/Chapter2.hs @@ -140,7 +140,7 @@ List of booleans: String is a list of characters: >>> :t "some string" -"some string" :: String +"some string" :: [Char] Empty list: >>> :t [] From 2e20e4ab61b00bb0eab149cf7513df07aa3973c0 Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Sun, 23 Oct 2022 11:12:44 +0800 Subject: [PATCH 15/17] fix: fixed failing doctest for Chapter 1 --- src/Chapter1.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter1.hs b/src/Chapter1.hs index 1360e920c..d53057d2b 100644 --- a/src/Chapter1.hs +++ b/src/Chapter1.hs @@ -213,7 +213,7 @@ True :: Bool >>> :t 'a' 'a' :: Char >>> :t 42 -42 :: Num p => p +42 :: Num a => a A pair of boolean and char: >>> :t (True, 'x') From 83fc11ccedba2a682240ef18b5c761886e41383b Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Sat, 29 Oct 2022 14:53:52 +0800 Subject: [PATCH 16/17] chore: completed Chapter 4 --- src/Chapter4.hs | 69 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/src/Chapter4.hs b/src/Chapter4.hs index caec5a95d..115c6caa6 100644 --- a/src/Chapter4.hs +++ b/src/Chapter4.hs @@ -113,22 +113,30 @@ As always, try to guess the output first! And don't forget to insert the output in here: >>> :k Char +Char :: * >>> :k Bool +Bool :: * >>> :k [Int] +[Int] :: * >>> :k [] +[] :: * -> * >>> :k (->) +(->) :: * -> * -> * >>> :k Either +Either :: * -> * -> * >>> data Trinity a b c = MkTrinity a b c >>> :k Trinity +Trinity :: * -> * -> * -> * >>> data IntBox f = MkIntBox (f Int) >>> :k IntBox +IntBox :: (* -> *) -> * -} @@ -291,8 +299,9 @@ we can reuse already known concepts (e.g. partial application) from values and apply them to the type level? -} instance Functor (Secret e) where - fmap :: (a -> b) -> Secret e a -> Secret e b - fmap = error "fmap for Box: not implemented!" + fmap :: (a -> b) -> Secret e a -> Secret e b + fmap _ (Trap e) = Trap e + fmap f (Reward a) = Reward (f a) {- | =⚔️= Task 3 @@ -306,6 +315,11 @@ data List a = Empty | Cons a (List a) +instance Functor List where + fmap :: (a -> b) -> List a -> List b + fmap _ Empty = Empty + fmap f (Cons x xs) = Cons (f x) (fmap f xs) + {- | =🛡= Applicative @@ -471,10 +485,11 @@ Implement the Applicative instance for our 'Secret' data type from before. -} instance Applicative (Secret e) where pure :: a -> Secret e a - pure = error "pure Secret: Not implemented!" + pure = Reward (<*>) :: Secret e (a -> b) -> Secret e a -> Secret e b - (<*>) = error "(<*>) Secret: Not implemented!" + Trap e <*> _ = Trap e + Reward f <*> a = fmap f a {- | =⚔️= Task 5 @@ -488,6 +503,19 @@ Implement the 'Applicative' instance for our 'List' type. type. -} +joinList :: List a -> List a -> List a +joinList Empty l = l +joinList ls Empty = ls +joinList (Cons x xs) l = Cons x (joinList xs l) + +instance Applicative List where + pure :: a -> List a + pure a = Cons a Empty + + (<*>) :: List (a -> b) -> List a -> List b + Empty <*> _ = Empty + _ <*> Empty = Empty + (Cons x xs) <*> l = joinList (fmap x l) (xs <*> l) {- | =🛡= Monad @@ -599,7 +627,8 @@ Implement the 'Monad' instance for our 'Secret' type. -} instance Monad (Secret e) where (>>=) :: Secret e a -> (a -> Secret e b) -> Secret e b - (>>=) = error "bind Secret: Not implemented!" + (>>=) (Trap e) _ = Trap e + Reward a >>= f = f a {- | =⚔️= Task 7 @@ -610,6 +639,13 @@ Implement the 'Monad' instance for our lists. maybe a few) to flatten lists of lists to a single list. -} +flattenList :: List(List a) -> List a +flattenList Empty = Empty +flattenList (Cons x xs) = joinList x (flattenList xs) + +instance Monad List where + (>>=) :: List a -> (a -> List b) -> List b + l >>= f = flattenList (fmap f l) {- | =💣= Task 8*: Before the Final Boss @@ -628,7 +664,7 @@ Can you implement a monad version of AND, polymorphic over any monad? 🕯 HINT: Use "(>>=)", "pure" and anonymous function -} andM :: (Monad m) => m Bool -> m Bool -> m Bool -andM = error "andM: Not implemented!" +andM a b = a >>= \f -> if f then b else pure False {- | =🐉= Task 9*: Final Dungeon Boss @@ -671,6 +707,27 @@ Specifically, ❃ Implement the function to convert Tree to list -} +data Tree a + = EmptyTree + | Node a (Tree a) (Tree a) + deriving (Show) + +instance Functor Tree where + fmap :: (a -> b) -> Tree a -> Tree b + fmap _ EmptyTree = EmptyTree + fmap f (Node a l r) = Node (f a) (fmap f l) (fmap f r) + +reverseTree :: Tree a -> Tree a +reverseTree EmptyTree = EmptyTree +reverseTree (Node a l r) = Node a (reverseTree r) (reverseTree l) + +treeToList :: Tree a -> List a +treeToList EmptyTree = Empty +treeToList (Node a l r) = Cons a (append (treeToList l) (treeToList r)) + +append :: List a -> List a -> List a +append Empty bs = bs +append (Cons a as) bs = Cons a (append as bs) {- You did it! Now it is time to open pull request with your changes From b6c777a0562ce2633bf841813d320739d6f2b30e Mon Sep 17 00:00:00 2001 From: Jed Aureus Gonzales Date: Wed, 9 Nov 2022 11:37:11 +0800 Subject: [PATCH 17/17] test push --- src/Chapter4.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Chapter4.hs b/src/Chapter4.hs index 115c6caa6..710c89e98 100644 --- a/src/Chapter4.hs +++ b/src/Chapter4.hs @@ -732,4 +732,4 @@ append (Cons a as) bs = Cons a (append as bs) {- You did it! Now it is time to open pull request with your changes and summon @vrom911 for the review! --} +-} \ No newline at end of file