mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
publish part2 preview!
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
module Examples.Bank where
|
||||
|
||||
import qualified Data.Map as Map
|
||||
|
||||
data Bank = Bank (Map.Map String Int)
|
||||
deriving (Show,Eq)
|
||||
|
||||
deposit :: String -> Int -> Bank -> Bank
|
||||
deposit accountName amount (Bank accounts) =
|
||||
Bank (Map.adjust (\x -> x+amount) accountName accounts)
|
||||
|
||||
withdraw :: String -> Int -> Bank -> (Int,Bank)
|
||||
withdraw accountName amount (Bank accounts) =
|
||||
let balance = Map.findWithDefault 0 accountName accounts -- balance is 0 for a nonexistant account
|
||||
withdrawal = min amount balance -- can't withdraw over balance
|
||||
newAccounts = Map.adjust (\x -> x-withdrawal) accountName accounts
|
||||
in (withdrawal, Bank newAccounts)
|
||||
|
||||
-- `BankOp a` is an operation that transforms a Bank value, while returning a value of type `a`
|
||||
data BankOp a = BankOp (Bank -> (a,Bank))
|
||||
|
||||
-- running a BankOp on a Bank
|
||||
runBankOp :: BankOp a -> Bank -> (a,Bank)
|
||||
runBankOp (BankOp f) bank = f bank
|
||||
|
||||
-- Running one BankOp after another
|
||||
(+>>) :: BankOp a -> BankOp b -> BankOp b
|
||||
op1 +>> op2 = BankOp combined
|
||||
where combined bank = let (_,bank1) = runBankOp op1 bank
|
||||
in runBankOp op2 bank1
|
||||
|
||||
-- Running a parameterized BankOp, using the value returned by a previous BankOp
|
||||
-- The implementation is a bit tricky but it's enough to understand how +> is used for now.
|
||||
(+>) :: BankOp a -> (a -> BankOp b) -> BankOp b
|
||||
op +> parameterized = BankOp combined
|
||||
where combined bank = let (a,bank1) = runBankOp op bank
|
||||
in runBankOp (parameterized a) bank1
|
||||
|
||||
-- Make a BankOp out of deposit. There is no return value so we use ().
|
||||
depositOp :: String -> Int -> BankOp ()
|
||||
depositOp accountName amount = BankOp depositHelper
|
||||
where depositHelper bank = ((), deposit accountName amount bank)
|
||||
|
||||
-- Make a BankOp out of withdraw. Note how
|
||||
-- withdraw accountName amount :: Bank -> (Int,Bank)
|
||||
-- is almost a BankOp already!
|
||||
withdrawOp :: String -> Int -> BankOp Int
|
||||
withdrawOp accountName amount = BankOp (withdraw accountName amount)
|
||||
|
||||
-- distribute amount to two accounts
|
||||
distributeOp :: String -> String -> Int -> BankOp ()
|
||||
distributeOp to1 to2 amount =
|
||||
depositOp to1 half
|
||||
+>>
|
||||
depositOp to2 rest
|
||||
where half = div amount 2
|
||||
rest = amount - half
|
||||
|
||||
-- withdraw up to 100 units from one account, and distribute it evenly among two accounts
|
||||
shareOp :: String -> String -> String -> BankOp ()
|
||||
shareOp from to1 to2 =
|
||||
withdrawOp from 100
|
||||
+>
|
||||
distributeOp to1 to2
|
||||
@@ -0,0 +1,9 @@
|
||||
import Network.HTTP
|
||||
import Control.Monad
|
||||
|
||||
main = do
|
||||
rsp <- simpleHTTP (getRequest "http://httpbin.org/base64/aGFza2VsbCBmb3IgZXZlcgo=")
|
||||
body <- getResponseBody rsp
|
||||
forM_ (words body) $ \w -> do
|
||||
putStr "word: "
|
||||
putStrLn w
|
||||
@@ -0,0 +1,40 @@
|
||||
module Examples.ReadTypes where
|
||||
|
||||
import Control.Monad (forM)
|
||||
import Data.List (isInfixOf, isSuffixOf)
|
||||
import System.Directory (listDirectory, doesDirectoryExist)
|
||||
|
||||
-- a line is a type signature if it contains :: but does not contain =
|
||||
isTypeSignature :: String -> Bool
|
||||
isTypeSignature s = not (isInfixOf "=" s) && isInfixOf "::" s
|
||||
|
||||
-- return list of types for a .hs file
|
||||
readTypesFile :: FilePath -> IO [String]
|
||||
readTypesFile file
|
||||
| isSuffixOf ".hs" file = do content <- readFile file
|
||||
let ls = lines content
|
||||
return (filter isTypeSignature ls)
|
||||
| otherwise = return []
|
||||
|
||||
-- list children of directory, prepend directory name
|
||||
qualifiedChildren :: String -> IO [String]
|
||||
qualifiedChildren path = do childs <- listDirectory path
|
||||
return (map (\name -> path++"/"++name) childs)
|
||||
|
||||
-- get type signatures for all entries in given directory
|
||||
-- note mutual recursion with readTypes
|
||||
readTypesDir :: String -> IO [String]
|
||||
readTypesDir path = do childs <- qualifiedChildren path
|
||||
typess <- forM childs readTypes
|
||||
return (concat typess)
|
||||
|
||||
-- recursively read types contained in a file or directory
|
||||
-- note mutual recursion with readTypesDir
|
||||
readTypes :: String -> IO [String]
|
||||
readTypes path = do isDir <- doesDirectoryExist path
|
||||
if isDir then readTypesDir path else readTypesFile path
|
||||
|
||||
-- main is the IO action that gets run when you run the program
|
||||
main :: IO ()
|
||||
main = do ts <- readTypes "."
|
||||
mapM_ putStrLn ts
|
||||
@@ -0,0 +1 @@
|
||||
module Mooc.VeryLimitedPrelude (Int,Integer,Bool(..),Num(..),otherwise,undefined) where
|
||||
@@ -0,0 +1,162 @@
|
||||
module Set10a where
|
||||
|
||||
import Data.Char
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: Given a list, produce a new list where each element of the
|
||||
-- original list repeats twice.
|
||||
--
|
||||
-- Make sure your function works with infinite lists.
|
||||
--
|
||||
-- Examples:
|
||||
-- doublify [7,1,6] ==> [7,7,1,1,6,6]
|
||||
-- take 10 (doublify [0..]) ==> [0,0,1,1,2,2,3,3,4,4]
|
||||
|
||||
doublify :: [a] -> [a]
|
||||
doublify = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: Implement the function interleave that takes two lists and
|
||||
-- produces a new list that takes elements alternatingly from both
|
||||
-- lists like this:
|
||||
--
|
||||
-- interleave [1,2,3] [4,5,6] ==> [1,4,2,5,3,6]
|
||||
--
|
||||
-- If one list runs out of elements before the other, just keep adding
|
||||
-- elements from the other list.
|
||||
--
|
||||
-- Make sure your function also works with infinite lists.
|
||||
--
|
||||
-- Examples:
|
||||
-- interleave [1,2,3] [4,5,6] ==> [1,4,2,5,3,6]
|
||||
-- interleave [1,2] [4,5,6,7] ==> [1,4,2,5,6,7]
|
||||
-- take 10 (interleave [7,7,7] [1..]) ==> [7,1,7,2,7,3,4,5,6,7]
|
||||
-- take 10 (interleave [1..] (repeat 0)) ==> [1,0,2,0,3,0,4,0,5,0]
|
||||
|
||||
interleave :: [a] -> [a] -> [a]
|
||||
interleave = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: Deal out cards. Given a list of cards (strings), and a list
|
||||
-- of players (strings), deal out the cards to the players in a cycle.
|
||||
--
|
||||
-- Make sure your function works with infinite inputs as well!
|
||||
--
|
||||
-- Example:
|
||||
-- deal ["Hercule","Ariadne"] ["Ace","Joker","Heart"]
|
||||
-- ==> [("Ace","Hercule"),("Joker","Ariadne"),("Heart","Hercule")]
|
||||
-- take 4 (deal ["a","b","c"] (map show [0..]))
|
||||
-- ==> [("0","a"),("1","b"),("2","c"),("3","a")]
|
||||
-- deal ("you":(repeat "me")) ["1","2","3","4"]
|
||||
-- ==> [("1","you"),("2","me"),("3","me"),("4","me")]
|
||||
--
|
||||
-- Hint: remember the functions cycle and zip?
|
||||
|
||||
deal :: [String] -> [String] -> [(String,String)]
|
||||
deal = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: Given two lists, xs and ys, and an element z, generate an
|
||||
-- infinite list that consists of
|
||||
--
|
||||
-- * the elements of xs
|
||||
-- * z
|
||||
-- * the elements of ys
|
||||
-- * z
|
||||
-- * the elements of xs
|
||||
-- * ... and so on
|
||||
--
|
||||
-- Examples:
|
||||
-- take 20 (alternate "abc" "def" ',') ==> "abc,def,abc,def,abc,"
|
||||
-- take 10 (alternate [1,2] [3,4,5] 0) ==> [1,2,0,3,4,5,0,1,2,0]
|
||||
|
||||
alternate :: [a] -> [a] -> a -> [a]
|
||||
alternate xs ys z = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: Check if the length of a list is at least n. Make sure your
|
||||
-- function works for infinite inputs.
|
||||
--
|
||||
-- Examples:
|
||||
-- lengthAtLeast 2 [1,2,3] ==> True
|
||||
-- lengthAtLeast 7 [1,2,3] ==> False
|
||||
-- lengthAtLeast 10 [0..] ==> True
|
||||
|
||||
lengthAtLeast :: Int -> [a] -> Bool
|
||||
lengthAtLeast = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: The function chunks should take in a list, and a number n,
|
||||
-- and return all sublists of length n of the original list.
|
||||
--
|
||||
-- Make sure your function works with infinite inputs. The function
|
||||
-- lengthAtLeast can help with this.
|
||||
--
|
||||
-- Examples:
|
||||
-- chunks 2 [1,2,3,4] ==> [[1,2],[2,3],[3,4]]
|
||||
-- take 4 (chunks 3 [0..]) ==> [[0,1,2],[1,2,3],[2,3,4],[3,4,5]]
|
||||
|
||||
chunks :: Int -> [a] -> [[a]]
|
||||
chunks = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: Define a newtype called IgnoreCase, that wraps a value of
|
||||
-- type String. Define an `Eq` instance for IgnoreCase so that it
|
||||
-- compares strings in a case-insensitive way.
|
||||
--
|
||||
-- To help the tests, also implement the function
|
||||
-- ignorecase :: String -> IgnoreCase
|
||||
--
|
||||
-- Hint: remember Data.Char.toLower
|
||||
--
|
||||
-- Examples:
|
||||
-- ignorecase "abC" == ignoreCase "ABc" ==> True
|
||||
-- ignorecase "acC" == ignoreCase "ABc" ==> False
|
||||
|
||||
data IgnoreCase = Todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: Here's the Room type and some helper functions from the
|
||||
-- course material. Define a cyclic Room structure like this:
|
||||
--
|
||||
-- * maze1 has the description "Maze"
|
||||
-- * The direction "Left" goes to maze2
|
||||
-- * "Right" goes to maze3
|
||||
-- * maze2 has the description "Deeper in the maze"
|
||||
-- * "Left" goes to maze3
|
||||
-- * "Right" goes to maze1
|
||||
-- * maze3 has the description "Elsewhere in the maze"
|
||||
-- * "Left" goes to maze1
|
||||
-- * "Right" goes to maze2
|
||||
--
|
||||
-- The variable maze should point to the room maze1.
|
||||
--
|
||||
-- Examples:
|
||||
-- play maze ["Left","Left","Left"]
|
||||
-- ==> ["Maze","Deeper in the maze","Elsewhere in the maze","Maze"]
|
||||
-- play maze ["Right","Right","Right","Right"]
|
||||
-- ==> ["Maze","Elsewhere in the maze","Deeper in the maze","Maze","Elsewhere in the maze"]
|
||||
-- play maze ["Left","Left","Right"]
|
||||
-- ==> ["Maze","Deeper in the maze","Elsewhere in the maze","Deeper in the maze"]
|
||||
|
||||
data Room = Room String [(String,Room)]
|
||||
|
||||
-- Do not modify describe, move or play. The tests will use the
|
||||
-- original definitions of describe, move and play regardless of your
|
||||
-- modifications.
|
||||
|
||||
describe :: Room -> String
|
||||
describe (Room s _) = s
|
||||
|
||||
move :: Room -> String -> Maybe Room
|
||||
move (Room _ directions) direction = lookup direction directions
|
||||
|
||||
play :: Room -> [String] -> [String]
|
||||
play room [] = [describe room]
|
||||
play room (d:ds) = case move room d of Nothing -> [describe room]
|
||||
Just r -> describe room : play r ds
|
||||
|
||||
maze :: Room
|
||||
maze = todo
|
||||
@@ -0,0 +1,168 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
||||
|
||||
module Set10aTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Control.Exception (evaluate, try, SomeException)
|
||||
import Data.Char
|
||||
import Data.List
|
||||
import Language.Haskell.TH
|
||||
import Test.QuickCheck
|
||||
import Test.QuickCheck.Monadic
|
||||
|
||||
|
||||
import Set10a hiding (describe,move,play)
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"doublify",[ex1_finite, ex1_infinite])
|
||||
,(2,"interleave",[ex2_finite, ex2_infinite_1, ex2_infinite_2])
|
||||
,(3,"deal",[ex3_examples, ex3_finite, ex3_infinite_1, ex3_infinite_2])
|
||||
,(4,"alternate",[ex4_examples, ex4])
|
||||
,(5,"lenghtAtLeast",[ex5_finite, ex5_infinite])
|
||||
,(6,"chunks",[ex6_finite, ex6_infinite])
|
||||
,(7,"IgnoreCase",[ex7_type, ex7_works])
|
||||
,(8,"maze",[ex8_1, ex8_2])]
|
||||
|
||||
-- -- -- --
|
||||
|
||||
ex1_finite =
|
||||
forAllBlind (choose (0,10)) $ \n ->
|
||||
forAllBlind (choose ('a','z')) $ \c ->
|
||||
forAllBlind (choose ('a','z')) $ \d ->
|
||||
$(testing [|doublify (replicate n c ++ [d])|]) (?==(replicate (2*n) c ++ [d,d]))
|
||||
|
||||
ex1_infinite =
|
||||
forAllBlind (choose (0,100)) $ \n ->
|
||||
forAllBlind (choose (0,1000)) $ \i ->
|
||||
counterexample ("With n = "++show n) $
|
||||
$(testing' [|doublify [n..]|]) $ \was ->
|
||||
counterexample (" Index "++show i) $
|
||||
was !! i ?== n + div i 2
|
||||
|
||||
evens (x:xs) = odds xs
|
||||
evens [] = []
|
||||
odds (x:xs) = x:evens xs
|
||||
odds [] = []
|
||||
|
||||
ex2_finite = forAll_ $ \(is::[Integer]) ->
|
||||
forAll_ $ \(rest::[Integer]) ->
|
||||
let as = odds is
|
||||
bs = evens is
|
||||
in conjoin [$(testing [|interleave as bs|]) (?==is)
|
||||
,if length as > length bs
|
||||
then $(testing [|interleave (as++rest) bs|]) (?==is++rest)
|
||||
else $(testing [|interleave as (bs++rest)|]) (?==is++rest)]
|
||||
|
||||
ex2_infinite_1 = forAll_ $ \(i::Integer,j::Integer) ->
|
||||
counterexample ("with i = " ++ show i ++ ", j = " ++ show j) $
|
||||
$(testing' [|take 10 (interleave (repeat i) (repeat j))|]) (?==take 10 (cycle [i,j]))
|
||||
|
||||
ex2_infinite_2 = forAll_ $ \(x::Integer) ->
|
||||
forAll_ $ \(Positive i) ->
|
||||
counterexample ("with x = " ++ show x) $
|
||||
$(testing' [|interleave [0..] (repeat x)|]) $ \res ->
|
||||
counterexample (" element at index " ++ show i) $
|
||||
res !! i == if odd i then x else fromIntegral (div i 2)
|
||||
|
||||
ex3_examples =
|
||||
conjoin [$(testing [|deal ["Hercule","Ariadne"] ["Ace","Joker","Heart"]|]) (?==[("Ace","Hercule"),("Joker","Ariadne"),("Heart","Hercule")])
|
||||
,$(testing [|deal ["Hercule","Ariadne"] e|]) (?==[])]
|
||||
where e = [] :: [String]
|
||||
|
||||
word = listOf1 (choose ('a','z'))
|
||||
|
||||
ex3_finite = forAllShrink_ (listOf1 word) $ \names ->
|
||||
forAllShrink_ (listOf1 word) $ \cards ->
|
||||
and [not (null names), not (null cards)] ==>
|
||||
$(testing [|deal names cards|]) (?==[(cards!!i, names!!(mod i (length names))) | i <- [0..length cards - 1]])
|
||||
|
||||
ex3_infinite_1 = forAllShrink_ (listOf1 word) $ \names ->
|
||||
not (null names) ==>
|
||||
forAllBlind (choose (length names, 10*length names)) $ \n ->
|
||||
counterexample ("With n = "++show n++", names = "++show names) $
|
||||
$(testing' [|take n (deal names (map show [0..]))|]) (?==[(show i, names!!(mod i (length names))) | i <- [0..n - 1]])
|
||||
|
||||
ex3_infinite_2 =
|
||||
$(testing' [|take 10 (deal (repeat "me") (repeat "card"))|]) (?==replicate 10 ("card","me"))
|
||||
|
||||
ex4_examples = conjoin [$(testing' [|take 20 (alternate "abc" "def" ',')|]) (?=="abc,def,abc,def,abc,")
|
||||
,$(testing' [|take 10 (alternate [1,2] [3,4,5] 0)|]) (?==[1,2,0,3,4,5,0,1,2,0])]
|
||||
|
||||
ex4 = forAllBlind (choose (1,3)) $ \n ->
|
||||
forAllBlind (choose (1,6)) $ \m ->
|
||||
forAll_ $ \(NonNegative i) ->
|
||||
$(testing [|alternate (replicate n 1) (replicate m 1) 0|]) $ \was ->
|
||||
counterexample (" Index "++show i) $
|
||||
(was !! i ?== if mod i (2+n+m) `elem` [n,n+1+m] then 0 else 1)
|
||||
|
||||
ex5_finite = forAll_ $ \(is::[Int]) ->
|
||||
forAll_ $ \(NonNegative n) ->
|
||||
$(testing [|lengthAtLeast n is|]) (?==(length is >= n))
|
||||
|
||||
ex5_infinite = forAll_ $ \(Positive (i::Int)) ->
|
||||
forAll_ $ \(NonNegative n) ->
|
||||
counterexample ("With n = " ++ show n ++ ", i = " ++ show i) $
|
||||
$(testing' [|lengthAtLeast n (repeat i)|]) (?==True)
|
||||
|
||||
ex6_finite = forAllBlind (choose (1,6)) $ \n ->
|
||||
forAllShrink_ (listOf word) $ \ws ->
|
||||
$(testing [|chunks n ws|]) (?==[[ws!!i | i <- [j..j+n-1]] | j <- [0..length ws - n]])
|
||||
|
||||
ex6_infinite = forAllBlind (choose (1,10)) $ \n ->
|
||||
forAllBlind (choose (1,25)) $ \k ->
|
||||
counterexample ("With k = "++show k++", n = "++show n) $
|
||||
$(testing' [|take k (chunks n [0..])|]) (?==[[j..j+n-1] | j <- [0..k-1]])
|
||||
|
||||
shuffleCase w = (do s <- vectorOf (length w) (elements [toLower,toUpper])
|
||||
return (zipWith ($) s w)) `suchThat` (/=w)
|
||||
|
||||
ex7_type = $(do let s = "IgnoreCase"
|
||||
n <- lookupTypeName s
|
||||
case n of
|
||||
Nothing -> [|counterexample ("Type "++s++" not defined!") False|]
|
||||
Just n -> do info <- reify n
|
||||
case info of TyConI (NewtypeD _ _ _ _ _ _) -> [|property True|]
|
||||
_ -> [|counterexample ("Definition "++s++" is not a newype declaration!") False|])
|
||||
|
||||
ex7_works =
|
||||
$(hasType "ignorecase" [t|String -> IgnoreCase|]) $ \ignorecase ->
|
||||
$(withInstance "Eq" "IgnoreCase" [|(==)|]) $ \((==)::IgnoreCase->IgnoreCase->Bool) ->
|
||||
property $ do
|
||||
w1 <- word
|
||||
w2 <- shuffleCase w1
|
||||
w3 <- word
|
||||
let t :: String -> String -> Bool -> Property
|
||||
t x y exp = counterexample ("ignorecase " ++ show x ++ " == ignorecase " ++ show y) $ (ignorecase x == ignorecase y) ?== exp
|
||||
return $ conjoin [t w1 w1 True
|
||||
,t w1 w2 True
|
||||
,t w2 w1 True
|
||||
,t (w1++w3) w2 False
|
||||
,t w2 (w1++w3) False
|
||||
,t w1 (w2++w3) False
|
||||
,t (w2++w3) w1 False]
|
||||
|
||||
|
||||
describe :: Room -> String
|
||||
describe (Room s _) = s
|
||||
|
||||
move :: Room -> String -> Maybe Room
|
||||
move (Room _ directions) direction = lookup direction directions
|
||||
|
||||
play :: Room -> [String] -> [String]
|
||||
play room [] = [describe room]
|
||||
play room (d:ds) = case move room d of Nothing -> [describe room]
|
||||
Just r -> describe room : play r ds
|
||||
|
||||
ex8_1 = forAllShrink_ (choose (0,20)) $ \i ->
|
||||
counterexample ("with i = " ++ show i) $
|
||||
conjoin [$(testing' [|play maze (replicate i "Left")|]) (?==take (i+1) (cycle ["Maze","Deeper in the maze","Elsewhere in the maze"]))
|
||||
,$(testing' [|play maze (replicate i "Right")|]) (?==take (i+1) (cycle ["Maze","Elsewhere in the maze","Deeper in the maze"]))]
|
||||
|
||||
ex8_2 = forAllShrinkBlind (listOf (elements ["Left","Right"])) subterms $ \dirs ->
|
||||
let cnt = sum (map (\d -> case d of "Left" -> 1; "Right" -> -1) dirs)
|
||||
answer = ["Maze","Deeper in the maze","Elsewhere in the maze"] !! mod cnt 3
|
||||
in counterexample ("with dirs = " ++ show dirs) $
|
||||
$(testing' [|last (play maze dirs)|]) (?==answer)
|
||||
@@ -0,0 +1,90 @@
|
||||
-- This exercise set hides most of Prelude. You only have access to
|
||||
-- the Bool, Int and list types, and pattern matching.
|
||||
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
|
||||
module Set10b where
|
||||
|
||||
import Mooc.VeryLimitedPrelude
|
||||
import Mooc.Todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: Define the operator ||| that works like ||, but forces its
|
||||
-- _right_ argument instead of the left one.
|
||||
--
|
||||
-- Examples:
|
||||
-- False ||| False ==> False
|
||||
-- True ||| False ==> True
|
||||
-- undefined ||| True ==> True
|
||||
-- False ||| undefined ==> an error!
|
||||
|
||||
(|||) :: Bool -> Bool -> Bool
|
||||
x ||| y = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: Define the function boolLength, that returns the length of a
|
||||
-- list of booleans and forces all of the elements
|
||||
--
|
||||
-- Examples:
|
||||
-- boolLength [False,True,False] ==> 3
|
||||
-- boolLength [False,undefined] ==> an error!
|
||||
--
|
||||
-- Note that with the ordinary length function,
|
||||
-- length [False,undefined] ==> 2
|
||||
|
||||
boolLength :: [Bool] -> Int
|
||||
boolLength xs = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: Define the function validate which, given a predicate and a
|
||||
-- value, evaluates to the value. However, validate should also force the
|
||||
-- result of `predicate value`, even though it is not used.
|
||||
--
|
||||
-- Examples:
|
||||
-- validate even 3 ==> 3
|
||||
-- validate odd 3 ==> 3
|
||||
-- validate undefined 3 ==> an error!
|
||||
-- validate (\x -> undefined) 3 ==> an error!
|
||||
|
||||
validate :: (a -> Bool) -> a -> a
|
||||
validate predicate value = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: Even though we can't implement the generic seq function
|
||||
-- ourselves, we can implement it manually for specific datatypes.
|
||||
--
|
||||
-- The type class MySeq contains the method myseq which is supposed to
|
||||
-- work like the built-in seq function. Implement the given MySeq
|
||||
-- instances.
|
||||
--
|
||||
-- Just like in the course material, we use the special value
|
||||
-- `undefined` here to illustrate what myseq evaluates. The tests for
|
||||
-- this exercise also use undefined.
|
||||
--
|
||||
-- Examples:
|
||||
-- myseq True 0 ==> 0
|
||||
-- myseq (not True) 0 ==> 0
|
||||
-- myseq (undefined :: Bool) 0
|
||||
-- ==> *** Exception: Prelude.undefined
|
||||
-- myseq (3::Int) True ==> True
|
||||
-- myseq (undefined::Int) True
|
||||
-- ==> *** Exception: Prelude.undefined
|
||||
-- myseq [1,2] 'z' ==> 'z'
|
||||
-- myseq [undefined] 'z' ==> 'z' -- [undefined] is in WHNF
|
||||
-- myseq (1:undefined) 'z' ==> 'z' -- 1:undefined is in WHNF
|
||||
-- myseq (undefined:[2,3]) 'z' ==> 'z' -- undefined:[2,3] is in WHNF
|
||||
-- myseq [1..] 'z' ==> 'z'
|
||||
-- myseq (undefined::[Int])
|
||||
-- ==> *** Exception: Prelude.undefined
|
||||
|
||||
class MySeq a where
|
||||
myseq :: a -> b -> b
|
||||
|
||||
instance MySeq Bool where
|
||||
myseq = todo
|
||||
|
||||
instance MySeq Int where
|
||||
myseq = todo
|
||||
|
||||
instance MySeq [a] where
|
||||
myseq = todo
|
||||
@@ -0,0 +1,71 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
||||
|
||||
module Set10bTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Control.Exception (evaluate, try, SomeException)
|
||||
import Data.List
|
||||
import Test.QuickCheck
|
||||
import Test.QuickCheck.Monadic
|
||||
|
||||
|
||||
import Set10b
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"|||",[imports, ex1_normal, ex1_undefined])
|
||||
,(2,"boolLength",[imports, ex2_normal, ex2_undefined])
|
||||
,(3,"validate",[imports, ex3_normal, ex3_fail])
|
||||
,(4,"myseq",[imports, ex4_bool, ex4_int, ex4_list_ok, ex4_list_fail])
|
||||
]
|
||||
|
||||
-- -- -- -- --
|
||||
|
||||
imports = $(importsOnly "Set10b" ["GHC.Num", "GHC.Base", "GHC.Classes", "GHC.Types", "GHC.Err",
|
||||
"Mooc.Todo", "Mooc.VeryLimitedPrelude"])
|
||||
|
||||
ex1_normal = forAll_ $ \(a,b) ->
|
||||
$(testing [|a ||| b|]) (?==(a||b))
|
||||
|
||||
ex1_undefined =
|
||||
counterexample ("undefined ||| True") $ (errorWithoutStackTrace "You forced your left argument!"|||True) == True
|
||||
|
||||
ex2_normal = forAll_ $ \bs -> boolLength bs === length bs
|
||||
|
||||
ex2_undefined = forAll_ $ \bs ->
|
||||
counterexample ("boolLength ("++show bs++"++[undefined,True])") $
|
||||
shouldFail (boolLength (bs++[undefined,True]))
|
||||
|
||||
ex3_normal = forAll_ $ \(n::Int) ->
|
||||
counterexample ("validate even "++show n) $
|
||||
validate even n ?== n
|
||||
|
||||
ex3_fail = conjoin [counterexample "validate undefined 'c'" $ shouldFail (validate undefined 'c')
|
||||
,counterexample "validate (\\x -> undefined) \"foo\"" $ shouldFail (validate (\x -> undefined) "foo")]
|
||||
|
||||
ex4_bool = $(withInstance "MySeq" "Bool" [|myseq :: Bool -> a -> a|]) $ \myseq ->
|
||||
forAll_ $ \(i::Int) ->
|
||||
conjoin [$(testing [|myseq True i|]) (?==i)
|
||||
,$(testing [|myseq False i|]) (?==i)
|
||||
,counterexample ("myseq (undefined::Bool) " ++ show i) $ shouldFail (myseq (undefined::Bool) i)]
|
||||
|
||||
ex4_int = $(withInstance "MySeq" "Int" [|myseq :: Int -> a -> a|]) $ \myseq ->
|
||||
forAll_ $ \(i::Int,b::Bool) ->
|
||||
conjoin [$(testing [|myseq i b|]) (?==b)
|
||||
,counterexample ("myseq (undefined::Int) " ++ show b) $ shouldFail (myseq (undefined::Int) b)]
|
||||
|
||||
ex4_list_ok = $(withInstance1 "MySeq" "[]" [|myseq :: [Int] -> a -> a|]) $ \myseq ->
|
||||
forAll_ $ \(is::[Int]) ->
|
||||
forAll_ $ \(i::Int) ->
|
||||
forAllBlind (choose ('a','z')) $ \c ->
|
||||
$(testing [|myseq is c|]) (?==c)
|
||||
.&&.
|
||||
conjoin' [counterexample ("myseq (undefined:" ++ show is ++") " ++ show c) $ counterexample " should not fail" $ (myseq (undefined:is) c ?== c)
|
||||
,counterexample ("myseq (" ++ show is ++ "++[undefined]) " ++ show c) $ counterexample " should not fail" $ (myseq (is++[undefined]) c ?== c)
|
||||
,counterexample ("myseq (" ++ show i ++ ":undefined) " ++ show c) $ counterexample " should not fail" $ (myseq (i:undefined) c ?== c)]
|
||||
|
||||
ex4_list_fail = $(withInstance1 "MySeq" "[]" [|myseq :: [Int] -> a -> a|]) $ \myseq ->
|
||||
forAllBlind (choose ('a','z')) $ \c ->
|
||||
counterexample ("myseq (undefined::[Int]) "++show c) $ shouldFail (myseq (undefined::[Int]) c)
|
||||
@@ -0,0 +1,143 @@
|
||||
module Set11a where
|
||||
|
||||
import Control.Monad
|
||||
import Data.List
|
||||
import System.IO
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
-- Lecture 11:
|
||||
-- * The IO type
|
||||
-- * do-notation
|
||||
--
|
||||
-- Useful functions / operations:
|
||||
-- * putStrLn
|
||||
-- * getLine
|
||||
-- * readLn
|
||||
-- * replicateM
|
||||
-- * readFile
|
||||
-- * lines
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: define an IO operation hello that prints two lines. The
|
||||
-- first line should be HELLO and the second one WORLD
|
||||
|
||||
hello :: IO ()
|
||||
hello = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: define the IO operation greet that takes a name as an
|
||||
-- argument and prints a line "HELLO name".
|
||||
|
||||
greet :: String -> IO ()
|
||||
greet name = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: define the IO operation greet2 that reads a name from the
|
||||
-- keyboard and then greets that name like the in the previous
|
||||
-- exercise.
|
||||
--
|
||||
-- Try to use the greet operation in your solution.
|
||||
|
||||
greet2 :: IO ()
|
||||
greet2 = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: define the IO operation readWords n which reads n lines from
|
||||
-- the user and produces them as a list, in alphabetical order.
|
||||
--
|
||||
-- Example in GHCi:
|
||||
-- Set11> readWords 3
|
||||
-- bob
|
||||
-- alice
|
||||
-- carl
|
||||
-- ["alice","bob","carl"]
|
||||
|
||||
readWords :: Int -> IO [String]
|
||||
readWords n = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: define the IO operation readUntil f, which reads lines from
|
||||
-- the user and returns them as a list. Reading is stopped when f
|
||||
-- returns True for a line. (The value for which f returns True is not
|
||||
-- returned.)
|
||||
--
|
||||
-- Example in GHCi:
|
||||
-- *Set11> readUntil (=="STOP")
|
||||
-- bananas
|
||||
-- garlic
|
||||
-- pakchoi
|
||||
-- STOP
|
||||
-- ["bananas","garlic","pakchoi"]
|
||||
|
||||
readUntil :: (String -> Bool) -> IO [String]
|
||||
readUntil f = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: given n, print the numbers from n to 0, one per line
|
||||
|
||||
countdownPrint :: Int -> IO ()
|
||||
countdownPrint n = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: isums n should read n numbers from the user (one per line) and
|
||||
-- 1) after each number, print the running sum up to that number
|
||||
-- 2) finally, produce the sum of all numbers
|
||||
--
|
||||
-- Example:
|
||||
-- 1. run `isums 3`
|
||||
-- 2. user enters '3', should print '3'
|
||||
-- 3. user enters '5', should print '8' (3+5)
|
||||
-- 4. user enters '1', should print '9' (3+5+1)
|
||||
-- 5. produces 9
|
||||
|
||||
isums :: Int -> IO Int
|
||||
isums n = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: when is a useful function, but its first argument has type
|
||||
-- Bool. Write a function that behaves similarly but the first
|
||||
-- argument has type IO Bool.
|
||||
|
||||
whenM :: IO Bool -> IO () -> IO ()
|
||||
whenM cond op = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 9: implement the while loop. while condition operation should
|
||||
-- run operation as long as condition returns True.
|
||||
--
|
||||
-- Examples:
|
||||
-- -- prints nothing
|
||||
-- while (return False) (putStrLn "IMPOSSIBLE")
|
||||
--
|
||||
-- -- prints YAY! as long as the user keeps answering Y
|
||||
-- while ask (putStrLn "YAY!")
|
||||
|
||||
-- used in an example
|
||||
ask :: IO Bool
|
||||
ask = do putStrLn "Y/N?"
|
||||
line <- getLine
|
||||
return $ line == "Y"
|
||||
|
||||
while :: IO Bool -> IO () -> IO ()
|
||||
while cond op = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 10: given a string and an IO operation, print the string, run
|
||||
-- the IO operation, print the string again, and finally return what
|
||||
-- the operation returned.
|
||||
--
|
||||
-- Note! the operation should be run only once
|
||||
--
|
||||
-- Examples:
|
||||
-- debug "CIAO" (return 3)
|
||||
-- - prints two lines that contain CIAO
|
||||
-- - returns the value 3
|
||||
-- debug "BOOM" getLine
|
||||
-- 1. prints "BOOM"
|
||||
-- 2. reads a line from the user
|
||||
-- 3. prints "BOOM"
|
||||
-- 4. returns the line read from the user
|
||||
|
||||
debug :: String -> IO a -> IO a
|
||||
debug s op = todo
|
||||
@@ -0,0 +1,104 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
||||
|
||||
module Set11aTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Control.Monad
|
||||
import Data.List
|
||||
|
||||
import Test.QuickCheck
|
||||
|
||||
import Set11a hiding (ask)
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = precondition imports
|
||||
[(1,"hello",[ex1_hello])
|
||||
,(2,"greet",[ex2_greet])
|
||||
,(3,"greet2",[ex3_greet2])
|
||||
,(4,"readWords",[ex4_readWords])
|
||||
,(5,"readUntil",[ex5_readUntil])
|
||||
,(6,"countdownPrint",[ex6])
|
||||
,(7,"isums",[ex7_isums])
|
||||
,(8,"whenM",[ex8_whenM_True, ex8_whenM_False])
|
||||
,(9,"while",[ex9_example, ex9_False])
|
||||
,(10,"debug",[ex10_debug])]
|
||||
|
||||
-- -- -- -- --
|
||||
|
||||
imports = $(importsOnly "Set11a" ["Control.Monad","Data.List","Data.Foldable","Prelude","Data.OldList","System.IO"
|
||||
,"GHC.Num", "GHC.Base", "GHC.Classes", "GHC.Show", "GHC.Types", "GHC.Err"
|
||||
,"Mooc.Todo"])
|
||||
|
||||
ex1_hello =
|
||||
$(testing [|hello|]) . withNoInput $
|
||||
checkOutput (?== "HELLO\nWORLD\n")
|
||||
|
||||
word = listOf1 (choose ('a','z'))
|
||||
|
||||
ex2_greet = forAllBlind word $ \name ->
|
||||
$(testing [|greet name|]) . withNoInput $
|
||||
checkOutput (?== ("HELLO "++name++"\n"))
|
||||
|
||||
ex3_greet2 = forAllBlind word $ \name ->
|
||||
$(testing [|greet2|]) . withInput (name++"\n") $
|
||||
checkOutput (?== ("HELLO "++name++"\n"))
|
||||
|
||||
ex4_readWords =
|
||||
forAllBlind (listOf1 word) $ \words ->
|
||||
$(testing [|readWords (length words - 1)|]) . withInput (unlines words) $
|
||||
checkResult (?== sort (init words))
|
||||
|
||||
ex5_readUntil =
|
||||
forAllBlind word $ \end ->
|
||||
forAllBlind (listOf1 (word `suchThat` (/=end))) $ \words ->
|
||||
counterexample ("readUntil (=="++show end++")") $
|
||||
($ readUntil (==end)) $
|
||||
withInput (unlines $ words ++ [end]) $
|
||||
checkResult (?==words)
|
||||
|
||||
ex6 =
|
||||
forAllBlind (choose (0,40)) $ \n ->
|
||||
$(testing [|countdownPrint n|]) . withNoInput $
|
||||
checkOutput (?== unlines (map show [n,n-1..0]))
|
||||
|
||||
ex7_isums =
|
||||
forAllBlind (listOf1 (choose (-10,10))) $ \nums ->
|
||||
$(testing [|isums (length nums)|]) . withInput (unlines $ map show nums) $
|
||||
check (?==unlines (map show $ scanl1 (+) nums)) (?==sum nums)
|
||||
|
||||
ex8_whenM_True =
|
||||
forAllBlind (choose (0::Int,10)) $ \i ->
|
||||
counterexample ("with i = " ++ show i) $
|
||||
$(testing' [|whenM (return True) (print i)|]) . withNoInput $
|
||||
checkOutput (?== show i++"\n")
|
||||
|
||||
ex8_whenM_False =
|
||||
forAllBlind (choose (0::Int,10)) $ \i ->
|
||||
counterexample ("with i = " ++ show i) $
|
||||
$(testing' [|whenM (return False) (print i)|]) . withNoInput $
|
||||
checkOutput (?== "")
|
||||
|
||||
ask :: IO Bool
|
||||
ask = do putStrLn "Y/N?"
|
||||
line <- getLine
|
||||
return $ line == "Y"
|
||||
|
||||
ex9_example =
|
||||
forAllBlind (choose (0,10)) $ \i ->
|
||||
$(testing' [|while ask (putStrLn "YAY!")|]) . withInput (unlines $ replicate i "Y" ++ ["N"]) $
|
||||
checkOutput (?== unlines (concat (replicate i ["Y/N?","YAY!"]) ++ ["Y/N?"]))
|
||||
|
||||
ex9_False =
|
||||
$(testing' [|while (return False) (putStrLn "IMPOSSIBLE")|]) . withNoInput $
|
||||
checkOutput (?== "")
|
||||
|
||||
ex10_debug =
|
||||
forAllBlind word $ \message ->
|
||||
forAllBlind word $ \output ->
|
||||
forAllBlind word $ \result ->
|
||||
counterexample ("debug "++show message++" (do putStrLn "++show output++"; return "++show result++")") $
|
||||
($ (debug message (putStrLn output >> return result))) . withNoInput $
|
||||
check (?== unlines [message,output,message]) (?== result)
|
||||
@@ -0,0 +1,195 @@
|
||||
module Set11b where
|
||||
|
||||
import Control.Monad
|
||||
import Data.List
|
||||
import Data.IORef
|
||||
import System.IO
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: Given an IORef String and a list of Strings, update the value
|
||||
-- in the IORef by appending to it all the strings in the list, in
|
||||
-- order.
|
||||
--
|
||||
-- Example:
|
||||
-- *Set11b> r <- newIORef "x"
|
||||
-- *Set11b> appendAll r ["foo","bar","quux"]
|
||||
-- *Set11b> readIORef r
|
||||
-- "xfoobarquux"
|
||||
|
||||
appendAll :: IORef String -> [String] -> IO ()
|
||||
appendAll = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: Given two IORefs, swap the values stored in them.
|
||||
--
|
||||
-- Example:
|
||||
-- *Set11b> x <- newIORef "x"
|
||||
-- *Set11b> y <- newIORef "y"
|
||||
-- *Set11b> swapIORefs x y
|
||||
-- *Set11b> readIORef x
|
||||
-- "y"
|
||||
-- *Set11b> readIORef y
|
||||
-- "x"
|
||||
|
||||
swapIORefs :: IORef a -> IORef a -> IO ()
|
||||
swapIORefs = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: sometimes one bumps into IO operations that return IO
|
||||
-- operations. For instance the type IO (IO Int) means an IO operation
|
||||
-- that returns an IO operation that returns an Int.
|
||||
--
|
||||
-- Implement the function doubleCall which takes an operation op and
|
||||
-- 1. runs op
|
||||
-- 2. runs the operation returned by op
|
||||
-- 3. returns the value returned by this operation
|
||||
--
|
||||
-- Examples:
|
||||
-- - doubleCall (return (return 3)) is the same as return 3
|
||||
--
|
||||
-- - let op :: IO (IO [String])
|
||||
-- op = do l <- readLn
|
||||
-- return $ replicateM l getLine
|
||||
-- in doubleCall op
|
||||
--
|
||||
-- works just like
|
||||
--
|
||||
-- do l <- readLn
|
||||
-- replicateM l getLine
|
||||
|
||||
doubleCall :: IO (IO a) -> IO a
|
||||
doubleCall op = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: implement the analogue of function composition (the (.)
|
||||
-- operator) for IO operations. That is, take an operation op1 of type
|
||||
-- a -> IO b
|
||||
-- an operation op2 of type
|
||||
-- c -> IO a
|
||||
-- and a value of type
|
||||
-- c
|
||||
-- and returns an operation op3 of type
|
||||
-- IO b
|
||||
--
|
||||
-- op3 should of course
|
||||
-- 1. take the value of type c and pass it to op2
|
||||
-- 2. take the resulting value (of type a) and pass it to op1
|
||||
-- 3. return the result (of type b)
|
||||
|
||||
compose :: (a -> IO b) -> (c -> IO a) -> c -> IO b
|
||||
compose op1 op2 c = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: Implement the operation mkCounter that produces the IO operations
|
||||
-- inc :: IO () and get :: IO Int. These operations should work like this:
|
||||
--
|
||||
-- get returns the number of times inc has been called
|
||||
--
|
||||
-- In other words, a simple stateful counter. Use an IORef to store the count.
|
||||
--
|
||||
-- Note: this is an IO operation that produces two IO operations. Thus
|
||||
-- the type of mkCounter is IO (IO (), IO Int).
|
||||
--
|
||||
-- This exercise is tricky. Feel free to leave it until later.
|
||||
--
|
||||
-- An example of how mkCounter works in GHCi:
|
||||
--
|
||||
-- *Set11b> (inc,get) <- mkCounter
|
||||
-- *Set11b> inc
|
||||
-- *Set11b> inc
|
||||
-- *Set11b> get
|
||||
-- 2
|
||||
-- *Set11b> inc
|
||||
-- *Set11b> inc
|
||||
-- *Set11b> get
|
||||
-- 4
|
||||
|
||||
mkCounter :: IO (IO (), IO Int)
|
||||
mkCounter = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: Reading lines from a file. The module System.IO defines
|
||||
-- operations for Handles, which represent open files that can be read
|
||||
-- from or written to. Here are some functions that might be useful:
|
||||
--
|
||||
-- * hGetLine :: Handle -> IO String
|
||||
-- Reads one line from the Handle. Will fail if the Handle is at the
|
||||
-- end of the file
|
||||
-- * hIsEOF :: Handle -> IO String
|
||||
-- Produces True if the Handle is at the end of the file.
|
||||
-- * hGetContents :: Handle -> IO String
|
||||
-- Reads content from Handle until the end of the file.
|
||||
--
|
||||
-- Implement the function hFetchLines which returns the contents of
|
||||
-- the given handle as a sequence of lines.
|
||||
--
|
||||
-- There are multiple ways to implement this function. You can either
|
||||
-- read the lines one by one, or read the whole file and then worry
|
||||
-- about splitting lines. Both approaches are fine, and you can even
|
||||
-- try out both!
|
||||
--
|
||||
-- Example:
|
||||
-- *Set11b> h <- openFile "Set11b.hs" ReadMode
|
||||
-- *Set11b> ls <- hFetchLines h
|
||||
-- *Set11b> take 3 ls
|
||||
-- ["module Set11b where","","import Control.Monad"]
|
||||
|
||||
hFetchLines :: Handle -> IO [String]
|
||||
hFetchLines = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: Given a Handle and a list of line indexes, produce the lines
|
||||
-- at those indexes from the file.
|
||||
--
|
||||
-- Line indexing starts from 1.
|
||||
--
|
||||
-- Here too, there are multiple ways to implement this. You can try
|
||||
-- using hFetchLines, or writing out a loop that gets lines from the
|
||||
-- handle.
|
||||
|
||||
hSelectLines :: Handle -> [Int] -> IO [String]
|
||||
hSelectLines h nums = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: In this exercise we see how a program can be split into a
|
||||
-- pure part that does all of the work, and a simple IO wrapper that
|
||||
-- drives the pure logic.
|
||||
--
|
||||
-- Implement the function interact' that takes a pure function f of
|
||||
-- type
|
||||
-- (String, st) -> (Bool, String, st)
|
||||
-- and a starting state of type st and returns an IO operation of type
|
||||
-- IO st
|
||||
--
|
||||
-- interact' should read a line from the user, feed the line and the
|
||||
-- current state to f. f then returns a boolean, a string to print and
|
||||
-- a new state. The string is printed, and if the boolean is True, we
|
||||
-- continue running with the new state. If the boolean is False, the
|
||||
-- execution has ended and the state should be returned.
|
||||
--
|
||||
-- Example:
|
||||
-- *Set11b> interact' counter 1
|
||||
-- print
|
||||
-- 1
|
||||
-- inc
|
||||
-- done
|
||||
-- inc
|
||||
-- done
|
||||
-- print
|
||||
-- 3
|
||||
-- quit
|
||||
-- bye bye
|
||||
-- 3
|
||||
-- *Set11b>
|
||||
|
||||
-- This is used in the example above. Don't change it!
|
||||
counter :: (String,Integer) -> (Bool,String,Integer)
|
||||
counter ("inc",n) = (True,"done",n+1)
|
||||
counter ("print",n) = (True,show n,n)
|
||||
counter ("quit",n) = (False,"bye bye",n)
|
||||
|
||||
interact' :: ((String,st) -> (Bool,String,st)) -> st -> IO st
|
||||
interact' f state = todo
|
||||
@@ -0,0 +1,145 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
||||
|
||||
module Set11aTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Control.Monad
|
||||
import Data.List
|
||||
import Data.IORef
|
||||
import GHC.IO.Handle
|
||||
import System.Directory
|
||||
import System.IO
|
||||
|
||||
import Test.QuickCheck
|
||||
import Test.QuickCheck.Monadic
|
||||
|
||||
import Set11b hiding (counter)
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"appendAll",[ex1])
|
||||
,(2,"swapIORefs",[ex2])
|
||||
,(3,"doubleCall",[ex3_doubleCall, ex3_doubleCall_2])
|
||||
,(4,"composeIO",[ex4_composeIO_1, ex4_composeIO_2])
|
||||
,(5,"mkCounter",[ex5_mkCounter])
|
||||
,(6,"hFetchLines",[ex6])
|
||||
,(7,"hSelectLines",[ex7_hSelectLines])
|
||||
,(8,"interact'",[ex8_interact_terminates, ex8_interact_example, ex8_interact_loop])]
|
||||
|
||||
-- -- -- -- --
|
||||
|
||||
word = listOf1 (choose ('a','z'))
|
||||
|
||||
ex1 = forAllBlind word $ \init ->
|
||||
forAllBlind (listOf word) $ \ws ->
|
||||
counterexample ("appendAll ref " ++ show ws) $
|
||||
counterexample (" Initial value of ref was: " ++ show init) $
|
||||
monadicIO $ do ref <- run $ newIORef init
|
||||
run $ appendAll ref ws
|
||||
out <- run $ readIORef ref
|
||||
stop_ $ counterexample " Final value in ref" $ out ?== concat (init:ws)
|
||||
|
||||
ex2 = forAllBlind word $ \w1 ->
|
||||
forAllBlind word $ \w2 ->
|
||||
counterexample "swapIORefs r1 r2" $
|
||||
counterexample (" Initial value of r1: "++show w1) $
|
||||
counterexample (" Initial value of r2: "++show w2) $
|
||||
monadicIO $ do r1 <- run $ newIORef w1
|
||||
r2 <- run $ newIORef w2
|
||||
run $ swapIORefs r1 r2
|
||||
o1 <- run $ readIORef r1
|
||||
o2 <- run $ readIORef r2
|
||||
stop_ $ conjoin [counterexample " readIORef r1" $ o1 ?== w2
|
||||
,counterexample " readIORef r2" $ o2 ?== w1]
|
||||
|
||||
ex3_doubleCall =
|
||||
forAllBlind (choose (0,20::Int)) $ \i ->
|
||||
counterexample ("doubleCall (return (return "++show i++"))") $
|
||||
($ doubleCall (return (return i))) . withNoInput $
|
||||
check (?=="") (?==i)
|
||||
|
||||
ex3_doubleCall_2 =
|
||||
forAllBlind word $ \w1 ->
|
||||
forAllBlind word $ \w2 ->
|
||||
counterexample ("doubleCall (do putStrLn "++show w1++"; return (putStrLn "++show w2++"))") $
|
||||
($ doubleCall (do putStrLn w1; return (putStrLn w2))) . withNoInput $
|
||||
check (?==(w1++"\n"++w2++"\n")) (?==())
|
||||
|
||||
ex4_composeIO_1 =
|
||||
forAllBlind word $ \w ->
|
||||
forAllBlind word $ \v ->
|
||||
counterexample ("compose putStrLn (\\x -> do putStrLn x; getLine) " ++ show w) $
|
||||
($ compose putStrLn (\x -> do putStrLn x; getLine) w) . withInput (v++"\n") $
|
||||
checkOutput (?==w++"\n"++v++"\n")
|
||||
|
||||
ex4_composeIO_2 =
|
||||
forAll_ $ \(i::Int) ->
|
||||
counterexample ("compose (\\x -> return (x*2)) (\\y -> return (y+1)) " ++ show i) $
|
||||
($ compose (return . (*2)) (return . (+1)) i) . withNoInput $
|
||||
checkResult (?== (i+1)*2)
|
||||
|
||||
|
||||
ex5_mkCounter = forAllBlind (choose (0,20)) $ \n ->
|
||||
counterexample "(inc,get) <- mkCounter" $
|
||||
counterexample (" Called inc "++show n++" times, then called get") $
|
||||
monadicIO $ do m <- run $ do (i,g) <- mkCounter
|
||||
replicateM_ n i
|
||||
g
|
||||
stop_ $ m ?== n
|
||||
|
||||
ex6 = forAllBlind (listOf1 word) $ \lines ->
|
||||
counterexample ("Contents of handle h:\n"++unlines lines) $
|
||||
counterexample "hFetchLines h" $
|
||||
monadicIO $ do
|
||||
dir <- run $ getTemporaryDirectory
|
||||
(_,h) <- run $ openTempFile dir "hSelectLines.in"
|
||||
run $ hPutStr h $ unlines lines
|
||||
run $ hSeek h AbsoluteSeek 0
|
||||
outs <- run $ hFetchLines h
|
||||
stop_ $ outs ?== lines
|
||||
|
||||
ex7_hSelectLines =
|
||||
forAllBlind (listOf1 word) $ \lines ->
|
||||
forAllBlind (fmap (nub.sort) . listOf1 $ choose (1,length lines)) $ \inds ->
|
||||
counterexample ("Contents of handle h:\n"++unlines lines) $
|
||||
counterexample ("hSelectLines h "++show inds) $
|
||||
monadicIO $ do
|
||||
dir <- run $ getTemporaryDirectory
|
||||
(path,h) <- run $ openTempFile dir "hSelectLines.in"
|
||||
run $ hPutStr h $ unlines lines
|
||||
run $ hSeek h AbsoluteSeek 0
|
||||
outs <- run $ hSelectLines h inds
|
||||
stop_ $ counterexample (" was: "++show outs) $
|
||||
conjoin [counterexample "Length of result" $ length outs ?== length inds
|
||||
,conjoin [counterexample ("result!!"++show i) $ outs!!i ?== lines!!((inds!!i)-1)
|
||||
| i <- [0..length inds-1]]]
|
||||
|
||||
counter :: (String,Integer) -> (Bool,String,Integer)
|
||||
counter ("inc",n) = (True,"done",n+1)
|
||||
counter ("print",n) = (True,show n,n)
|
||||
counter ("quit",n) = (False,"bye bye",n)
|
||||
|
||||
ex8_interact_terminates =
|
||||
forAllBlind word $ \w1 ->
|
||||
forAllBlind word $ \w2 ->
|
||||
forAllBlind (choose (0::Int,100)) $ \state ->
|
||||
counterexample ("let f (input,state) = (False,input,state) in interact' f "++show state) $
|
||||
($ let f (input,state) = (False,input,state) in interact' f state) . withInput (unlines [w1,w2]) $
|
||||
check (?==(w1++"\n")) (?==state)
|
||||
|
||||
ex8_interact_example =
|
||||
$(testing' [|interact' counter 1|]) . withInput (unlines ["print","inc","inc","print","quit"]) $
|
||||
check (?==unlines ["1","done","done","3","bye bye"]) (?==3)
|
||||
|
||||
ex8_interact_loop =
|
||||
forAllBlind (choose (0::Int,100)) $ \state ->
|
||||
forAllBlind (choose (0::Int,5)) $ \steps ->
|
||||
forAllBlind word $ \w ->
|
||||
forAllBlind word $ \end ->
|
||||
let input = unlines $ replicate steps w ++ [end]
|
||||
output = unlines $ map show [state..state+steps]
|
||||
in counterexample ("let f (input,state) = (input=="++show w++",show state,state+1) in interact' f "++show state) $
|
||||
($ let f (input,state) = (input==w,show state,state+1) in interact' f state) . withInput input $
|
||||
check (?==output) (?==state+steps+1)
|
||||
@@ -0,0 +1,212 @@
|
||||
module Set12 where
|
||||
|
||||
import Data.Functor
|
||||
import Data.Foldable
|
||||
import Data.List
|
||||
import Data.Monoid
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: Implement the function incrementAll that takes a functor
|
||||
-- value containing numbers and increments each number inside by one.
|
||||
--
|
||||
-- Examples:
|
||||
-- incrementAll [1,2,3] ==> [2,3,4]
|
||||
-- incrementAll (Just 3.0) ==> Just 4.0
|
||||
|
||||
incrementAll :: (Functor f, Num n) => f n -> f n
|
||||
incrementAll x = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: Sometimes one wants to fmap multiple levels deep. Implement
|
||||
-- the functions fmap2 and fmap3 that map over nested functors.
|
||||
--
|
||||
-- Examples:
|
||||
-- fmap2 on [[Int]]:
|
||||
-- fmap2 negate [[1,2],[3]]
|
||||
-- ==> [[-1,-2],[-3]]
|
||||
-- fmap2 on [Maybe String]:
|
||||
-- fmap2 head [Just "abcd",Nothing,Just "efgh"]
|
||||
-- ==> [Just 'a',Nothing,Just 'e']
|
||||
-- fmap3 on [[[Int]]]:
|
||||
-- fmap3 negate [[[1,2],[3]],[[4],[5,6]]]
|
||||
-- ==> [[[-1,-2],[-3]],[[-4],[-5,-6]]]
|
||||
-- fmap3 on Maybe [Maybe Bool]
|
||||
-- fmap3 not (Just [Just False, Nothing])
|
||||
-- ==> Just [Just True,Nothing]
|
||||
|
||||
fmap2 :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
|
||||
fmap2 = todo
|
||||
|
||||
fmap3 :: (Functor f, Functor g, Functor h) => (a -> b) -> f (g (h a)) -> f (g (h b))
|
||||
fmap3 = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: below you'll find a type Result that works a bit like Maybe,
|
||||
-- but there are two different types of "Nothings": one with and one
|
||||
-- without an error description.
|
||||
--
|
||||
-- Implement the instance Functor Result
|
||||
|
||||
data Result a = MkResult a | NoResult | Failure String
|
||||
deriving Show
|
||||
|
||||
instance Functor Result where
|
||||
fmap f result = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: Here's a reimplementation of the Haskell list type. You might
|
||||
-- remember it from Set6. Implement the instance Functor List.
|
||||
--
|
||||
-- Example:
|
||||
-- fmap (+2) (LNode 0 (LNode 1 (LNode 2 Empty)))
|
||||
-- ==> LNode 2 (LNode 3 (LNode 4 Empty))
|
||||
|
||||
data List a = Empty | LNode a (List a)
|
||||
deriving Show
|
||||
|
||||
instance Functor List where
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: Here's another list type. This type every node contains two
|
||||
-- values, so it's a type for a list of pairs. Implement the instance
|
||||
-- Functor TwoList.
|
||||
--
|
||||
-- Example:
|
||||
-- fmap (+2) (TwoNode 0 1 (TwoNode 2 3 TwoEmpty))
|
||||
-- ==> TwoNode 2 3 (TwoNode 4 5 TwoEmpty)
|
||||
|
||||
data TwoList a = TwoEmpty | TwoNode a a (TwoList a)
|
||||
deriving Show
|
||||
|
||||
instance Functor TwoList where
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: Count all occurrences of a given element inside a Foldable.
|
||||
--
|
||||
-- Hint: you might find some useful functions from Data.Foldable.
|
||||
-- Check the docs! Or then you can just implement count directly.
|
||||
--
|
||||
-- Examples:
|
||||
-- count True [True,False,True] ==> 2
|
||||
-- count 'c' (Just 'c') ==> 1
|
||||
|
||||
count :: (Eq a, Foldable f) => a -> f a -> Int
|
||||
count = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: Return all elements that are in two Foldables, as a list.
|
||||
--
|
||||
-- Examples:
|
||||
-- inBoth "abcd" "fobar" ==> "ab"
|
||||
-- inBoth [1,2] (Just 2) ==> [2]
|
||||
-- inBoth Nothing [3] ==> []
|
||||
|
||||
inBoth :: (Foldable f, Foldable g, Eq a) => f a -> g a -> [a]
|
||||
inBoth = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: Implement the instance Foldable List.
|
||||
--
|
||||
-- Remember what the minimal complete definitions for Foldable were:
|
||||
-- you should only need to implement one function.
|
||||
--
|
||||
-- After defining the instance, you'll be able to compute:
|
||||
-- sum (LNode 1 (LNode 2 (LNode 3 Empty))) ==> 6
|
||||
-- length (LNode 1 (LNode 2 (LNode 3 Empty))) ==> 3
|
||||
|
||||
instance Foldable List where
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 9: Implement the instance Foldable TwoList.
|
||||
--
|
||||
-- After defining the instance, you'll be able to compute:
|
||||
-- sum (TwoNode 0 1 (TwoNode 2 3 TwoEmpty)) ==> 6
|
||||
-- length (TwoNode 0 1 (TwoNode 2 3 TwoEmpty)) ==> 4
|
||||
|
||||
instance Foldable TwoList where
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 10: (Tricky!) Fun a is a type that wraps a function Int -> a.
|
||||
-- Implement a Functor instance for it.
|
||||
--
|
||||
-- Figuring out what the Functor instance should do is most of the
|
||||
-- puzzle.
|
||||
|
||||
data Fun a = Fun (Int -> a)
|
||||
|
||||
runFun :: Fun a -> Int -> a
|
||||
runFun (Fun f) x = f x
|
||||
|
||||
instance Functor Fun where
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 11: (Tricky!) You'll find the binary tree type from Set 5b
|
||||
-- below. We'll implement a `Foldable` instance for it!
|
||||
--
|
||||
-- Implementing `foldr` directly for the Tree type is complicated.
|
||||
-- However, there is another method in Foldable we can define instead:
|
||||
--
|
||||
-- foldMap :: Monoid m => (a -> m) -> Tree a -> m
|
||||
--
|
||||
-- There's a default implementation for `foldr` in Foldable that uses
|
||||
-- `foldMap`.
|
||||
--
|
||||
-- Instead of implementing `foldMap` directly, we can build it with
|
||||
-- these functions:
|
||||
--
|
||||
-- fmap :: (a -> m) -> Tree a -> Tree m
|
||||
-- sumTree :: Monoid m => Tree m -> m
|
||||
--
|
||||
-- So your task is to define a `Functor` instance and the `sumTree`
|
||||
-- function.
|
||||
--
|
||||
-- Examples:
|
||||
-- using the [] Monoid with the (++) operation:
|
||||
-- sumTree Leaf :: [a]
|
||||
-- ==> []
|
||||
-- sumTree (Node [3,4,5] (Node [1,2] Leaf Leaf) (Node [6] Leaf Leaf))
|
||||
-- ==> [1,2,3,4,5,6]
|
||||
-- using the Sum Monoid
|
||||
-- sumTree Leaf :: Sum Int
|
||||
-- ==> Sum 0
|
||||
-- sumTree (Node (Sum 3) (Node (Sum 2) Leaf Leaf) (Node (Sum 1) Leaf Leaf))
|
||||
-- ==> Sum 6
|
||||
--
|
||||
-- Once you're done, foldr should operate like this:
|
||||
-- foldr (:) [] Leaf ==> []
|
||||
-- foldr (:) [] (Node 2 (Node 1 Leaf Leaf) (Node 3 Leaf Leaf)) ==> [1,2,3]
|
||||
--
|
||||
-- foldr (:) [] (Node 4 (Node 2 (Node 1 Leaf Leaf)
|
||||
-- (Node 3 Leaf Leaf))
|
||||
-- (Node 5 Leaf
|
||||
-- (Node 6 Leaf Leaf)))
|
||||
-- ==> [1,2,3,4,5,6]
|
||||
--
|
||||
-- The last example more visually:
|
||||
--
|
||||
-- .4.
|
||||
-- / \
|
||||
-- 2 5 ====> 1 2 3 4 5 6
|
||||
-- / \ \
|
||||
-- 1 3 6
|
||||
|
||||
data Tree a = Leaf | Node a (Tree a) (Tree a)
|
||||
deriving Show
|
||||
|
||||
instance Functor Tree where
|
||||
fmap = todo
|
||||
|
||||
sumTree :: Monoid m => Tree m -> m
|
||||
sumTree = todo
|
||||
|
||||
instance Foldable Tree where
|
||||
foldMap f t = sumTree (fmap f t)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Bonus! If you enjoyed the two last exercises (not everybody will),
|
||||
-- you'll like the `loeb` function:
|
||||
--
|
||||
-- https://github.com/quchen/articles/blob/master/loeb-moeb.md
|
||||
@@ -0,0 +1,226 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving #-}
|
||||
|
||||
module Set12Test where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
import Data.List
|
||||
import Data.Monoid
|
||||
|
||||
import Test.QuickCheck hiding (Result,Fun,Failure)
|
||||
|
||||
import Set12
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"incrementAll",[ex1_list, ex1_just, ex1_nothing])
|
||||
,(2,"fmap23",[ex2_fmap2_examples, ex2_fmap3_examples])
|
||||
,(3,"Functor Result",[ex3_num, ex3_empties])
|
||||
,(4,"Functor List",[ex4_num, ex4_bool])
|
||||
,(5,"Functor TwoList",[ex5_num, ex5_bool])
|
||||
,(6,"count",[ex6_list, ex6_maybe])
|
||||
,(7,"inBoth",[ex7_list, ex7_maybe])
|
||||
,(8,"Foldable List",[ex8_bool, ex8_num])
|
||||
,(9,"Foldable TwoList",[ex9_bool, ex9_num])
|
||||
,(10,"Fun",[ex10_1, ex10_2])
|
||||
,(11,"Foldable Tree",[ex11_fmap_even, ex11_fmap_plus, ex11_sumTree_int, ex11_sumTree_list])]
|
||||
|
||||
|
||||
-- -- -- -- -- --
|
||||
|
||||
ex1_list =
|
||||
forAll_ $ \(xs::[Int]) ->
|
||||
$(testing [|incrementAll xs|]) (?== map (+1) xs)
|
||||
|
||||
ex1_just =
|
||||
forAll_ $ \(i::Int) ->
|
||||
$(testing [|incrementAll (Just i)|]) (?== Just (i+1))
|
||||
|
||||
ex1_nothing = $(testing [|incrementAll (Nothing::Maybe Int)|]) (?== Nothing)
|
||||
|
||||
ex2_fmap2_examples =
|
||||
conjoin [$(testing' [|fmap2 negate [[1,2],[3]]|]) (?==[[-1,-2],[-3]])
|
||||
,$(testing' [|fmap2 head [Just "abcd",Nothing,Just "efgh"]|]) (?==[Just 'a',Nothing,Just 'e'])]
|
||||
|
||||
ex2_fmap3_examples =
|
||||
conjoin [$(testing' [|fmap3 negate [[[1,2],[3]],[[4],[5,6]]]|]) (?==[[[-1,-2],[-3]],[[-4],[-5,-6]]])
|
||||
,$(testing' [|fmap3 not (Just [Just False, Nothing])|]) (?==Just [Just True,Nothing])]
|
||||
|
||||
deriving instance Eq a => Eq (Result a)
|
||||
|
||||
ex3_num =
|
||||
forAll_ $ \(k::Int) ->
|
||||
counterexample ("fmap (+1) (MkResult "++show k++")") $
|
||||
fmap (+(1::Int)) (MkResult k) ?== MkResult (k+1)
|
||||
|
||||
ex3_empties =
|
||||
$(testing' [|fmap not NoResult|]) (?== NoResult)
|
||||
.&.
|
||||
$(testing' [|fmap not (Failure "oh no.")|]) (?== Failure "oh no.")
|
||||
.&.
|
||||
$(testing' [|fmap not (Failure "Mein Gott!")|]) (?== Failure "Mein Gott!")
|
||||
|
||||
deriving instance Eq a => Eq (List a)
|
||||
|
||||
toList = foldr LNode Empty
|
||||
|
||||
ex4_num =
|
||||
forAll_ $ \(xs::[Int]) ->
|
||||
let l = toList xs
|
||||
in counterexample ("fmap (+1) ("++show l++")") $
|
||||
fmap (+1) l ?== toList (map (+1) xs)
|
||||
|
||||
ex4_bool =
|
||||
forAll_ $ \(bs::[Bool]) ->
|
||||
let l = toList bs in
|
||||
counterexample ("fmap not ("++show l++")") $
|
||||
fmap not l ?== toList (map not bs)
|
||||
|
||||
deriving instance Eq a => Eq (TwoList a)
|
||||
|
||||
toTwoList :: [a] -> TwoList a
|
||||
toTwoList [] = TwoEmpty
|
||||
toTwoList (x:y:xs) = TwoNode x y (toTwoList xs)
|
||||
|
||||
ex5_num =
|
||||
forAll_ $ \(xs::[Int]) ->
|
||||
even (length xs) ==>
|
||||
let l = toTwoList xs
|
||||
in counterexample ("fmap (+1) ("++show l++")") $
|
||||
fmap (+1) l ?== toTwoList (map (+1) xs)
|
||||
|
||||
ex5_bool =
|
||||
forAll_ $ \(bs::[Bool]) ->
|
||||
even (length bs) ==>
|
||||
let l = toTwoList bs in
|
||||
counterexample ("fmap not ("++show l++")") $
|
||||
fmap not l ?== toTwoList (map not bs)
|
||||
|
||||
ex6_list =
|
||||
forAll_ $ \(bs::[Bool]) ->
|
||||
forAll_ $ \b ->
|
||||
$(testing [|count b bs|]) (?==length (filter (==b) bs))
|
||||
|
||||
ex6_maybe =
|
||||
forAllBlind (choose ('a','z')) $ \c ->
|
||||
forAllBlind (choose ('a','z') `suchThat` (/=c)) $ \d ->
|
||||
conjoin [$(testing [|count c n|]) (?==0)
|
||||
,$(testing [|count c (Just c)|]) (?==1)
|
||||
,$(testing [|count d (Just c)|]) (?==0)]
|
||||
where n = Nothing :: Maybe Char
|
||||
|
||||
ex7_list =
|
||||
forAll_ $ \(is::[Int]) ->
|
||||
forAll_ $ \(js::[Int]) ->
|
||||
$(testing [|inBoth (nub is) (nub js)|]) (?==intersect (nub is) (nub js))
|
||||
|
||||
ex7_maybe =
|
||||
forAll_ $ \(i::Int) ->
|
||||
forAll_ $ \j ->
|
||||
conjoin [$(testing [|inBoth (Just i) (Just j)|]) (?==if i==j then [i] else [])
|
||||
,$(testing [|inBoth (Just i) (Just i)|]) (?==[i])
|
||||
,$(testing [|inBoth (Just i) n|]) (?==[])]
|
||||
where n = Nothing :: Maybe Int
|
||||
|
||||
ex8_bool =
|
||||
forAll_ $ \(xs::[Bool]) ->
|
||||
let l = toList xs
|
||||
in counterexample ("foldr (:) [] ("++show l++")") $
|
||||
foldr (:) [] l ?== xs
|
||||
|
||||
ex8_num =
|
||||
forAll_ $ \(NonEmpty (is::[Int])) ->
|
||||
let l = toList is
|
||||
in $(testing [|minimum l|]) (?==minimum is)
|
||||
|
||||
ex9_bool =
|
||||
forAll_ $ \(xs::[Bool]) ->
|
||||
even (length xs) ==>
|
||||
let l = toTwoList xs
|
||||
in counterexample ("foldr (:) [] ("++show l++")") $
|
||||
foldr (:) [] l ?== xs
|
||||
|
||||
ex9_num =
|
||||
forAll_ $ \(NonEmpty (is::[Int])) ->
|
||||
even (length is) ==>
|
||||
let l = toTwoList is
|
||||
in $(testing [|minimum l|]) (?==minimum is)
|
||||
|
||||
ex10_1 =
|
||||
forAll_ $ \(i::Int) ->
|
||||
counterexample ("runFun (fmap not (Fun even)) "++show i) $
|
||||
runFun (fmap not (Fun even)) i ?== odd i
|
||||
|
||||
ex10_2 =
|
||||
forAll_ $ \(i::Int) ->
|
||||
counterexample ("runFun (fmap (*2) (Fun (\\i -> i))) "++show i) $
|
||||
runFun (fmap (*2) (Fun id)) i ?== 2*i
|
||||
|
||||
deriving instance Eq a => Eq (Tree a)
|
||||
|
||||
ex11_fmap_even = conjoin
|
||||
[$(testing' [|fmap even Leaf|]) (?==Leaf)
|
||||
,$(testing' [|fmap even (Node 3 Leaf Leaf)|]) (?==Node False Leaf Leaf)
|
||||
,$(testing' [|fmap even (Node 2 Leaf Leaf)|]) (?==Node True Leaf Leaf)
|
||||
,$(testing' [|fmap even (Node 2 (Node 3 Leaf Leaf) Leaf)|]) (?==Node True (Node False Leaf Leaf) Leaf)
|
||||
,$(testing' [|fmap even (Node 2 (Node 3 Leaf Leaf) (Node 4 Leaf Leaf))|]) (?==Node True (Node False Leaf Leaf) (Node True Leaf Leaf))]
|
||||
|
||||
trees :: Int -> Gen (Tree Int, Tree Int)
|
||||
trees 0 = return (Leaf,Leaf)
|
||||
trees n = do
|
||||
i <- choose (0,10)
|
||||
let j = i+2
|
||||
nleft <- choose (0,n-1)
|
||||
nright <- choose (0,n-1)
|
||||
(iLeft,jLeft) <- trees nleft
|
||||
(iRight,jRight) <- trees nright
|
||||
return (Node i iLeft iRight, Node j jLeft jRight)
|
||||
|
||||
m_fmap n = forAllBlind (trees n) $ \(from,to) ->
|
||||
counterexample ("fmap (+2) ("++show from++")") $
|
||||
fmap (+2) from ?== to
|
||||
|
||||
ex11_fmap_plus = conjoin [m_fmap 0
|
||||
,m_fmap 1
|
||||
,m_fmap 2
|
||||
,m_fmap 3
|
||||
,m_fmap 4]
|
||||
|
||||
treeAndSum 0 = return (0,Leaf)
|
||||
treeAndSum n = do
|
||||
(lsum,l) <- treeAndSum (n-1)
|
||||
(rsum,r) <- treeAndSum (n-1)
|
||||
val <- choose (0,10::Int)
|
||||
return (val+rsum+lsum, Node (Sum val) l r)
|
||||
|
||||
m_treeSum_Sum n = forAllBlind (treeAndSum n) $ \(s,t) ->
|
||||
$(testing [|sumTree t|]) (?==Sum s)
|
||||
|
||||
ex11_sumTree_int = conjoin [m_treeSum_Sum 0
|
||||
,m_treeSum_Sum 1
|
||||
,m_treeSum_Sum 2
|
||||
,m_treeSum_Sum 3]
|
||||
|
||||
split :: [a] -> Gen ([a],[a])
|
||||
split xs = do
|
||||
i <- choose (0,length xs-1)
|
||||
return $ (take i xs, drop i xs)
|
||||
|
||||
listToTree 0 xs = return (Node xs Leaf Leaf)
|
||||
listToTree n xs = frequency
|
||||
[(1,return (Node xs Leaf Leaf))
|
||||
,(4,do
|
||||
(left,rest) <- split xs
|
||||
(me,right) <- split rest
|
||||
l <- listToTree (n-1) left
|
||||
r <- listToTree (n-1) right
|
||||
return $ Node me l r)]
|
||||
|
||||
m_sumTree_list n = forAll_ $ \(is::[Int]) ->
|
||||
forAllBlind (listToTree n is) $ \tree ->
|
||||
$(testing [|sumTree tree|]) (?==is)
|
||||
|
||||
ex11_sumTree_list = conjoin [m_sumTree_list 0
|
||||
,m_sumTree_list 1
|
||||
,m_sumTree_list 2
|
||||
,m_sumTree_list 3]
|
||||
@@ -0,0 +1,267 @@
|
||||
module Set13a where
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
import Control.Monad
|
||||
import Control.Monad.State
|
||||
import Data.Char
|
||||
import Data.List
|
||||
import qualified Data.Map as Map
|
||||
|
||||
import Examples.Bank
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: Your task is to help implement the function readName that
|
||||
-- given a string like "Forename Surname" produces the pair
|
||||
-- ("Forname", "Surname"). readName should fail (return Nothing) in
|
||||
-- the following cases:
|
||||
--
|
||||
-- 1. the input string doesn't contain a space
|
||||
-- 2. one of the names contains numbers
|
||||
-- 3. one of the names doesn't start with a capital letter
|
||||
--
|
||||
-- The function readNames has already been implemented using the ?>
|
||||
-- operator from the course material. You need to define the helper
|
||||
-- functions split, checkNumber and checkCapitals so that readNames
|
||||
-- works correctly.
|
||||
|
||||
(?>) :: Maybe a -> (a -> Maybe b) -> Maybe b
|
||||
Nothing ?> _ = Nothing -- In case of failure, propagate failure
|
||||
Just x ?> f = f x -- In case of sucess, run the next computation
|
||||
|
||||
-- DO NOT touch this definition!
|
||||
readNames :: String -> Maybe (String,String)
|
||||
readNames s =
|
||||
split s
|
||||
?>
|
||||
checkNumber
|
||||
?>
|
||||
checkCapitals
|
||||
|
||||
-- split should split a string into two words. If the input doesn't
|
||||
-- contain a space, Nothing should be returned
|
||||
--
|
||||
-- (NB! There are obviously other corner cases like the inputs " " and
|
||||
-- "a b c", but you don't need to worry about those here)
|
||||
split :: String -> Maybe (String,String)
|
||||
split = todo
|
||||
|
||||
-- checkNumber should take a pair of two strings and return them
|
||||
-- unchanged if they don't contain numbers. Otherwise Nothing is
|
||||
-- returned.
|
||||
checkNumber :: (String, String) -> Maybe (String, String)
|
||||
checkNumber = todo
|
||||
|
||||
-- checkCapitals should take a pair of two strings and return them
|
||||
-- unchanged if both start with a capital letter. Otherwise Nothing is
|
||||
-- returned.
|
||||
checkCapitals :: (String, String) -> Maybe (String, String)
|
||||
checkCapitals (for,sur) = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: Given a list of players and their scores (as [(String,Int)]),
|
||||
-- and two player names, return the name of the player who has more
|
||||
-- points (wrapped in a Just), or Nothing if either of the players
|
||||
-- doesn't exist.
|
||||
--
|
||||
-- In the case of a draw, prefer the first player.
|
||||
--
|
||||
-- Use the function
|
||||
-- lookup :: Eq a => a -> [(a, b)] -> Maybe b
|
||||
-- and either do-notation (easier) or ?> chaining (trickier!)
|
||||
--
|
||||
-- Examples:
|
||||
-- winner [("ender",13),("orson",6),("scott",5)] "ender" "orson"
|
||||
-- ==> Just "ender"
|
||||
-- winner [("ender",13),("orson",6),("scott",5)] "orson" "ender"
|
||||
-- ==> Just "ender"
|
||||
-- winner [("ender",13),("orson",6),("scott",5)] "orson" "scott"
|
||||
-- ==> Just "orson"
|
||||
-- winner [("ender",13),("orson",6),("scott",5)] "orson" "ridley"
|
||||
-- ==> Nothing
|
||||
-- winner [("a",1),("b",1)] "a" "b"
|
||||
-- ==> Just "a"
|
||||
|
||||
winner :: [(String,Int)] -> String -> String -> Maybe String
|
||||
winner scores player1 player2 = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: given a list of indices and a list of values, return the sum
|
||||
-- of the values in the given indices. You should fail if any of the
|
||||
-- indices is too large or too small.
|
||||
--
|
||||
-- Use the Maybe monad, i.e. the >>= operator or do-notation.
|
||||
--
|
||||
-- Hint! implement a function safeIndex :: [a] -> Int -> Maybe a
|
||||
--
|
||||
-- Examples:
|
||||
-- selectSum [0..10] [4,6,9]
|
||||
-- Just 19
|
||||
-- selectSum [0..10] [4,6,9,20]
|
||||
-- Nothing
|
||||
|
||||
selectSum :: Num a => [a] -> [Int] -> Maybe a
|
||||
selectSum xs is = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: Here is the Logger monad from the course material. Implement
|
||||
-- the operation countAndLog which produces the number of elements
|
||||
-- from the given list that fulfil the given predicate. Additionally,
|
||||
-- countAndLog should log all elements that fulfil the predicate
|
||||
-- (using show to turn them into strings).
|
||||
--
|
||||
-- Examples:
|
||||
-- countAndLog even [0,1,2,3,4,5]
|
||||
-- ==> Logger ["0","2","4"] 3
|
||||
|
||||
data Logger a = Logger [String] a
|
||||
deriving (Show, Eq)
|
||||
|
||||
msg :: String -> Logger ()
|
||||
msg s = Logger [s] ()
|
||||
|
||||
instance Functor Logger where
|
||||
fmap f (Logger l a) = Logger l (f a)
|
||||
|
||||
instance Monad Logger where
|
||||
return x = Logger [] x
|
||||
Logger la a >>= f = Logger (la++lb) b
|
||||
where Logger lb b = f a
|
||||
|
||||
-- This is an Applicative instance that works for any monad, you
|
||||
-- can just ignore it for now. We'll get back to Applicative later.
|
||||
instance Applicative Logger where
|
||||
pure = return
|
||||
(<*>) = ap
|
||||
|
||||
countAndLog :: Show a => (a -> Bool) -> [a] -> Logger Int
|
||||
countAndLog = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: You can find the Bank and BankOp code from the course
|
||||
-- material in the module Examples.Bank (file
|
||||
-- exercises/Examples/Bank.hs), which has been imported into this
|
||||
-- namespace.
|
||||
--
|
||||
-- Implement a BankOp balance that produces the balance of the given
|
||||
-- account. Produce 0 if the account does not exist. The balance
|
||||
-- operation shouldn't change the state of the Bank. The functions
|
||||
-- from Data.Map are available under the prefix Map.
|
||||
|
||||
exampleBank :: Bank
|
||||
exampleBank = (Bank (Map.fromList [("harry",10),("cedric",7),("ginny",1)]))
|
||||
|
||||
balance :: String -> BankOp Int
|
||||
balance accountName = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: Using the operations balance, withdrawOp and depositOp, and
|
||||
-- chaining (+>), implement the BankOp rob, which transfers all the
|
||||
-- money from one account to another account.
|
||||
--
|
||||
-- Examples:
|
||||
-- runBankOp (balance "harry") exampleBank
|
||||
-- ==> (10,Bank (fromList [("cedric",7),("ginny",1),("harry",10)]))
|
||||
-- runBankOp (balance "sean") exampleBank
|
||||
-- ==> (0,Bank (fromList [("cedric",7),("ginny",1),("harry",10)]))
|
||||
-- runBankOp (rob "cedric" "ginny") exampleBank
|
||||
-- ==> ((),Bank (fromList [("cedric",0),("ginny",8),("harry",10)]))
|
||||
-- runBankOp (rob "sean" "ginny") exampleBank
|
||||
-- ==> ((),Bank (fromList [("cedric",7),("ginny",1),("harry",10)]))
|
||||
|
||||
rob :: String -> String -> BankOp ()
|
||||
rob from to = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: using the State monad, write the operation update that first
|
||||
-- multiplies the state by 2 and then adds one to it. The state has
|
||||
-- type Int.
|
||||
--
|
||||
-- Example:
|
||||
-- runState update 3
|
||||
-- ==> ((),7)
|
||||
|
||||
update :: State Int ()
|
||||
update = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: Checking that parentheses are balanced with the State monad.
|
||||
--
|
||||
-- Do this by implementing the function paren, which updates the state
|
||||
-- based on a single character. A '(' should increase the state, and a
|
||||
-- ')' should decrease the state. If the state goes to -1 (there are
|
||||
-- more closing than opening parentheses), it should stay there to
|
||||
-- indicate that a parenthesis error was encountered.
|
||||
--
|
||||
-- After you've implemented paren, the given definition of parensMatch
|
||||
-- should work.
|
||||
--
|
||||
-- Examples:
|
||||
-- runState (paren '(') 3 ==> (4,())
|
||||
-- runState (paren ')') 3 ==> (2,())
|
||||
-- runState (paren ')') 0 ==> (-1,())
|
||||
-- runState (paren ')') (-1) ==> (-1,())
|
||||
-- runState (paren '(') (-1) ==> (-1,())
|
||||
-- parensMatch "()" ==> True
|
||||
-- parensMatch "(" ==> False
|
||||
-- parensMatch "())" ==> False
|
||||
-- parensMatch "(()(()()))" ==> True
|
||||
-- parensMatch "(()((()))" ==> False
|
||||
-- parensMatch "(()))(" ==> False
|
||||
|
||||
paren :: Char -> State Int ()
|
||||
paren = todo
|
||||
|
||||
parensMatch :: String -> Bool
|
||||
parensMatch s = count == 0
|
||||
where (_,count) = runState (mapM_ paren s) 0
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 9: using a state of type [(a,Int)] we can keep track of the
|
||||
-- numbers of occurrences of elements of type a. For instance
|
||||
-- [('a',1),('x',3)] means that we've seen one 'a' and three 'x's.
|
||||
--
|
||||
-- Implement a State monad operation count that registers the
|
||||
-- occurrence of the given value.
|
||||
--
|
||||
-- That is, the operation `count x` should fetch the pair `(x,n)` from
|
||||
-- the state, and replace it with the pair `(x,n+1)`. If no such pair
|
||||
-- is found, the operation should add `(x,1)` to the state.
|
||||
--
|
||||
-- Examples:
|
||||
-- runState (count True) []
|
||||
-- ==> ((),[(True,1)])
|
||||
-- runState (count 7) []
|
||||
-- ==> ((),[(7,1)])
|
||||
-- runState (count 'a') [('a',1),('b',3)]
|
||||
-- ==> ((),[('a',2),('b',3)])
|
||||
-- runState (count 'a' >> count 'b' >> count 'a') []
|
||||
-- ==> ((),[('a',2),('b',1)])
|
||||
--
|
||||
-- PS. The order of the list of pairs doesn't matter
|
||||
|
||||
count :: Eq a => a -> State [(a,Int)] ()
|
||||
count x = return ()
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 10: Implement the operation occurrences, which
|
||||
-- 1. runs the count operation on each element in the input list
|
||||
-- 2. finally produces the number of different items stored in the
|
||||
-- state
|
||||
--
|
||||
-- In other words, use the state monad to count how many unique values
|
||||
-- occur in a list.
|
||||
--
|
||||
-- Examples:
|
||||
-- runState (occurrences [True,True,True,False,False]) []
|
||||
-- ==> (2,[(True,3),(False,2)])
|
||||
-- runState (occurrences [5,5,6,6,5,6,7]) []
|
||||
-- ==> (3,[(5,3),(6,3),(7,1)])
|
||||
-- runState (occurrences [True,False]) [(True,1)]
|
||||
-- ==> (2,[(True,2),(False,1)])
|
||||
-- runState (occurrences [4,7]) [(2,1),(3,1)]
|
||||
-- ==> (4,[(2,1),(3,1),(4,1),(7,1)])
|
||||
|
||||
occurrences :: (Eq a) => [a] -> State [(a,Int)] Int
|
||||
occurrences xs = todo
|
||||
@@ -0,0 +1,229 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving #-}
|
||||
|
||||
module Set13aTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Control.Monad.State
|
||||
import Data.Char
|
||||
import Data.List
|
||||
import qualified Data.Map as Map
|
||||
import Test.QuickCheck
|
||||
|
||||
import Examples.Bank
|
||||
import Set13a
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"readNames",[ex1_ok, ex1_fail])
|
||||
,(2,"winner",[ex2_small, ex2_big, ex2_fail])
|
||||
,(3,"selectSum",[ex3_ok, ex3_fail])
|
||||
,(4,"countAndLog",[ex4])
|
||||
,(5,"balance",[ex5_balance_examples, ex5_balance_ok, ex5_balance_nok])
|
||||
,(6,"rob",[ex6_rob_examples, ex6_rob])
|
||||
,(7,"State update",[ex7])
|
||||
,(8,"parensMatch",[ex8_paren, ex8_parensMatch])
|
||||
,(9,"State count",[ex9])
|
||||
,(10,"State occurrences",[ex10_1, ex10_2])
|
||||
]
|
||||
|
||||
-- -- -- -- -- -- --
|
||||
|
||||
word = do fst <- choose ('A','Z')
|
||||
rest <- listOf (choose ('a','z'))
|
||||
return $ fst:rest
|
||||
|
||||
bad = do a <- choose ('A','Z')
|
||||
b <- word
|
||||
c <- elements "0123456789"
|
||||
d <- word
|
||||
return $ a:b++c:d
|
||||
|
||||
ex1_ok =
|
||||
forAllBlind word $ \for ->
|
||||
forAllBlind word $ \sur ->
|
||||
let str = for++" "++sur
|
||||
in $(testing [|readNames str|])
|
||||
(?==Just (for,sur))
|
||||
|
||||
m_ex1_fail s =
|
||||
$(testing [|readNames s|]) (?== Nothing)
|
||||
|
||||
ex1_fail =
|
||||
forAllBlind word $ \for ->
|
||||
forAllBlind word $ \sur ->
|
||||
forAllBlind bad $ \b ->
|
||||
conjoin [m_ex1_fail (for ++ sur),
|
||||
m_ex1_fail (map toLower for ++ " " ++ sur),
|
||||
m_ex1_fail (for ++ " " ++ map toLower sur),
|
||||
m_ex1_fail (for ++ b ++ " " ++ sur),
|
||||
m_ex1_fail (for ++ " " ++ sur ++ b)]
|
||||
|
||||
ex2_small =
|
||||
forAllBlind word $ \p1 ->
|
||||
forAllBlind (word `suchThat` (/=p1)) $ \p2 ->
|
||||
forAllBlind (choose (1,20)) $ \s1 ->
|
||||
forAllBlind (choose (0,s1)) $ \s2 ->
|
||||
forAllBlind (shuffle [(p1,s1),(p2,s2)]) $ \inp ->
|
||||
conjoin [$(testing [|winner inp p1 p2|]) (?==Just p1)
|
||||
,s2 < s1 ==> $(testing [|winner inp p2 p1|]) (?==Just p1)]
|
||||
|
||||
ex2_big =
|
||||
forAllBlind word $ \w ->
|
||||
forAllBlind (choose (10,100)) $ \s ->
|
||||
forAllBlind (nub <$> listOf1 (word`suchThat`(/=w))) $ \names ->
|
||||
forAllBlind (vectorOf (length names) (choose (0,s-1))) $ \scores ->
|
||||
forAllBlind (elements names) $ \other ->
|
||||
forAllBlind (shuffle ((w,s):zip names scores)) $ \inp ->
|
||||
conjoin [$(testing [|winner inp other w|]) (?==Just w)
|
||||
,$(testing [|winner inp w other|]) (?==Just w)]
|
||||
|
||||
ex2_fail =
|
||||
forAllBlind (nub <$> listOf1 word) $ \names ->
|
||||
forAllBlind (vectorOf (length names) (choose (0,100))) $ \scores ->
|
||||
forAllBlind (elements names) $ \ok ->
|
||||
forAllBlind (word `suchThat` (not.flip elem names)) $ \nok1 ->
|
||||
forAllBlind (word `suchThat` (not.flip elem names)) $ \nok2 ->
|
||||
let inp = zip names scores
|
||||
in conjoin $[$(testing [|winner inp ok nok1|]) (?==Nothing)
|
||||
,$(testing [|winner inp nok1 ok|]) (?==Nothing)
|
||||
,$(testing [|winner inp nok1 nok2|]) (?==Nothing)]
|
||||
|
||||
ex3_ok = forAll_ $ \(as::[Int]) ->
|
||||
forAllBlind (shuffle (zip [0..] as)) $ \pairs ->
|
||||
forAllShrink_ (sublistOf pairs) $ \selected ->
|
||||
$(testing [|selectSum as (map fst selected)|]) (?==Just (sum $ map snd selected))
|
||||
|
||||
ex3_fail = property $ do
|
||||
as <- arbitrary :: Gen [Int]
|
||||
is <- listOf (choose (0,length as - 1))
|
||||
b <- elements [-1,length as]
|
||||
inp <- shuffle (b:is)
|
||||
return $ $(testing [|selectSum as inp|]) (?==Nothing)
|
||||
|
||||
ex4 = property $ do
|
||||
i <- choose (0::Int,10)
|
||||
is <- listOf (choose (0,10) `suchThat` (/=i))
|
||||
n <- choose (0,5)
|
||||
input <- shuffle (replicate n i ++ is)
|
||||
return $ counterexample ("countAndLog (=="++show i++") "++show input) $
|
||||
countAndLog (==i) input ?== Logger (replicate n (show i)) n
|
||||
|
||||
ex5_balance_examples =
|
||||
conjoin [$(testing' [|runBankOp (balance "harry") exampleBank|]) (?==(10,exampleBank))
|
||||
,$(testing' [|runBankOp (balance "sean") exampleBank|]) (?==(0,exampleBank))]
|
||||
|
||||
bank = do
|
||||
names <- nub <$> listOf1 word
|
||||
bals <- vectorOf (length names) (choose (0,100))
|
||||
return $ Map.fromList (zip names bals)
|
||||
|
||||
ex5_balance_ok = forAllBlind bank $ \b ->
|
||||
forAllBlind (elements (Map.keys b)) $ \account ->
|
||||
let bank = Bank b
|
||||
in $(testing' [|runBankOp (balance account) bank|]) $ \out ->
|
||||
counterexample (" with bank = " ++ show bank++"\n account = "++show account) $
|
||||
out?==(b Map.! account, bank)
|
||||
|
||||
ex5_balance_nok = forAllBlind bank $ \b ->
|
||||
forAllBlind (word `suchThat` (not.flip elem (Map.keys b))) $ \account ->
|
||||
let bank = Bank b
|
||||
in $(testing' [|runBankOp (balance account) bank|]) $ \out ->
|
||||
counterexample (" with bank = " ++ show bank++"\n account = "++show account) $
|
||||
out?==(0,bank)
|
||||
|
||||
ex6_rob_examples =
|
||||
conjoin [$(testing' [|runBankOp (rob "cedric" "ginny") exampleBank|])
|
||||
(?==((),Bank (Map.fromList [("cedric",0),("ginny",8),("harry",10)])))
|
||||
,$(testing' [|runBankOp (rob "sean" "ginny") exampleBank|])
|
||||
(?==((),Bank (Map.fromList [("cedric",7),("ginny",1),("harry",10)])))]
|
||||
|
||||
ex6_rob = property $ do
|
||||
from <- word
|
||||
to <- word `suchThat` (/=from)
|
||||
others <- listOf (word `suchThat` (not.flip elem [from,to]))
|
||||
balf <- choose (0,100)
|
||||
balt <- choose (0,100)
|
||||
bals <- vectorOf (length others) (choose (0,100))
|
||||
let run from to bank exp = $(testing' [|runBankOp (rob from to) bank|]) $ \out ->
|
||||
counterexample (" with bank = " ++ show bank++"\n from = "++show from++"\n to = "++show to) $
|
||||
out ?== ((),exp)
|
||||
return $ conjoin [run from to
|
||||
(Bank . Map.fromList $ (from,balf):(to,balt):zip others bals)
|
||||
(Bank . Map.fromList $ (from,0):(to,balf+balt):zip others bals)
|
||||
,run from to
|
||||
(Bank . Map.fromList $ (to,balt):zip others bals)
|
||||
(Bank . Map.fromList $ (to,balt):zip others bals)]
|
||||
|
||||
ex7 = forAll_ $ \i ->
|
||||
counterexample ("runState update "++show i) $
|
||||
runState update i ?== ((),2*i+1)
|
||||
|
||||
ex8_paren =
|
||||
forAll_ $ \(NonNegative i) ->
|
||||
conjoin [counterexample ("runState (paren '(') "++show i) $
|
||||
runState (paren '(') i ?== ((),i+1)
|
||||
,counterexample ("runState (paren ')') "++show i) $
|
||||
runState (paren ')') i ?== ((),i-1)
|
||||
,$(testing' [|runState (paren '(') (-1)|]) (?==((),-1))
|
||||
,$(testing' [|runState (paren ')') (-1)|]) (?==((),-1))]
|
||||
|
||||
genMatch = frequency [(3,return "()"),
|
||||
(1,(\x -> "("++x++")") <$> genMatch),
|
||||
(1,(++) <$> genMatch <*> genMatch)]
|
||||
|
||||
flop ')' = '('
|
||||
flop '(' = ')'
|
||||
|
||||
breakMatch s = do i <- choose (0,length s - 1)
|
||||
let (pre,x:suf) = splitAt i s
|
||||
elements [pre++suf, pre++flop x:suf]
|
||||
|
||||
filterMatch s = do x <- elements "()"
|
||||
n <- choose (1,length s)
|
||||
return $ s \\ replicate n x
|
||||
|
||||
ex8_parensMatch =
|
||||
forAllBlind genMatch $ \match ->
|
||||
conjoin [$(testing [|parensMatch match|]) (?==True)
|
||||
,forAllBlind (breakMatch match) $ \broken -> $(testing [|parensMatch broken|]) (?==False)
|
||||
,forAllBlind (filterMatch match) $ \broken -> $(testing [|parensMatch broken|]) (?==False)]
|
||||
|
||||
ex9 = property $ do
|
||||
is <- fmap nub $ listOf1 (choose ('a','z') :: Gen Char)
|
||||
fs <- vectorOf (length is) (choose (1,2048))
|
||||
let assocs = zip is fs
|
||||
x <- elements is
|
||||
y <- choose ('0','z') `suchThat` \y -> not (elem y is)
|
||||
let Just cx = lookup x assocs
|
||||
s x = counterexample ("runState (count "++show x++") "++show assocs) . counterexample " Final state"
|
||||
return $ conjoin [s y $
|
||||
hasElements ((y,1):assocs) (execState (count y) assocs)
|
||||
,s x $
|
||||
hasElements ((x,cx+1):delete (x,cx) assocs) (execState (count x) assocs)]
|
||||
|
||||
ex10_1 =
|
||||
forAllShrink_ (nub <$> listOf (choose ('a','z'))) $ \cs ->
|
||||
forAllBlind (vectorOf (length cs) (choose (1,3))) $ \ns ->
|
||||
let expanded = concat (zipWith replicate ns cs)
|
||||
in forAllBlind (shuffle expanded) $ \input ->
|
||||
counterexample ("runState (occurrences "++show input++") []") $
|
||||
let out@(x,s) = runState (occurrences input) []
|
||||
in counterexample (" Was: " ++ show out) $
|
||||
conjoin [counterexample "Produced value" $ x ?== length cs
|
||||
,counterexample "Final state" $ hasElements (zip cs ns) s]
|
||||
|
||||
ex10_2 =
|
||||
forAllShrink_ (nub <$> listOf (choose (10,100))) $ \xs ->
|
||||
forAllBlind (vectorOf (length xs) (choose (1,3))) $ \ns ->
|
||||
forAllBlind (choose (0::Int,9)) $ \x ->
|
||||
forAllBlind (choose (1,20)) $ \n0 ->
|
||||
forAllBlind (choose (1,20)) $ \n ->
|
||||
let state = zip xs ns++[(x,n0)]
|
||||
input = replicate n x
|
||||
in counterexample ("runState (occurrences "++show input++") "++show state) $
|
||||
let out@(ret,s) = runState (occurrences input) state
|
||||
in counterexample (" Was: " ++ show out) $
|
||||
conjoin [counterexample "Produced value" $ ret ?== length xs + 1
|
||||
,counterexample "Final state" $ hasElements ((x,n+n0):zip xs ns) s]
|
||||
@@ -0,0 +1,325 @@
|
||||
module Set13b where
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
import Control.Monad
|
||||
import Control.Monad.State
|
||||
import Data.Char
|
||||
import Data.List
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: implement the function ifM, that takes three monadic
|
||||
-- operations. If the first of the operations returns True, the second
|
||||
-- operation should be run. Otherwise the third operation should be
|
||||
-- run.
|
||||
--
|
||||
-- Note the polymorphic `Monad m =>` type signature. Your operation
|
||||
-- should work on all monads, and thus needs to be implemented with
|
||||
-- Monad operations like do and >>=. Don't try to pattern match on
|
||||
-- Maybes.
|
||||
--
|
||||
-- Examples (test is defined below):
|
||||
-- In the Maybe Monad:
|
||||
-- ifM (Just True) (Just '1') (Just '2') ==> Just '1'
|
||||
-- ifM (Just False) (Just '1') (Just '2') ==> Just '2'
|
||||
-- ifM Nothing (Just '1') (Just '2') ==> Nothing
|
||||
-- ifM (Just True) (Just '1') Nothing ==> Just '1'
|
||||
-- In the State Monad (test is defined below):
|
||||
-- runState (ifM get (return 'a') (return 'b')) False
|
||||
-- ==> ('b',False)
|
||||
-- runState (put 11 >> ifM test (return 'a') (return 'b')) 0
|
||||
-- ==> ('b',11)
|
||||
-- runState (put 9 >> ifM test (return 'a') (return 'b')) 0
|
||||
-- ==> ('a',9)
|
||||
|
||||
test :: State Int Bool
|
||||
test = do
|
||||
x <- get
|
||||
return (x<10)
|
||||
|
||||
ifM :: Monad m => m Bool -> m a -> m a -> m a
|
||||
ifM opBool opThen opElse = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: the standard library function Control.Monad.mapM defines a
|
||||
-- monadic map operation. Some examples of using it (safeDiv is defined
|
||||
-- below):
|
||||
--
|
||||
-- mapM (safeDiv 10.0) [1.0,5.0,2.0] => Just [10.0,2.0,5.0]
|
||||
-- mapM (safeDiv 10.0) [1.0,0.0,2.0] => Nothing
|
||||
--
|
||||
-- Your task is to implement the function mapM2 that works like mapM,
|
||||
-- but there are two lists and the operation takes two arguments. More
|
||||
-- concretely, running `mapM2 op xs ys` should run `op`, giving it the
|
||||
-- first element of xs and the first element of ys. Then, it should
|
||||
-- run `op` on the second elements of xs and ys, and so forth.
|
||||
-- Finally, all the values produced by `op` are returned, in order, as
|
||||
-- a list.
|
||||
--
|
||||
-- If the lists are of different length, you can stop processing them
|
||||
-- once the shorter one ends.
|
||||
--
|
||||
-- Examples:
|
||||
-- mapM2 safeDiv [6.0,10.0,12.0] [3.0,2.0,4.0]
|
||||
-- ==> Just [2.0,5.0,3.0]
|
||||
-- mapM2 safeDiv [6.0,10.0,12.0] [3.0,0.0,4.0]
|
||||
-- ==> Nothing
|
||||
-- mapM2 (\x y -> Just (x+y)) [1,2,3] [6,7]
|
||||
-- ==> Just [7,9]
|
||||
-- runState (mapM2 perhapsIncrement [True,False,True] [1,2,4]) 0
|
||||
-- ==> ([(),(),()],5)
|
||||
|
||||
-- Do not change safeDiv or perhapsIncrement, they're used by the
|
||||
-- examples & test outputs.
|
||||
safeDiv :: Double -> Double -> Maybe Double
|
||||
safeDiv x 0.0 = Nothing
|
||||
safeDiv x y = Just (x/y)
|
||||
|
||||
perhapsIncrement :: Bool -> Int -> State Int ()
|
||||
perhapsIncrement True x = modify (+x)
|
||||
perhapsIncrement False _ = return ()
|
||||
|
||||
mapM2 :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]
|
||||
mapM2 op xs ys = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: Finding paths.
|
||||
--
|
||||
-- In this exercise, you'll process mazes, described as lists like this:
|
||||
|
||||
maze1 :: [(String,[String])]
|
||||
maze1 = [("Entry",["Pit","Corridor 1"])
|
||||
,("Pit",[])
|
||||
,("Corridor 1",["Entry","Dead end"])
|
||||
,("Dead end",["Corridor 1"])
|
||||
,("Corridor 2",["Corridor 3"])
|
||||
,("Corridor 3",["Corridor 2"])]
|
||||
|
||||
-- This means that you can get from Entry to Pit or Corridor 1, and
|
||||
-- from Corridor 1 you can get back to Entry or the Dead end, and so
|
||||
-- forth. Here's a drawing of what maze1 looks like. Note how you
|
||||
-- can't get out of the Pit, and Corridors 2 and 3 aren't connected to
|
||||
-- the Entry.
|
||||
--
|
||||
-- Entry <--> Corridor 1 <--> Dead end
|
||||
-- |
|
||||
-- v Corridor 2 <--> Corridor 3
|
||||
-- Pit
|
||||
--
|
||||
-- Your task is to implement the function path that checks if there is
|
||||
-- a path from one location to another.
|
||||
--
|
||||
-- path maze1 "Entry" "Pit" ==> True
|
||||
-- path maze1 "Entry" "Dead end" ==> True
|
||||
-- path maze1 "Pit" "Entry" ==> False
|
||||
-- path maze1 "Entry" "Corridor 2" ==> False
|
||||
--
|
||||
-- To implement path, we'll need some helper functions. We'll work in
|
||||
-- the State monad, with a state of type [String]. This tracks which
|
||||
-- places we've been to.
|
||||
--
|
||||
-- The operation `visit maze place1` should work like this:
|
||||
-- * if place1 is in the state (i.e. we've visited it before), do nothing
|
||||
-- * otherwise, add place1 to the state (it has now been visited), and:
|
||||
-- * for all neighbouring places of place1, run visit
|
||||
--
|
||||
-- PS. You might recognize this as a Depth-First Search, but if you
|
||||
-- haven't heard the term, don't worry.
|
||||
--
|
||||
-- Examples:
|
||||
-- runState (visit maze1 "Pit") []
|
||||
-- ==> ((),["Pit"])
|
||||
-- runState (visit maze1 "Corridor 2") []
|
||||
-- ==> ((),["Corridor 3","Corridor 2"])
|
||||
-- runState (visit maze1 "Entry") []
|
||||
-- ==> ((),["Dead end","Corridor 1","Pit","Entry"])
|
||||
-- runState (visit maze1 "Entry") ["Corridor 1"]
|
||||
-- ==> ((),["Pit","Entry","Corridor 1"])
|
||||
|
||||
|
||||
visit :: [(String,[String])] -> String -> State [String] ()
|
||||
visit maze place = todo
|
||||
|
||||
-- Now you should be able to implement path using visit. If you run
|
||||
-- visit on a place using an empty state, you'll get a state that
|
||||
-- lists all the places that are reachable from the starting place.
|
||||
|
||||
path :: [(String,[String])] -> String -> String -> Bool
|
||||
path maze place1 place2 = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: Given two lists, ks and ns, find numbers i and j from ks,
|
||||
-- such that their sum i+j=n is in ns. Return all such triples
|
||||
-- (i,j,n).
|
||||
--
|
||||
-- Use the list monad!
|
||||
--
|
||||
-- Examples:
|
||||
-- findSum2 [1,2,3,4] [6,7]
|
||||
-- ==> [(2,4,6),(3,3,6),(3,4,7),(4,2,6),(4,3,7)]
|
||||
--
|
||||
-- PS. The tests don't care about the order of results.
|
||||
|
||||
findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)]
|
||||
findSum2 ks ns = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: compute all possible sums of elements from the given
|
||||
-- list. Use the list monad.
|
||||
--
|
||||
-- Hint! a list literal like [True,False] or [x,0] can be useful when
|
||||
-- combined with do-notation!
|
||||
--
|
||||
-- The order of the returned list does not matter and it may contain
|
||||
-- duplicates.
|
||||
--
|
||||
-- Examples:
|
||||
-- allSums []
|
||||
-- ==> [0]
|
||||
-- allSums [1]
|
||||
-- ==> [1,0]
|
||||
-- allSums [1,2,4]
|
||||
-- ==> [7,3,5,1,6,2,4,0]
|
||||
|
||||
allSums :: [Int] -> [Int]
|
||||
allSums xs = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: the standard library defines the function
|
||||
--
|
||||
-- foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
|
||||
--
|
||||
-- This function behaves like foldr, but the operation used is
|
||||
-- monadic. foldM f acc xs works by running f for each element in xs,
|
||||
-- giving it also the result of the previous invocation of f.
|
||||
--
|
||||
-- Your task is to implement the functions f1 and f2 so that the
|
||||
-- functions sumBounded and sumNotTwice work.
|
||||
--
|
||||
-- Do not change the definitions of sumBounded and sumNotTwice. The
|
||||
-- tests have their own copies of the definitions anyway.
|
||||
|
||||
-- sumBounded computes the sum of a list. However if the sum at any
|
||||
-- point during the execution goes over the given bound, Nothing is
|
||||
-- returned.
|
||||
--
|
||||
-- Examples:
|
||||
-- sumBounded 5 [1,2,1,-2,3]
|
||||
-- ==> Just 5
|
||||
-- sumBounded 5 [1,2,3,1,-2] -- 1+2+3=6 which results in Nothing
|
||||
-- ==> Nothing
|
||||
sumBounded :: Int -> [Int] -> Maybe Int
|
||||
sumBounded k xs = foldM (f1 k) 0 xs
|
||||
|
||||
f1 :: Int -> Int -> Int -> Maybe Int
|
||||
f1 k acc x = todo
|
||||
|
||||
-- sumNotTwice computes the sum of a list, but counts only the first
|
||||
-- occurrence of each value.
|
||||
--
|
||||
-- Examples:
|
||||
-- sumNotTwice [1,2,3] ==> 6
|
||||
-- sumNotTwice [1,1,2,3,2,2,3] ==> 6
|
||||
-- sumNotTwice [3,-2,3] ==> 1
|
||||
-- sumNotTwice [1,2,-2,3] ==> 4
|
||||
sumNotTwice :: [Int] -> Int
|
||||
sumNotTwice xs = fst $ runState (foldM f2 0 xs) []
|
||||
|
||||
f2 :: Int -> Int -> State [Int] Int
|
||||
f2 acc x = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: here is the Result type from Set12. Implement a Monad Result
|
||||
-- instance that behaves roughly like the Monad Maybe instance.
|
||||
--
|
||||
-- That is,
|
||||
-- 1. MkResult behave like Just
|
||||
-- 2. If part of computation produces NoResult, the whole computation
|
||||
-- produces NoResult (just like Nothing)
|
||||
-- 3. Similarly, if we get a Failure "reason" value, the whole
|
||||
-- computation produces Failure "reason"
|
||||
--
|
||||
-- Examples:
|
||||
-- MkResult 1 >> Failure "boom" >> MkResult 2
|
||||
-- ==> Failure "boom"
|
||||
-- MkResult 1 >> NoResult >> Failure "not reached"
|
||||
-- ==> NoResult
|
||||
-- MkResult 1 >>= (\x -> MkResult (x+1))
|
||||
-- ==> MkResult 2
|
||||
|
||||
data Result a = MkResult a | NoResult | Failure String deriving (Show,Eq)
|
||||
|
||||
instance Functor Result where
|
||||
-- The same Functor instance you used in Set12 works here.
|
||||
fmap = todo
|
||||
|
||||
-- This is an Applicative instance that works for any monad, you
|
||||
-- can just ignore it for now. We'll get back to Applicative later.
|
||||
instance Applicative Result where
|
||||
pure = return
|
||||
(<*>) = ap
|
||||
|
||||
instance Monad Result where
|
||||
-- implement return and >>=
|
||||
return = todo
|
||||
(>>=) = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: Here is the type SL that combines the State and Logger
|
||||
-- types. Implement an instance Monad SL, that behaves like the
|
||||
-- combination of State and Logger. That is, state is propagated from
|
||||
-- one operation to the next, and log messages are stored in the order
|
||||
-- they are produced.
|
||||
--
|
||||
-- To simplify the type signatures, the type of the state has been set
|
||||
-- to Int, instead of being a parameter like in the standard State
|
||||
-- monad.
|
||||
--
|
||||
-- This is a tough one, probably the hardest exercise on this course!
|
||||
-- You can come back to it later if you don't get it now.
|
||||
--
|
||||
-- You might find it easier to start with the Functor instance
|
||||
--
|
||||
-- Examples:
|
||||
-- runSL (putSL 2 >> msgSL "hello" >> getSL) 0
|
||||
-- ==> (2,2,["hello"])
|
||||
-- runSL (replicateM_ 5 (modifySL (+1) >> getSL >>= \x -> msgSL ("got "++show x))) 1
|
||||
-- ==> ((),6,["got 2","got 3","got 4","got 5","got 6"])
|
||||
|
||||
data SL a = SL (Int -> (a,Int,[String]))
|
||||
|
||||
-- Run an SL operation with the given starting state
|
||||
runSL :: SL a -> Int -> (a,Int,[String])
|
||||
runSL (SL f) state = f state
|
||||
|
||||
-- Write a log message
|
||||
msgSL :: String -> SL ()
|
||||
msgSL msg = SL (\s -> ((),s,[msg]))
|
||||
|
||||
-- Fetch the state
|
||||
getSL :: SL Int
|
||||
getSL = SL (\s -> (s,s,[]))
|
||||
|
||||
-- Overwrite the state
|
||||
putSL :: Int -> SL ()
|
||||
putSL s' = SL (\s -> ((),s',[]))
|
||||
|
||||
-- Modify the state
|
||||
modifySL :: (Int->Int) -> SL ()
|
||||
modifySL f = SL (\s -> ((),f s,[]))
|
||||
|
||||
instance Functor SL where
|
||||
-- implement fmap
|
||||
fmap = todo
|
||||
|
||||
-- This is an Applicative instance that works for any monad, you
|
||||
-- can just ignore it for now. We'll get back to Applicative later.
|
||||
instance Applicative SL where
|
||||
pure = return
|
||||
(<*>) = ap
|
||||
|
||||
instance Monad SL where
|
||||
-- implement return and >>=
|
||||
return = todo
|
||||
(>>=) = todo
|
||||
@@ -0,0 +1,269 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving #-}
|
||||
|
||||
module Set13bTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Control.Monad.State
|
||||
import qualified Data.Bits
|
||||
import Data.Char
|
||||
import Data.Either
|
||||
import Data.Function
|
||||
import Data.List
|
||||
import qualified Data.Map as Map
|
||||
import Test.QuickCheck hiding (Result,Failure)
|
||||
|
||||
import Examples.Bank
|
||||
import Set13b hiding (perhapsIncrement,sumBounded,sumNotTwice)
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"ifM",[ex1_maybe, ex1_state])
|
||||
,(2,"mapM2",[ex2_maybe, ex2_state])
|
||||
,(3,"path",[ex3_visit_examples, ex3_visit_tree, ex3_visit_linear, ex3_visit
|
||||
,ex3_path_examples, ex3_path_linear, ex3_path])
|
||||
,(4,"findSum2", [ex4_simple, ex4])
|
||||
,(5,"allSums", [ex5_bits])
|
||||
,(6,"foldM", [ex6_sumBounded_ok, ex6_sumBounded_fail, ex6_sumNotTwice])
|
||||
,(7,"Monad Result", [ex7])
|
||||
,(8,"Monad SL", [ex8_fmap_1, ex8_fmap_2, ex8_1, ex8_2, ex8_stress])]
|
||||
|
||||
-- -- -- -- -- -- --
|
||||
|
||||
ex1_maybe =
|
||||
forAll_ $ \(c::Char) ->
|
||||
forAll_ $ \(d::Char) ->
|
||||
forAll_ $ \(b::Bool) ->
|
||||
let nc = Nothing :: Maybe Char
|
||||
nb = Nothing :: Maybe Bool
|
||||
in conjoin [$(testing [|ifM (Just b) (Just c) (Just d)|]) (?==Just (if b then c else d))
|
||||
,$(testing [|ifM (Just b) (Just c) nc|]) (?==if b then Just c else Nothing)
|
||||
,$(testing [|ifM (Just b) nc (Just d)|]) (?==if b then Nothing else Just d)
|
||||
,$(testing [|ifM nb (Just c) (Just d)|]) (?==Nothing)]
|
||||
|
||||
ex1_state =
|
||||
conjoin [$(testing' [|runState (ifM get (return 'a') (return 'b')) True|]) (?==('a',True))
|
||||
,$(testing' [|runState (ifM get (return 'a') (return 'b')) False|]) (?==('b',False))]
|
||||
|
||||
ex2_maybe =
|
||||
forAll_ $ \(as::[Int]) ->
|
||||
forAll_ $ \(bs::[Int]) ->
|
||||
let z = zipWith (-) as bs
|
||||
res = if all (/=0) z then Just z else Nothing
|
||||
in counterexample ("mapM2 (\\x y -> if x == y then Nothing else Just (x-y)) "++show as++" "++show bs) $
|
||||
mapM2 (\x y -> if x == y then Nothing else Just (x-y)) as bs ?== res
|
||||
|
||||
perhapsIncrement :: Bool -> Int -> State Int ()
|
||||
perhapsIncrement True x = modify (+x)
|
||||
perhapsIncrement False _ = return ()
|
||||
|
||||
ex2_state =
|
||||
forAll_ $ \(bs::[Bool]) ->
|
||||
forAll_ $ \(is::[Int]) ->
|
||||
counterexample ("runState (mapM2 perhapsIncrement "++show bs++" "++show is++") 0") $
|
||||
runState (mapM2 perhapsIncrement bs is) 0 ?== (zipWith (\_ _ -> ()) is bs, sum $ zipWith (\b i -> if b then i else 0) bs is)
|
||||
|
||||
ex3_visit_examples = conjoin [$(testing' [|runState (visit maze1 "Pit") []|]) (?==((),["Pit"]))
|
||||
,$(testing' [|runState (visit maze1 "Corridor 2") []|]) (?==((),["Corridor 3","Corridor 2"]))
|
||||
,$(testing' [|runState (visit maze1 "Entry") []|]) (?==((),["Dead end","Corridor 1","Pit","Entry"]))
|
||||
,$(testing' [|runState (visit maze1 "Entry") ["Corridor 1"]|]) (?==((),["Pit","Entry","Corridor 1"]))]
|
||||
|
||||
genTree 0 name = return [(name,[])]
|
||||
genTree height name = do
|
||||
n <- choose (1,3)
|
||||
children <- nub <$> vectorOf n ((:name) <$> choose ('a','z'))
|
||||
rest <- concat <$> forM children (genTree (height-1))
|
||||
return $ (name,children):rest
|
||||
|
||||
shrinkTree xs = do pair@(x,_) <- xs
|
||||
return $ map (\(n,ns) -> (n,delete x ns)) $ delete pair xs
|
||||
|
||||
ex3_visit_tree = forAllBlind (choose (1::Int,4)) $ \depth ->
|
||||
forAllShrinkBlind (genTree depth "0") shrinkTree $ \maze ->
|
||||
let root = fst (head maze)
|
||||
in counterexample ("runState (visit "++show maze++" "++show root++") []") $
|
||||
within timeLimit $
|
||||
($ runState (visit maze root) []) . was $ \(_,state) ->
|
||||
counterexample " Final state" $
|
||||
hasElements (map fst maze) state
|
||||
|
||||
ex3_visit_linear = forAllBlind (choose (2::Int,6)) $ \n ->
|
||||
forAllBlind (choose (0,n-1)) $ \start ->
|
||||
forAllBlind (choose (start,n)) $ \end ->
|
||||
let maze = [(show i,[show (i+1)]) | i <- [0..n-1]]++[(show n,[])]
|
||||
sstart = show start
|
||||
send = show end
|
||||
in counterexample ("runState (visit "++show maze++" "++show sstart++") ["++show send++"]") $
|
||||
within timeLimit $
|
||||
($ runState (visit maze sstart) [send]) . was $ \(_,state) ->
|
||||
counterexample " Final state" $
|
||||
hasElements (map show [start..end]) state
|
||||
|
||||
genConn :: [String] -> [String] -> Gen [(String,String)]
|
||||
genConn nodes [] = return []
|
||||
genConn nodes todo = do
|
||||
u <- elements todo
|
||||
v <- elements $ nodes \\ todo
|
||||
rest <- genConn nodes (delete u todo)
|
||||
return $ (u,v):(v,u):rest
|
||||
|
||||
genGraph :: [String] -> Gen [(String,String)]
|
||||
genGraph nodes = do
|
||||
base <- genConn nodes (tail nodes)
|
||||
ns <- vectorOf 3 (elements nodes)
|
||||
return $ (ns!!0,ns!!1):(ns!!1,ns!!2):base
|
||||
|
||||
adj :: [(String,String)] -> [(String,[String])]
|
||||
adj = map (simpl.unzip) . groupBy ((==)`on`fst) . sort . nub
|
||||
where simpl (x:_,ys) = (x,ys)
|
||||
|
||||
ex3_visit = property $ do
|
||||
n1 <- choose (1,5)
|
||||
n2 <- choose (1,4)
|
||||
names <- shuffle $ map show [1..n1+n2]
|
||||
let (names1,names2) = splitAt n1 names
|
||||
g1 <- genGraph names1
|
||||
g2 <- genGraph names2
|
||||
let maze = adj (g1++g2)
|
||||
return $ counterexample ("runState (visit "++show maze++" "++head names1++") []") $
|
||||
within timeLimit $
|
||||
($ runState (visit maze (head names1)) []) . was $ \(_,state) ->
|
||||
counterexample " Final state" $
|
||||
hasElements names1 state
|
||||
|
||||
ex3_path_examples =
|
||||
conjoin [$(testing' [|path maze1 "Entry" "Pit"|]) (?==True)
|
||||
,$(testing' [|path maze1 "Entry" "Dead end"|]) (?==True)
|
||||
,$(testing' [|path maze1 "Pit" "Entry"|]) (?==False)
|
||||
,$(testing' [|path maze1 "Entry" "Corridor 2"|]) (?==False)]
|
||||
|
||||
ex3_path_linear = forAllBlind (choose (2::Int,6)) $ \n ->
|
||||
forAllBlind (choose (0,n)) $ \start ->
|
||||
forAllBlind (choose (0,n)) $ \end ->
|
||||
let maze = [(show i,[show (i+1)]) | i <- [0..n-1]]++[(show n,[])]
|
||||
sstart = show start
|
||||
send = show end
|
||||
in $(testing [|path maze sstart send|]) (?==(start<=end))
|
||||
|
||||
ex3_path = property $ do
|
||||
n1 <- choose (1,5)
|
||||
n2 <- choose (1,5)
|
||||
names <- shuffle $ map show [1..n1+n2]
|
||||
let (names1,names2) = splitAt n1 names
|
||||
g1 <- genGraph names1
|
||||
g2 <- genGraph names2
|
||||
let maze = adj (g1++g2)
|
||||
from <- elements names
|
||||
to <- elements names
|
||||
return $ $(testing [|path maze from to|]) (?==(elem from names1 == elem to names1))
|
||||
|
||||
ex4_simple =
|
||||
conjoin [$(testing [|findSum2 [6,1] [7]|]) (hasElements [(1,6,7),(6,1,7)])
|
||||
,$(testing [|findSum2 [6,1] [8]|]) (?==[])
|
||||
,$(testing [|findSum2 [2,1] [4]|]) (hasElements [(2,2,4)])
|
||||
,$(testing [|findSum2 [1,2,3,4] [6,7]|]) (hasElements [(2,4,6),(3,3,6),(3,4,7),(4,2,6),(4,3,7)])]
|
||||
|
||||
ex4 = forAllShrink_ (choose (1, 10)) $ \n ->
|
||||
(n>0 ==>) $
|
||||
property $ do
|
||||
step <- choose (1,5)
|
||||
start <- choose (1,100)
|
||||
let vals = [start,start+step..start+step*(n-1)]
|
||||
i1 <- choose (0,length vals-1)
|
||||
--i2 <- choose (0,n)
|
||||
let v1 = (vals!!i1)*2
|
||||
lim1 = min i1 (length vals-1-i1)
|
||||
triples1 = [(vals!!(i1-k),vals!!(i1+k),v1) | k <- [-lim1..lim1]]
|
||||
return $ $(testing [|findSum2 vals [v1]|]) (hasElements triples1)
|
||||
|
||||
ex5_bits = forAllShrink_ (choose (1::Int,9)) $ \n ->
|
||||
let vals = 0:map (\x -> 2^x) [0..n]
|
||||
all = nub $ [0..2^(n+1)-1]
|
||||
in conjoin [forAllBlind (elements vals) $ \del ->
|
||||
del > 0 ==>
|
||||
$(testing [|allSums (delete del vals)|]) (hasElementsDuplicates (filter ((==0).(Data.Bits..&.del)) all))
|
||||
,$(testing [|allSums vals|]) (hasElementsDuplicates all)]
|
||||
|
||||
m is = maximum (scanl1 (+) is)
|
||||
|
||||
sumBounded :: Int -> [Int] -> Maybe Int
|
||||
sumBounded k xs = foldM (f1 k) 0 xs
|
||||
|
||||
ex6_sumBounded_ok =
|
||||
forAllShrink_ (listOf1 (choose (-10,10))) $ \is ->
|
||||
forAllBlind (choose (0,3)) $ \diff ->
|
||||
let k = m is + diff
|
||||
in $(testing [|sumBounded k is|]) (?==Just (sum is))
|
||||
|
||||
ex6_sumBounded_fail =
|
||||
forAllBlind (listOf1 (choose (-10,10))) $ \is ->
|
||||
forAllBlind (choose (1::Int,3)) $ \diff ->
|
||||
let k = m is - diff
|
||||
in $(testing [|sumBounded k is|]) (?==Nothing)
|
||||
|
||||
sumNotTwice :: [Int] -> Int
|
||||
sumNotTwice xs = fst $ runState (foldM f2 0 xs) []
|
||||
|
||||
ex6_sumNotTwice =
|
||||
forAllShrink_ (listOf1 (choose (-5,5))) $ \is ->
|
||||
$(testing [|sumNotTwice is|]) (?==sum (nub is))
|
||||
|
||||
ex7 =
|
||||
let op :: Int -> Result Int
|
||||
op i = if i>3 then Failure "big" else return (i+1)
|
||||
s = "let op i = if (i>3) then Failure \"big\" else return (i+1) in "
|
||||
in conjoin [counterexample' (s++" MkResult 1 >>= op") $
|
||||
(MkResult 1 >>= op) ?== MkResult 2,
|
||||
counterexample' (s++" MkResult 4 >>= op") $
|
||||
(MkResult 4 >>= op) ?== Failure "big",
|
||||
counterexample' (s++" Fail \"foo\" >>= op") $
|
||||
(Failure "foo" >>= op) ?== Failure "foo",
|
||||
counterexample' (s++" NoResult >>= op") $
|
||||
(NoResult >>= op) ?== NoResult]
|
||||
|
||||
word = listOf1 (choose ('a','z'))
|
||||
|
||||
ex8_fmap_1 = property $
|
||||
do i <- choose (0,10)
|
||||
let op = fmap (+1) getSL
|
||||
return $ counterexample ("runSL (fmap (+1) getSL) " ++ show i) $
|
||||
runSL op i ?== (i+1,i,[])
|
||||
|
||||
ex8_fmap_2 = property $
|
||||
do m <- word
|
||||
s <- choose (0,10)
|
||||
let op = fmap (const True) (msgSL m)
|
||||
return $ counterexample ("runSL (fmap (const True) (msgSL "++show m++")) "++show s) $
|
||||
runSL op s ?== (True,s,[m])
|
||||
|
||||
ex8_1 = property $
|
||||
do i <- choose (0,10)
|
||||
let op = putSL i >> getSL >>= \i -> msgSL (show i)
|
||||
s = "putSL "++show i++" >> getSL >>= \\i -> msgSL (show i)"
|
||||
return $ counterexample ("runSL ("++s++") 1") $ runSL op 1 ?== ((),i,[show i])
|
||||
|
||||
ex8_2 = property $
|
||||
do msg <- word
|
||||
msg2 <- word
|
||||
i <- choose (0,10)
|
||||
j <- choose (0,10)
|
||||
let op = do msgSL msg
|
||||
x <- getSL
|
||||
msgSL (msg2++show x)
|
||||
putSL (x+i)
|
||||
return x
|
||||
s = "op = \ndo msgSL "++show msg++"\n x <- getSL\n msgSL ("++show msg2++"++show x)\n putSL (x+"++show i++")\n return x"
|
||||
return $ counterexample (s++"\n\nrunSL op "++show j) $ runSL op j ?== (j,j+i,[msg,msg2++show j])
|
||||
|
||||
ex8_stress =
|
||||
forAll_ $ \ops ->
|
||||
let m (Left i) = modifySL (+i)
|
||||
m (Right s) = msgSL s
|
||||
s (Left i) = "modifySL (+"++show i++")"
|
||||
s (Right m) = "msgSL "++show m
|
||||
op = mapM_ m ops
|
||||
desc = "runSL ("++intercalate " >> " (map s ops)++") 0"
|
||||
(incs,msgs) = partitionEithers ops
|
||||
state = sum incs
|
||||
in counterexample desc $ runSL op 0 ?== ((),state,msgs)
|
||||
@@ -0,0 +1,216 @@
|
||||
-- Welcome to the first exercise set of part 2 of the Haskell Mooc!
|
||||
-- Edit this file according to the instructions, and check your
|
||||
-- answers with
|
||||
--
|
||||
-- stack runhaskell Set9aTest.hs
|
||||
--
|
||||
-- You can also play around with your answers in GHCi with
|
||||
--
|
||||
-- stack ghci Set9a.hs
|
||||
|
||||
module Set9a where
|
||||
|
||||
import Data.List
|
||||
import Data.Ord
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: Implement a function workload that takes in the number of
|
||||
-- exercise a student has to finish, and another number that counts
|
||||
-- the number of hours each exercise takes.
|
||||
--
|
||||
-- If the total number of hours needed for all exercises is over 100,
|
||||
-- return "Holy moly!" if it is under 10, return "Piece of cake!".
|
||||
-- Otherwise return "Ok."
|
||||
|
||||
workload :: Int -> Int -> String
|
||||
workload nExercises hoursPerExercise = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: Implement the function echo that builds a string like this:
|
||||
--
|
||||
-- echo "hello!" ==> "hello!, ello!, llo!, lo!, o!, !, "
|
||||
-- echo "ECHO" ==> "ECHO, CHO, HO, O, "
|
||||
-- echo "X" ==> "X, "
|
||||
-- echo "" ==> ""
|
||||
--
|
||||
-- Hint: use recursion
|
||||
|
||||
echo :: String -> String
|
||||
echo = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: A country issues some banknotes. The banknotes have a serial
|
||||
-- number that can be used to check if the banknote is valid. For a
|
||||
-- banknote to be valid, either
|
||||
-- * the third and fifth digits need to be the same
|
||||
-- * or the fourth and sixth digits need to be the same
|
||||
--
|
||||
-- Given a list of bank note serial numbers (strings), count how many
|
||||
-- are valid.
|
||||
|
||||
countValid :: [String] -> Int
|
||||
countValid = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: Find the first element that repeats two or more times _in a
|
||||
-- row_ in the input list. Return a Nothing value if no element repeats.
|
||||
--
|
||||
-- Examples:
|
||||
-- repeated [1,2,3] ==> Nothing
|
||||
-- repeated [1,2,2,3,3] ==> Just 2
|
||||
-- repeated [1,2,1,2,3,3] ==> Just 3
|
||||
|
||||
repeated :: Eq a => [a] -> Maybe a
|
||||
repeated = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: A laboratory has been collecting measurements. Some of the
|
||||
-- measurements have failed, so the lab is using the type
|
||||
-- Either String Int
|
||||
-- to track the measurements. A Left value represents a failed measurement,
|
||||
-- while a Right value represents a succesful one.
|
||||
--
|
||||
-- Compute the sum of all succesful measurements. If there are
|
||||
-- succesful measurements, return the sum wrapped in a Right, but if
|
||||
-- there are none, return Left "no data".
|
||||
--
|
||||
-- Examples:
|
||||
-- sumSuccess [Right 1, Left "it was a snake!", Right 3]
|
||||
-- ==> Right 4
|
||||
-- sumSuccess [Left "lab blew up", Left "I was sick"]
|
||||
-- ==> Left "no data"
|
||||
-- sumSuccess []
|
||||
-- ==> Left "no data"
|
||||
|
||||
sumSuccess :: [Either String Int] -> Either String Int
|
||||
sumSuccess = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: A combination lock can either be open or closed. The lock
|
||||
-- also remembers a code. A closed lock can only be opened with the
|
||||
-- right code. The code of an open lock can be changed.
|
||||
--
|
||||
-- Implement a datatype Lock and the functions isOpen, open, lock,
|
||||
-- changeCode and the constant aLock as instructed below.
|
||||
--
|
||||
-- Examples:
|
||||
-- isOpen aLock ==> False
|
||||
-- isOpen (lock aLock) ==> False
|
||||
-- isOpen (open "1234" aLock) ==> True
|
||||
-- isOpen (lock (open "1234" aLock)) ==> False
|
||||
-- isOpen (open "1235" aLock) ==> False
|
||||
-- isOpen (lock (open "1235" aLock)) ==> False
|
||||
-- isOpen (open "1234" (changeCode "0000" aLock)) ==> True
|
||||
-- isOpen (open "0000" (changeCode "0000" aLock)) ==> False
|
||||
-- isOpen (open "0000" (lock (changeCode "0000" (open "1234" aLock)))) ==> True
|
||||
-- isOpen (open "1234" (lock (changeCode "0000" (open "1234" aLock)))) ==> False
|
||||
|
||||
data Lock = LockUndefined
|
||||
deriving Show
|
||||
|
||||
-- aLock should be a locked lock with the code "1234"
|
||||
aLock :: Lock
|
||||
aLock = todo
|
||||
|
||||
-- isOpen returns True if the lock is open
|
||||
isOpen :: Lock -> Bool
|
||||
isOpen = todo
|
||||
|
||||
-- open tries to open the lock with the given code. If the code is
|
||||
-- wrong, nothing happens.
|
||||
open :: String -> Lock -> Lock
|
||||
open = todo
|
||||
|
||||
-- lock closes a lock. If the lock is already closed, nothing happens.
|
||||
lock :: Lock -> Lock
|
||||
lock = todo
|
||||
|
||||
-- changeCode changes the code of an open lock. If the lock is closed,
|
||||
-- nothing happens.
|
||||
changeCode :: String -> Lock -> Lock
|
||||
changeCode = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: Here's a type Text that just wraps a String. Implement an Eq
|
||||
-- instance for Text that ignores all white space (space characters
|
||||
-- and line returns).
|
||||
--
|
||||
-- Examples
|
||||
-- Text "abc" == Text "abc" ==> True
|
||||
-- Text "a bc" == Text "ab c\n" ==> True
|
||||
-- Text "abc" == Text "abcd" ==> False
|
||||
-- Text "a bc" == Text "ab d\n" ==> False
|
||||
|
||||
data Text = Text String
|
||||
deriving Show
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: We can represent functions or mappings as lists of pairs.
|
||||
-- For example the list [("bob",13),("mary",8)] means that "bob" maps
|
||||
-- to 13 and "mary" maps to 8.
|
||||
--
|
||||
-- Implement _composition_ for mappings like this. You compose two
|
||||
-- mappings by looking up each result of the first mapping in the
|
||||
-- second mapping.
|
||||
--
|
||||
-- You may assume there are no repeated first elements of tuples in
|
||||
-- the argument lists, that is.
|
||||
--
|
||||
-- The ordering of the output doesn't matter.
|
||||
--
|
||||
-- Hint: remember the function `lookup` from Prelude?
|
||||
--
|
||||
-- Examples:
|
||||
-- composing two mappings of size 1:
|
||||
-- compose [("a",1)] [(1,True)]
|
||||
-- ==> [("a",True)]
|
||||
-- nonmatching mappings get ignored:
|
||||
-- compose [("a",1),("b",2)] [(3,False),(4,True)]
|
||||
-- ==> []
|
||||
-- a more complex example: note how "omicron" and "c" are ignored
|
||||
-- compose [("a","alpha"),("b","beta"),("c","gamma")] [("alpha",1),("beta",2),("omicron",15)]
|
||||
-- ==> [("a",1),("b",2)]
|
||||
|
||||
compose :: (Eq a, Eq b) => [(a,b)] -> [(b,c)] -> [(a,c)]
|
||||
compose = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 9: Reorder a list using an [(Int,Int)] mapping.
|
||||
--
|
||||
-- Given a list of mappings [(from,to)], reorder the list so that the element
|
||||
-- at the first index (from) goes to the second index (to). You may assume
|
||||
-- that the list is ordered with respect to the first index (e.g.
|
||||
-- [(0,0),(1,1),(2,2)], [(0,1),(1,0),(2,2)], [(0,1),(1,2),(2,0)], etc.). You
|
||||
-- may also assume that for a list of length n, every number from 0 to n - 1
|
||||
-- (inclusive) appears exactly once as the first index (from) and once as the
|
||||
-- second index (to).
|
||||
--
|
||||
-- (Mappings of this kind are known as permutations in math, see
|
||||
-- https://en.wikipedia.org/wiki/Permutation)
|
||||
--
|
||||
-- Implement the function permute that performs the reordering.
|
||||
--
|
||||
-- Examples:
|
||||
-- permute [(0,0),(1,1)] [True, False] ==> [True, False]
|
||||
-- permute [(0,1),(1,0)] [True, False] ==> [False, True]
|
||||
-- permute [(0,0),(1,1),(2,2),(3,3),(4,4)] "curry" ==> "curry"
|
||||
-- permute [(0,4),(1,3),(2,2),(3,1),(4,0)] "curry" ==> "yrruc"
|
||||
-- permute [(0,2),(1,1),(2,0),(3,3),(4,4)] "curry" ==> "rucry"
|
||||
-- permute [(0,2),(1,1),(2,0)] (permute [(0,2),(1,1),(2,0)] "foo")
|
||||
-- ==> "foo"
|
||||
-- permute [(0,1),(1,0),(2,2)] (permute [(0,0),(1,2),(2,1)] [9,3,5])
|
||||
-- ==> [5,9,3]
|
||||
-- permute [(0,0),(1,2),(2,1)] (permute [(0,1),(1,0),(2,2)] [9,3,5])
|
||||
-- ==> [3,5,9]
|
||||
-- permute ([(0,0),(1,2),(2,1)] `compose` [(0,1),(1,0),(2,2)]) [9,3,5]
|
||||
-- ==> [5,9,3]
|
||||
-- permute ([(0,1),(1,0),(2,2)] `compose` [(0,0),(1,2),(2,1)]) [9,3,5]
|
||||
-- ==> [3,5,9]
|
||||
|
||||
type Permutation = [(Int,Int)]
|
||||
|
||||
permute :: Permutation -> [a] -> [a]
|
||||
permute = todo
|
||||
@@ -0,0 +1,206 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
||||
|
||||
module Set9aTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Data.List
|
||||
import Data.List.NonEmpty (NonEmpty)
|
||||
import Test.QuickCheck
|
||||
|
||||
import Set9a
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"workload",[ex1_small, ex1_medium, ex1_big])
|
||||
,(2,"echo",[ex2_examples, ex2_random])
|
||||
,(3,"countValid",[ex3])
|
||||
,(4,"repeated",[ex4_unrepeated_int, ex4_repeated_char, ex4_repeated_int])
|
||||
,(5,"sumSuccess",[ex5])
|
||||
,(6,"Lock",[ex6_examples, ex6_gen])
|
||||
,(7,"Eq Text",[ex7])
|
||||
,(8,"compose",[ex8_one_one, ex8_many_one, ex8_bijection, ex8_surjective])
|
||||
,(9,"permute",[ex9_id, ex9_compose])
|
||||
]
|
||||
|
||||
-- -- -- -- --
|
||||
|
||||
ex1_small = forAllBlind (choose (1,10)) $ \n ->
|
||||
forAllBlind (choose (0,div 9 n)) $ \h ->
|
||||
$(testing [|workload n h|]) (?=="Piece of cake!")
|
||||
ex1_medium = forAllBlind (choose (1,20)) $ \n ->
|
||||
forAllBlind (choose (div 10 n+1, div 99 n)) $ \h ->
|
||||
counterexample (show (div 10 n+1, div 99 n)) $
|
||||
$(testing [|workload n h|]) (?=="Ok.")
|
||||
ex1_big = forAllBlind (choose (1,100)) $ \n ->
|
||||
forAllBlind (choose (div 100 n+1,101)) $ \h ->
|
||||
$(testing [|workload n h|]) (?=="Holy moly!")
|
||||
|
||||
ex2_examples = conjoin' [$(testing [|echo "hello!"|]) (?=="hello!, ello!, llo!, lo!, o!, !, ")
|
||||
,$(testing [|echo "ECHO"|]) (?=="ECHO, CHO, HO, O, ")
|
||||
,$(testing [|echo "X"|]) (?=="X, ")
|
||||
,$(testing [|echo ""|]) (?=="")]
|
||||
|
||||
word = listOf1 (choose ('a','z'))
|
||||
|
||||
ex2_random = forAllBlind word $ \w ->
|
||||
$(testing [|echo w|]) . was $ \v ->
|
||||
conjoin [counterexample " number of ',' characters" $ (length (filter (==',') v)) ?== length w
|
||||
,counterexample " length of string" $ length v ?== div (length w * (length w + 1)) 2 + 2 * length w
|
||||
,let prefix = w ++ ", " ++ tail w in counterexample (" should start with "++show prefix) $ prefix `isPrefixOf` v]
|
||||
|
||||
|
||||
digit = choose ('0','9')
|
||||
|
||||
valid = do
|
||||
a <- digit
|
||||
b <- digit
|
||||
c <- digit
|
||||
d <- digit
|
||||
x <- digit
|
||||
rest <- listOf digit
|
||||
elements [a:b:x:c:x:d:rest
|
||||
,a:b:c:x:d:x:rest]
|
||||
|
||||
invalid = do
|
||||
a <- digit
|
||||
b <- digit
|
||||
c <- digit
|
||||
d <- digit
|
||||
e <- digit `suchThat` (/=c)
|
||||
f <- digit `suchThat` (/=d)
|
||||
rest <- listOf digit
|
||||
return $ a:b:c:d:e:f:rest
|
||||
|
||||
ex3 = forAllShrinkBlind (listOf valid) subterms $ \vs ->
|
||||
forAllShrinkBlind (listOf invalid) subterms $ \is ->
|
||||
forAllBlind (shuffle (vs++is)) $ \ns ->
|
||||
$(testing [|countValid ns|]) (?==length vs)
|
||||
|
||||
ex4_unrepeated_int = forAll_ $ \ls ->
|
||||
$(testing [|repeated (nub (ls :: [Int]))|]) (?==Nothing)
|
||||
|
||||
ex4_repeated_char = forAllBlind (listOf1 (choose ('a','z'))) $ \cs' ->
|
||||
let cs = nub cs'
|
||||
in forAllBlind (choose (0,length cs - 1)) $ \i ->
|
||||
let c = cs!!i
|
||||
input = take i cs ++ c : drop i cs
|
||||
in $(testing [|repeated input|]) (?==Just c)
|
||||
|
||||
ex4_repeated_int = forAll_ $ \(NonEmpty prefix') ->
|
||||
forAll_ $ \suffix ->
|
||||
let prefix = nub prefix'
|
||||
chosen = last prefix :: Int
|
||||
in $(testing [|repeated (prefix ++ chosen : suffix)|]) (?==Just chosen)
|
||||
|
||||
ex5 = property $ do
|
||||
is <- arbitrary
|
||||
ws <- listOf word
|
||||
input <- shuffle (map Left ws ++ map Right is)
|
||||
return $ $(testing [|sumSuccess input|]) (?==if null is then Left "no data" else Right (sum is))
|
||||
|
||||
ex6_examples = conjoin
|
||||
[$(testing' [|isOpen aLock|]) (?== False)
|
||||
,$(testing' [|isOpen (lock aLock)|]) (?== False)
|
||||
,$(testing' [|isOpen (open "1234" aLock)|]) (?== True)
|
||||
,$(testing' [|isOpen (lock (open "1234" aLock))|]) (?== False)
|
||||
,$(testing' [|isOpen (open "1235" aLock)|]) (?== False)
|
||||
,$(testing' [|isOpen (lock (open "1235" aLock))|]) (?== False)
|
||||
,$(testing' [|isOpen (open "1234" (changeCode "0000" aLock))|]) (?== True)
|
||||
,$(testing' [|isOpen (open "0000" (changeCode "0000" aLock))|]) (?== False)
|
||||
,$(testing' [|isOpen (open "0000" (lock (changeCode "0000" (open "1234" aLock))))|]) (?== True)
|
||||
,$(testing' [|isOpen (open "1234" (lock (changeCode "0000" (open "1234" aLock))))|]) (?== False)]
|
||||
|
||||
ex6_gen = property $ do
|
||||
code <- vectorOf 5 digit
|
||||
wrong <- vectorOf 5 digit `suchThat` (/=code)
|
||||
return $
|
||||
counterexample ("with code = " ++ show code) $
|
||||
conjoin [$(testing' [|isOpen (changeCode code (open "1234" aLock))|]) (?== True)
|
||||
,$(testing' [|isOpen (lock (changeCode code (open "1234" aLock)))|]) (?== False)
|
||||
,$(testing' [|isOpen (lock (lock (changeCode code (open "1234" aLock))))|]) (?== False)
|
||||
,$(testing' [|isOpen (open code (lock (changeCode code (open "1234" aLock))))|]) (?== True)
|
||||
,$(testing' [|isOpen (open code (open code (lock (changeCode code (open "1234" aLock)))))|]) (?== True)]
|
||||
.&&.
|
||||
counterexample ("with wrong = " ++ show wrong)
|
||||
(conjoin [$(testing' [|isOpen (open wrong (lock (changeCode code (open "1234" aLock))))|]) (?== False)
|
||||
,$(testing' [|isOpen (open code (lock (changeCode code (changeCode wrong (open "1234" aLock)))))|]) (?== True)
|
||||
,$(testing' [|isOpen (open wrong (lock (changeCode code (changeCode wrong (open "1234" aLock)))))|]) (?== False)
|
||||
,$(testing' [|isOpen (open wrong (open code (lock (changeCode code (open "1234" aLock)))))|]) (?== True)
|
||||
,$(testing' [|isOpen (open code (open wrong (lock (changeCode code (open "1234" aLock)))))|]) (?== True)])
|
||||
|
||||
spacify [] = elements [" ","\n",""]
|
||||
spacify (c:cs) = frequency [(8, fmap (c:) (spacify cs))
|
||||
,(2, fmap (' ':) (spacify (c:cs)))
|
||||
,(1, fmap ('\n':) (spacify (c:cs)))]
|
||||
|
||||
change [] = do
|
||||
c <- choose ('a','z')
|
||||
return [c]
|
||||
change (c:cs) = oneof [fmap (:cs) $ choose ('a','z') `suchThat` (/=c)
|
||||
,fmap (c:) $ change cs]
|
||||
|
||||
ex7 = $(withInstance "Eq" "Text" [|(==) :: Text -> Text -> Bool|]) $ \(==) ->
|
||||
property $ do
|
||||
bare <- word
|
||||
v1 <- spacify bare
|
||||
v2 <- spacify bare
|
||||
wrong <- change v2
|
||||
return $ conjoin [$(testing [|Text bare == Text v1|]) (?==True)
|
||||
,$(testing [|Text v1 == Text bare|]) (?==True)
|
||||
,$(testing [|Text v1 == Text v1|]) (?==True)
|
||||
,$(testing [|Text v1 == Text v2|]) (?==True)
|
||||
,$(testing [|Text wrong == Text v2|]) (?==False)
|
||||
,$(testing [|Text bare == Text wrong|]) (?==False)]
|
||||
|
||||
ex8_one_one = forAll_ $ \(x::Int) ->
|
||||
forAll_ $ \(y::Char) ->
|
||||
forAll_ $ \(z::String) ->
|
||||
$(testing [|compose [(x,y)] [(y,z)]|]) (?==[(x,z)])
|
||||
|
||||
ex8_many_one = forAll_ $ \(x::Int) ->
|
||||
forAll_ $ \(y::String) ->
|
||||
forAll_ $ \(z::Int) ->
|
||||
forAll_ $ \pairs ->
|
||||
let pairs' = (x,y):filter (\(k,v) -> k/=x && v/=y) pairs
|
||||
in forAllBlind (shuffle pairs') $ \pairs'' ->
|
||||
$(testing [|compose pairs'' [(y,z)]|]) (?==[(x,z)])
|
||||
|
||||
ex8_bijection = forAllShrink_ (choose (1,10)) $ \n ->
|
||||
forAllBlind (shuffle [1..n::Int]) $ \ys ->
|
||||
forAllBlind (shuffle [1..n::Int]) $ \zs ->
|
||||
forAllBlind (shuffle (zip [1..n] ys)) $ \xys ->
|
||||
forAllBlind (shuffle (zip ys zs)) $ \yzs ->
|
||||
$(testing [|compose xys yzs|]) (hasElements (zip [1..n] zs))
|
||||
|
||||
ex8_surjective = forAllShrink_ (choose (2,5)) $ \n ->
|
||||
forAllShrink_ (choose (2,5)) $ \k ->
|
||||
forAllBlind (vector n) $ \(output::[Int]) ->
|
||||
let xs = take (n*k) ['a'..]
|
||||
xys = zip xs (cycle [1..n])
|
||||
yzs = zip [1..n] output
|
||||
expected = zip xs (cycle output)
|
||||
in forAllBlind (shuffle xys) $ \xys' ->
|
||||
forAllBlind (shuffle yzs) $ \yzs' ->
|
||||
$(testing [|compose xys' yzs'|]) (hasElements expected)
|
||||
|
||||
ex9_id = property $ do
|
||||
n <- choose (1,5)
|
||||
let id = [(i,i) | i <- [0..n-1]]
|
||||
xs <- shuffle (take n "abcdefghij")
|
||||
return $ $(testing [|permute id xs|]) (?== xs)
|
||||
|
||||
ex9_compose = property $ do
|
||||
n <- choose (2,5)
|
||||
p <- return . zip [0..n-1] =<< shuffle [0..n-1]
|
||||
q <- return . zip [0..n-1] =<< shuffle [0..n-1]
|
||||
xs <- shuffle (take n "abcdefghij")
|
||||
return $ counterexample
|
||||
("permute (compose p q) xs == permute q (permute p xs) failed:\n\
|
||||
\ p was " ++ show p ++ "\n q was " ++ show q ++ ", and\n xs \
|
||||
\was " ++ show xs ++ ";\n permute (compose p q) xs evaluated to " ++
|
||||
show (permute (compose p q) xs) ++ ",\n while \
|
||||
\permute q (permute p xs) evaluated to " ++
|
||||
show (permute q (permute p xs)))
|
||||
(permute (compose p q) xs == permute q (permute p xs))
|
||||
@@ -0,0 +1,377 @@
|
||||
module Set9b where
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
import Data.List
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 1: In this exercise set, we'll solve the N Queens problem step by step.
|
||||
-- N Queens is a generalisation of the Eight Queens problem described in
|
||||
-- Wikipedia: https://en.wikipedia.org/wiki/Eight_queens_puzzle
|
||||
--
|
||||
-- We'll be working with a two-dimensional coordinate system for indexing the
|
||||
-- queens on a chessboard of arbitrary size. (1,1) represents the top left
|
||||
-- corner. (1,2) is the next square on the top row, (1,3) is the one after that,
|
||||
-- (2,1) is the first square on the second row, (2,2) is the second square in
|
||||
-- the second row, and so on. In general, the coordinates are of the form
|
||||
-- (row,column). The idea is that the following arrangement of queens on a 8x8
|
||||
-- board will be encoded as the list [(1,8),(2,6),(3,4),(5,7)] of coordinates:
|
||||
--
|
||||
-- .......Q
|
||||
-- .....Q..
|
||||
-- ...Q....
|
||||
-- ........
|
||||
-- ......Q.
|
||||
-- ........
|
||||
-- ........
|
||||
-- ........
|
||||
--
|
||||
-- The first exercise is warmup. We'll define two helper functions that we're
|
||||
-- going to use later: nextRow, and nextCol. nextRow increases the row by one
|
||||
-- and sets column to 1. nextCol only increases the column by one. (By analogy,
|
||||
-- nextRow works like line break and carriage return while nextCol works like
|
||||
-- the space bar in a typewriter.)
|
||||
--
|
||||
-- Examples:
|
||||
-- nextRow (1,1) ==> (2,1)
|
||||
-- nextRow (4,7) ==> (5,1)
|
||||
-- nextCol (1,1) ==> (1,2)
|
||||
-- nextCol (4,7) ==> (4,8)
|
||||
--
|
||||
-- Before we start, remember type aliases? We define some of them just to make
|
||||
-- the roles of different function arguments clearer without adding syntactical
|
||||
-- overhead:
|
||||
|
||||
type Row = Int
|
||||
type Col = Int
|
||||
type Coord = (Row, Col)
|
||||
|
||||
nextRow :: Coord -> Coord
|
||||
nextRow (i,j) = todo
|
||||
|
||||
nextCol :: Coord -> Coord
|
||||
nextCol (i,j) = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 2: Implement the function prettyPrint that, given the size of the
|
||||
-- chessboard and a list of distinct coordinates of queens, prints the
|
||||
-- chessboard with the queens on it. Empty squares must be printed as '.'s and
|
||||
-- queens as 'Q's. The special line break character '\n' must be appended to the
|
||||
-- end of each row.
|
||||
--
|
||||
-- Examples:
|
||||
-- prettyPrint 3 [(1,1),(2,3),(3,2)] ==> "Q..\n..Q\n.Q.\n"
|
||||
-- prettyPrint 3 [(2,3),(1,1),(3,2)] ==> "Q..\n..Q\n.Q.\n"
|
||||
-- prettyPrint 3 [(1,3),(2,1),(3,2)] ==> "..Q\nQ..\n.Q.\n"
|
||||
--
|
||||
-- To see how the result looks like with the line breaks correctly printed, use
|
||||
-- putStrLn in GHCI. To open this module in GHCI, run 'stack ghci Set9b.hs'.
|
||||
--
|
||||
-- Examples:
|
||||
-- *Set9b> putStrLn $ prettyPrint 4 [(1,1),(1,4),(4,1),(4,4)]
|
||||
-- Q..Q
|
||||
-- ....
|
||||
-- ....
|
||||
-- Q..Q
|
||||
--
|
||||
-- *Set9b> putStrLn $ prettyPrint 4 [(4,4),(1,4),(1,1),(4,1)]
|
||||
-- Q..Q
|
||||
-- ....
|
||||
-- ....
|
||||
-- Q..Q
|
||||
--
|
||||
-- *Set9b> putStrLn $ prettyPrint 7 [(1,1),(2,3),(3,5),(4,7),(5,2),(6,4),(7,6)]
|
||||
-- Q......
|
||||
-- ..Q....
|
||||
-- ....Q..
|
||||
-- ......Q
|
||||
-- .Q.....
|
||||
-- ...Q...
|
||||
-- .....Q.
|
||||
--
|
||||
-- Hint: Remember the function elem? elem x xs checks if the list xs contains
|
||||
-- the element x, e.g. elem 1 [2,5,1] ==> True, elem 1 [2,5,2] ==> False.
|
||||
--
|
||||
-- Challenge: Try defining prettyPrint without elem by just iterating over all
|
||||
-- coordinates one at a time. (For those who've had a course in data structures
|
||||
-- and algorithms, this challenge is about finding an O(n^2) solution in terms
|
||||
-- of the width (or height) n of the chess board; the naïve solution with elem
|
||||
-- takes O(n^3) time. Just ignore the previous sentence, if you're not familiar
|
||||
-- with the O-notation.)
|
||||
prettyPrint :: Size -> [Coord] -> String
|
||||
prettyPrint = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 3: The task in this exercise is to define the relations sameRow, sameCol,
|
||||
-- sameDiag, and sameAntidiag that check whether or not two coordinates of the
|
||||
-- form (i,j) :: (Row, Col) on a table of indeterminate size are on the same
|
||||
-- column, diagonal (top left to bottom right), or antidiagonal (bottom left to
|
||||
-- top right) respectively. Indeterminate size of the table means that these
|
||||
-- relations should work for tables of all sizes. (You may assume that all
|
||||
-- coordinates will be positive.)
|
||||
--
|
||||
-- Examples:
|
||||
-- sameRow (1,1) (1,1) ==> True
|
||||
-- sameRow (1,1) (2,1) ==> False
|
||||
-- sameRow (1,1) (1,2) ==> True
|
||||
-- sameCol (1,1) (4,1) ==> True
|
||||
-- sameCol (1,1) (4,2) ==> False
|
||||
-- sameDiag (1,1) (2,2) ==> True
|
||||
-- sameDiag (1,1) (1,2) ==> False
|
||||
-- sameAntidiag (1,1) (1,2) ==> False
|
||||
-- sameAntidiag (2,10) (5,7) ==> True
|
||||
-- sameAntidiag (500,5) (5,500) ==> True
|
||||
|
||||
sameRow :: Coord -> Coord -> Bool
|
||||
sameRow (i,j) (k,l) = todo
|
||||
|
||||
sameCol :: Coord -> Coord -> Bool
|
||||
sameCol (i,j) (k,l) = todo
|
||||
|
||||
sameDiag :: Coord -> Coord -> Bool
|
||||
sameDiag (i,j) (k,l) = todo
|
||||
|
||||
sameAntidiag :: Coord -> Coord -> Bool
|
||||
sameAntidiag (i,j) (k,l) = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 4: In chess, a queen may capture another piece in the same row, column,
|
||||
-- diagonal, or antidiagonal in one step. This danger zone, where pieces can be
|
||||
-- captured by a queen (indicated here with the character '#') looks like this:
|
||||
--
|
||||
-- .#.#.#..
|
||||
-- ..###...
|
||||
-- ###Q####
|
||||
-- ..###...
|
||||
-- .#.#.#..
|
||||
-- #..#..#.
|
||||
-- ...#...#
|
||||
-- ...#....
|
||||
--
|
||||
-- For multiple queens, the danger zone is the union of the danger zones for
|
||||
-- individual queens. This means that all coordinates belonging to the danger
|
||||
-- zones of one or more individual queens also belongs to the collective danger
|
||||
-- zone of all queens on the board. For example, if we add a second queen to the
|
||||
-- coordinates (4,6), the danger zone grows:
|
||||
--
|
||||
-- .###.#..
|
||||
-- ..####.#
|
||||
-- ###Q####
|
||||
-- #####Q##
|
||||
-- .#.####.
|
||||
-- #..#.###
|
||||
-- ..##.#.#
|
||||
-- .#.#.#..
|
||||
--
|
||||
-- Implement the function danger that checks if a coordinate belongs to the
|
||||
-- collective danger zone of the given list of (coordinates of) queens.
|
||||
-- Graphically speaking, we want to check if the square at the given coordinates
|
||||
-- looks like '.' rather than '#'. (You may assume that the given coordinate
|
||||
-- will be different from all the coordinates in the stack.)
|
||||
--
|
||||
-- Examples:
|
||||
-- danger (5,2) [] ==> False
|
||||
-- danger (5,2) [(1,2)] ==> True
|
||||
-- danger (5,2) [(4,3)] ==> True
|
||||
-- danger (4,5) [(3,4),(4,6)] ==> True
|
||||
-- danger (5,3) [(3,4),(4,6)] ==> False
|
||||
-- danger (5,3) [(3,4),(4,6),(7,5),(6,2),(8,1)] ==> True
|
||||
--
|
||||
-- Hint: Use the relations of the previous exercise!
|
||||
--
|
||||
-- Lists of coordinates of queens will be later used in a First in Last Out
|
||||
-- (LIFO) manner, so we give this type the alias Stack:
|
||||
-- https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
|
||||
|
||||
type Size = Int
|
||||
type Candidate = Coord
|
||||
type Stack = [Coord]
|
||||
|
||||
danger :: Candidate -> Stack -> Bool
|
||||
danger = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 5: In this exercise, the task is to write a modified version of
|
||||
-- prettyPrint that marks those empty squares with '#' that are in the
|
||||
-- collective danger zone of the given stack of queens. You may assume that
|
||||
-- none of the queens in the stack are in the danger zone of another queen.
|
||||
--
|
||||
-- Examples:
|
||||
-- *Set9b> putStrLn $ prettyPrint2 3 []
|
||||
-- ...
|
||||
-- ...
|
||||
-- ...
|
||||
--
|
||||
-- *Set9b> putStrLn $ prettyPrint2 4 [(1,2),(2,4)]
|
||||
-- #Q##
|
||||
-- ###Q
|
||||
-- .###
|
||||
-- .#.#
|
||||
--
|
||||
-- *Set9b> putStrLn $ prettyPrint2 9 [(5,5)]
|
||||
-- #...#...#
|
||||
-- .#..#..#.
|
||||
-- ..#.#.#..
|
||||
-- ...###...
|
||||
-- ####Q####
|
||||
-- ...###...
|
||||
-- ..#.#.#..
|
||||
-- .#..#..#.
|
||||
-- #...#...#
|
||||
--
|
||||
-- (For those that did the challenge in exercise 2, there's probably no O(n^2)
|
||||
-- solution to this version. Any working solution is okay in this exercise.)
|
||||
|
||||
prettyPrint2 :: Size -> Stack -> String
|
||||
prettyPrint2 = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 6: Now that we can check if a piece can be safely placed into a square in
|
||||
-- the chessboard, it's time to write the first piece of the actual solution.
|
||||
--
|
||||
-- Given the size of the chessboard and a stack, the function fixFirst
|
||||
-- should take the queen on the top of the stack, and if it is in in
|
||||
-- danger, move it right (in the direction of increasing columns)
|
||||
-- until it is not in danger.
|
||||
--
|
||||
-- If no safe spot is found for the queen, fixFirst should return Nothing.
|
||||
--
|
||||
-- Examples:
|
||||
-- fixFirst 5 [(1,1)] ==> Just [(1,1)]
|
||||
-- fixFirst 5 [(3,4)] ==> Just [(3,4)]
|
||||
-- fixFirst 5 [(1,1),(1,5)] ==> Nothing
|
||||
-- fixFirst 5 [(1,1),(3,3)] ==> Just [(1,2),(3,3)]
|
||||
-- fixFirst 5 [(1,3),(3,3)] ==> Just [(1,4),(3,3)]
|
||||
-- fixFirst 5 [(2,1),(3,3)] ==> Just [(2,1),(3,3)]
|
||||
-- fixFirst 8 [(8,1),(1,1)] ==> Just [(8,2),(1,1)]
|
||||
-- fixFirst 8 [(4,1),(3,4),(4,6)] ==> Nothing
|
||||
-- fixFirst 8 [(6,1),(3,4),(4,6)] ==> Just [(6,2),(3,4),(4,6)]
|
||||
-- fixFirst 8 [(5,1),(3,8),(4,6),(7,5),(6,2),(8,1)] ==> Nothing
|
||||
--
|
||||
-- Hint: Remember prettyPrint and prettyPrint2? They might be useful
|
||||
-- for debugging. For example we can run this to see what's happening
|
||||
-- in that last example. The whole fifth row is in danger zone.
|
||||
--
|
||||
-- putStrLn $ prettyPrint2 8 [(3,8),(4,6),(7,5),(6,2),(8,1)]
|
||||
-- ###.####
|
||||
-- ##.#####
|
||||
-- #######Q
|
||||
-- #####Q##
|
||||
-- ########
|
||||
-- #Q######
|
||||
-- ####Q###
|
||||
-- Q#######
|
||||
|
||||
fixFirst :: Size -> Stack -> Maybe Stack
|
||||
fixFirst n s = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 7: We need two helper functions for stack management.
|
||||
--
|
||||
-- * continue moves on to a new row. It pushes a new candidate to the
|
||||
-- top of the stack (front of the list). The new candidate should be
|
||||
-- at the beginning of the next row with respect to the queen
|
||||
-- previously on top of the stack.
|
||||
--
|
||||
-- * backtrack moves back to the previous row. It removes the top
|
||||
-- element of the stack, and adjusts the new top element so that it
|
||||
-- is in the next column.
|
||||
--
|
||||
-- Examples:
|
||||
-- continue [(1,1)] ==> [(2,1),(1,1)]
|
||||
-- continue [(2,3),(1,1)] ==> [(3,1),(2,3),(1,1)]
|
||||
-- backtrack [(8,1),(7,5),(6,2),(4,6),(3,4)] ==> [(7,6),(6,2),(4,6),(3,4)]
|
||||
--
|
||||
-- Hint: Remember nextRow and nextCol? Use them!
|
||||
|
||||
continue :: Stack -> Stack
|
||||
continue s = todo
|
||||
|
||||
backtrack :: Stack -> Stack
|
||||
backtrack s = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 8: Let's take a step. Our algorithm solves the problem (in a
|
||||
-- greedy manner) one row at a time, backtracking when needed. The
|
||||
-- reason why we need backtracking is the following. We can greedily
|
||||
-- put the queens to (1,1) and (2,3) and end up with no safe spot on
|
||||
-- the third row:
|
||||
--
|
||||
-- Q###
|
||||
-- ##Q#
|
||||
-- ####
|
||||
-- #.##
|
||||
--
|
||||
-- However if we backtrack and move the queen from (2,3) to (2,4), we
|
||||
-- are able to place the third queen:
|
||||
--
|
||||
-- Q###
|
||||
-- ###Q
|
||||
-- #.##
|
||||
-- ##.#
|
||||
--
|
||||
-- Implement the function step that takes the size of a board and a
|
||||
-- stack, and tries to fix the position of the queen on the top of the
|
||||
-- stack (using fixFirst). If a new position is found, the function
|
||||
-- should call continue to return a stack with a new candidate. If a
|
||||
-- safe position is not found, the function should call backtrack to
|
||||
-- return a new stack.
|
||||
--
|
||||
-- Examples:
|
||||
--
|
||||
-- The first candidate is safe so we continue directly:
|
||||
-- step 4 [(1,1)] ==> [(2,1),(1,1)]
|
||||
--
|
||||
-- Q... Q...
|
||||
-- .... ==> Q...
|
||||
-- .... ....
|
||||
-- .... ....
|
||||
--
|
||||
-- The second candidate needs to be adjusted a bit before a third is added:
|
||||
-- step 4 [(2,1),(1,1)] ==> [(3,1),(2,3),(1,1)]
|
||||
--
|
||||
-- Q... Q...
|
||||
-- Q... ==> ..Q.
|
||||
-- .... Q...
|
||||
-- .... ....
|
||||
--
|
||||
-- No safe position is found for the third queen so we backtrack:
|
||||
-- step 4 [(3,1),(2,3),(1,1)] ==> [(2,4),(1,1)]
|
||||
--
|
||||
-- Q... Q...
|
||||
-- ..Q. ==> ...Q
|
||||
-- Q... ....
|
||||
-- .... ....
|
||||
--
|
||||
-- The new position of the second queen is ok so we move to the third row:
|
||||
-- step 4 [(2,4),(1,1)] ==> [(3,1),(2,4),(1,1)]
|
||||
--
|
||||
-- Q... Q...
|
||||
-- ...Q ==> ...Q
|
||||
-- .... Q...
|
||||
-- .... ....
|
||||
--
|
||||
-- More examples:
|
||||
-- step 8 [(3,9),(4,6),(7,5),(6,2),(8,1)] ==> [(4,7),(7,5),(6,2),(8,1)]
|
||||
-- step 8 [(4,7),(7,5),(6,2),(8,1)] ==> [(5,1),(4,7),(7,5),(6,2),(8,1)]
|
||||
|
||||
step :: Size -> Stack -> Stack
|
||||
step = todo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Ex 8: Let's solve our puzzle! The function finish takes a partial
|
||||
-- solution (stack) and repeatedly step until a complete solution is
|
||||
-- found.
|
||||
--
|
||||
-- Reminder: a complete solution has n queens that don't threaten each
|
||||
-- other. One easy way to know you have a valid solution is when step
|
||||
-- adds the (n+1)th queen.
|
||||
--
|
||||
-- After this, it's just a matter of calling `finish n [(1,1)]` to
|
||||
-- solve the n queens problem.
|
||||
|
||||
finish :: Size -> Stack -> Stack
|
||||
finish = todo
|
||||
|
||||
solve :: Size -> Stack
|
||||
solve n = finish n [(1,1)]
|
||||
@@ -0,0 +1,414 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
module Set9bTest where
|
||||
|
||||
import Mooc.Test
|
||||
import Mooc.Th
|
||||
|
||||
import Data.List
|
||||
import qualified Data.Set as S
|
||||
import Test.QuickCheck
|
||||
|
||||
import Set9b
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [ (1, "warmup", [ ex1_nextRow, ex1_nextCol ])
|
||||
, (2, "prettyPrint", [ ex2_examples, ex2_size, ex2_content, ex2_comm
|
||||
, ex2_correctness ])
|
||||
, (3, "relations", [ ex3_sameCol_pos, ex3_sameCol_neg
|
||||
, ex3_sameDiag_pos, ex3_sameDiag_neg
|
||||
, ex3_sameAntidiag_pos, ex3_sameAntidiag_neg ])
|
||||
, (4, "danger", [ ex4_danger, ex4_danger_neg ])
|
||||
, (5, "prettyPrint2", [ ex5_size, ex5_content, ex5_comm
|
||||
, ex5_correctness ])
|
||||
, (6, "fixFirst", [ ex6_fixFirst_safeZone, ex6_fixFirst_dangerZone ])
|
||||
, (7, "stackOps", [ ex7_continue, ex7_backtrack ])
|
||||
, (8, "nqueens_step", [ ex8_step_4, ex8_step_continue, ex8_step_backtrack ])
|
||||
, (9, "nqueens_finish", [ ex9_finish_small, ex9_finish_medium, ex9_finish_large ])
|
||||
]
|
||||
|
||||
-- -- -- -- --
|
||||
|
||||
size :: Coord -> Size
|
||||
size (i,j) = foldr max 0 [8, i, j]
|
||||
|
||||
coord :: Gen (Int, Int)
|
||||
coord = do
|
||||
(Positive i, Positive j) <- arbitrary :: Gen (Positive Int, Positive Int)
|
||||
return (i, j)
|
||||
|
||||
boundedCoord :: Size -> Gen Coord
|
||||
boundedCoord n = do
|
||||
i <- choose (1,n)
|
||||
j <- choose (1,n)
|
||||
return (i,j)
|
||||
|
||||
board :: Gen (Size, [Coord])
|
||||
board = do
|
||||
n <- choose (5,10)
|
||||
k <- choose (1,10)
|
||||
xs <- vectorOf k (boundedCoord n)
|
||||
let xs' = nub xs
|
||||
return (n, xs')
|
||||
|
||||
dangerZone :: Size -> Coord -> [Coord]
|
||||
dangerZone n (i,j) =
|
||||
let dis = [-i + 1 .. n - i]
|
||||
djs = [-j + 1 .. n - j]
|
||||
in [ (i + di, j + dj)
|
||||
| di <- dis, dj <- djs
|
||||
, di == dj || di == -dj || di * dj == 0
|
||||
]
|
||||
|
||||
safeZone :: Size -> Coord -> [Coord]
|
||||
safeZone n (i,j) =
|
||||
let dis = [-i + 1 .. n - i]
|
||||
djs = [-j + 1 .. n - j]
|
||||
in [ (i + di, j + dj)
|
||||
| di <- dis, dj <- djs
|
||||
, di /= dj, di /= -dj, di * dj /= 0
|
||||
]
|
||||
|
||||
full :: Size -> [Coord]
|
||||
full n = [(i,j) | i <- [1..n], j <- [1..n]]
|
||||
|
||||
queens :: Size -> Int -> Gen ([Coord], [Coord], [Coord])
|
||||
queens n 0 = return ([], [], full n)
|
||||
queens n k = do
|
||||
(qs, dz, sz) <- queens n (k - 1)
|
||||
case sz of
|
||||
[] -> return (qs, dz, sz)
|
||||
_ -> do q <- elements sz
|
||||
let qs' = q:qs
|
||||
let dz' = dz `union` dangerZone n q
|
||||
let sz' = sz `intersect` safeZone n q
|
||||
return (qs', dz', sz')
|
||||
|
||||
stack :: Gen Stack
|
||||
stack = do
|
||||
cs <- listOf1 arbitrary :: Gen [(Positive Int, Positive Int)]
|
||||
return $ map (\(Positive i, Positive j) -> (i,j)) cs
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
ex1_nextRow = property $ do
|
||||
(i,j) <- coord
|
||||
return $ $(testing [| nextRow (i,j) |]) (?== (i + 1, 1))
|
||||
|
||||
ex1_nextCol = property $ do
|
||||
(i,j) <- coord
|
||||
return $ $(testing [| nextCol (i,j) |]) (?== (i, j + 1))
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
ex2_examples = conjoin [$(testing [|prettyPrint 3 [(1,1),(2,3),(3,2)]|]) (?=="Q..\n..Q\n.Q.\n")
|
||||
,$(testing [|prettyPrint 3 [(2,3),(1,1),(3,2)]|]) (?=="Q..\n..Q\n.Q.\n")
|
||||
,$(testing [|prettyPrint 3 [(1,3),(2,1),(3,2)]|]) (?=="..Q\nQ..\n.Q.\n")]
|
||||
|
||||
ex2_size = property $ do
|
||||
(n, xs) <- board
|
||||
let ys = lines $ prettyPrint n xs
|
||||
return $ $(testing [| prettyPrint n xs |]) $ \out ->
|
||||
let ys = lines out
|
||||
in conjoin [ counterexample " number of lines in output" $
|
||||
length ys ?== n
|
||||
, counterexample " length of output lines" $
|
||||
map length ys ?== replicate n n ]
|
||||
|
||||
ex2_content = property $ do
|
||||
(n, xs) <- board
|
||||
let ys = prettyPrint n xs
|
||||
return $ $(testing [| prettyPrint n xs |]) $ \out ->
|
||||
counterexample " characters in output" $
|
||||
sort (nub out) ?== (if null xs then "\n." else "\n.Q")
|
||||
|
||||
ex2_comm = property $ do
|
||||
(n, xs) <- board
|
||||
xs' <- shuffle xs
|
||||
return $ counterexample
|
||||
("prettyPrint " ++ show n ++ " " ++ show xs ++ " == " ++
|
||||
"prettyPrint " ++ show n ++ " " ++ show xs' ++
|
||||
"\n Expected: True\n Was: False")
|
||||
(prettyPrint n xs == prettyPrint n xs')
|
||||
|
||||
ex2_correctness = property $ do
|
||||
(n, xs) <- board
|
||||
let m = S.fromList xs
|
||||
let ys = lines $ prettyPrint n xs
|
||||
let check _ [] = True
|
||||
check (i,j) ("":rows) = check (i + 1, 1) rows
|
||||
check (i,j) ((char:row):rows)
|
||||
| char == 'Q' = S.member (i,j) m && check (i, j + 1) (row:rows)
|
||||
| char == '.' = (not (S.member (i,j) m)) && check (i, j + 1) (row:rows)
|
||||
| otherwise = False
|
||||
return $ counterexample
|
||||
("prettyPrint " ++ show n ++ " " ++ show xs ++
|
||||
" didn't mark the queens and/or empty cells correctly.\n" ++
|
||||
"The return value was:\n " ++ show (prettyPrint n xs))
|
||||
(check (1,1) ys)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
ex3_sameCol_pos = property $ do
|
||||
(i,j) <- coord
|
||||
let xs = [(i + k, j) | k <- [0..9]]
|
||||
x <- elements xs
|
||||
y <- elements xs
|
||||
return $ $(testing [| sameCol x y |]) (?== True)
|
||||
|
||||
ex3_sameCol_neg = property $ do
|
||||
(i,j) <- coord
|
||||
let xs = [(i, j + k) | k <- [1..10]]
|
||||
x <- elements xs
|
||||
return $ $(testing [| sameCol (i,j) x |]) (?== False)
|
||||
|
||||
ex3_sameDiag_pos = property $ do
|
||||
(i,j) <- coord
|
||||
let xs = [(i + k, j + k) | k <- [0..9]]
|
||||
x <- elements xs
|
||||
y <- elements xs
|
||||
return $ $(testing [| sameDiag x y |]) (?== True)
|
||||
|
||||
ex3_sameDiag_neg = property $ do
|
||||
(i,j) <- coord
|
||||
let xs = [(i, j + k) | k <- [1..10]]
|
||||
x <- elements xs
|
||||
return $ $(testing [| sameDiag (i,j) x |]) (?== False)
|
||||
|
||||
ex3_sameAntidiag_pos = property $ do
|
||||
(i,j) <- coord
|
||||
let xs = [ (i - k, j + k) | k <- [0..min i 10] ]
|
||||
x <- elements xs
|
||||
y <- elements xs
|
||||
return $ $(testing [| sameAntidiag x y |]) (?== True)
|
||||
|
||||
ex3_sameAntidiag_neg = property $ do
|
||||
(i,j) <- coord
|
||||
let xs = [(i, j + k) | k <- [1..10]]
|
||||
x <- elements xs
|
||||
return $ $(testing [| sameAntidiag (i,j) x |]) (?== False)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
ex4_danger = property $ do
|
||||
(i,j) <- coord
|
||||
let n = size (i,j)
|
||||
let xs = dangerZone n (i,j)
|
||||
x <- elements xs
|
||||
return $ $(testing [| danger x [(i,j)] |]) (?== True)
|
||||
|
||||
ex4_danger_neg = property $ do
|
||||
(i,j) <- coord
|
||||
let n = size (i,j)
|
||||
let xs = safeZone n (i,j)
|
||||
x <- elements xs
|
||||
return $ $(testing [| danger x [(i,j)] |]) (?== False)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
ex5_size = property $ do
|
||||
n <- choose (5,10) :: Gen Int
|
||||
let k = n `div` 2
|
||||
(qs, _, _) <- queens n k
|
||||
return $ $(testing [| prettyPrint2 n qs |]) $ \out ->
|
||||
let ys = lines out
|
||||
in conjoin [ counterexample " number of lines in output" $
|
||||
length ys ?== n
|
||||
, counterexample " length of output lines" $
|
||||
map length ys ?== replicate n n ]
|
||||
|
||||
ex5_content = property $ do
|
||||
n <- choose (5,10) :: Gen Int
|
||||
let k = n `div` 2
|
||||
(qs, _, _) <- queens n k
|
||||
return $ $(testing [| prettyPrint2 n qs |]) $ \out ->
|
||||
counterexample " characters in output" $
|
||||
sort (nub out) ?== (if null qs then "\n." else "\n#.Q")
|
||||
|
||||
ex5_comm = property $ do
|
||||
n <- choose (5,10) :: Gen Int
|
||||
let k = n `div` 2
|
||||
(qs, dz, _) <- queens n k
|
||||
qs' <- shuffle qs
|
||||
return $ counterexample
|
||||
("prettyPrint2 " ++ show n ++ " " ++ show qs ++ " == " ++
|
||||
"prettyPrint2 " ++ show n ++ " " ++ show qs' ++
|
||||
"\n Expected: True\n Was: False")
|
||||
(prettyPrint2 n qs == prettyPrint2 n qs')
|
||||
|
||||
ex5_correctness = property $ do
|
||||
n <- choose (5,10) :: Gen Int
|
||||
let k = n `div` 2
|
||||
(qs, dz, _) <- queens n k
|
||||
let q = S.fromList qs
|
||||
let d = S.fromList dz
|
||||
let xs = lines $ prettyPrint2 n qs
|
||||
let check _ [] = True
|
||||
check (i,j) ("":rows) = check (i + 1, 1) rows
|
||||
check (i,j) ((char:row):rows)
|
||||
| char == 'Q' = S.member (i,j) q &&
|
||||
check (i, j + 1) (row:rows)
|
||||
| char == '#' = not (S.member (i,j) q) &&
|
||||
S.member (i,j) d &&
|
||||
check (i, j + 1) (row:rows)
|
||||
| char == '.' = not (S.member (i,j) q) &&
|
||||
not (S.member (i,j) d) &&
|
||||
check (i, j + 1) (row:rows)
|
||||
| otherwise = False
|
||||
return $ counterexample
|
||||
("prettyPrint2 " ++ show n ++ " " ++ show qs ++
|
||||
" didn't mark the queens and/or empty cells correctly.\n" ++
|
||||
"The return value was:\n " ++ show (prettyPrint2 n qs))
|
||||
(check (1,1) xs)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
ex6_fixFirst_safeZone = property $ do
|
||||
n <- choose (5,10) :: Gen Int
|
||||
let k = n `div` 2
|
||||
(qs, dz, sz) <- queens n k
|
||||
case sz of
|
||||
[] -> return $ property True
|
||||
_ -> do q <- elements sz
|
||||
return $ $(testing [| fixFirst n (q:qs) |]) (?== Just (q:qs))
|
||||
|
||||
ex6_fixFirst_dangerZone = property $ do
|
||||
n <- choose (5,10) :: Gen Int
|
||||
let k = n `div` 2
|
||||
(qs, dz, sz) <- queens n k
|
||||
q@(i,j) <- elements dz
|
||||
return $ $(testing [| fixFirst n (q:qs) |]) $ \x -> case x of
|
||||
x@(Just (q':qs')) -> conjoin [
|
||||
counterexample
|
||||
(" returned " ++ show x ++ ", but\n " ++ show q' ++
|
||||
" is in danger")
|
||||
(q' `elem` sz)
|
||||
, counterexample
|
||||
(" returned " ++ show x ++ ", but\n " ++ show qs' ++
|
||||
" was not " ++ show qs)
|
||||
(qs' == qs) ]
|
||||
x@(Just []) -> counterexample
|
||||
(" returned " ++ show x ++ ", but the list was empty")
|
||||
False
|
||||
Nothing -> counterexample
|
||||
(" returned Nothing, but there were safe squares on row " ++ show i ++
|
||||
": " ++ show (intersect row sz))
|
||||
(all (`elem` dz) row)
|
||||
where row = [(i,k) | k <- [j .. n]]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
ex7_continue = property $ do
|
||||
cs <- stack
|
||||
let input = show cs
|
||||
case continue cs of
|
||||
[] -> return $ counterexample
|
||||
("continue " ++ input ++ " returned []")
|
||||
False
|
||||
cs' -> return $ conjoin
|
||||
[ counterexample
|
||||
("length (continue " ++ input ++ ")")
|
||||
(length cs' ?== length cs + 1)
|
||||
, counterexample
|
||||
("fst (head (continue " ++ input ++ "))")
|
||||
(fst (head cs') ?== fst (head cs) + 1)
|
||||
, counterexample
|
||||
("snd (head (continue " ++ input ++ ")) should be positive, but \
|
||||
\it was " ++ show (snd (head cs')))
|
||||
(snd (head cs') >= 1)
|
||||
, counterexample
|
||||
("tail (continue " ++ input ++ ")")
|
||||
(tail cs' ?== cs)
|
||||
]
|
||||
|
||||
ex7_backtrack = property $ do
|
||||
cs <- stack `suchThat` ((>1).length)
|
||||
let input = show cs
|
||||
case backtrack cs of
|
||||
[] -> return $ counterexample
|
||||
("backtrack " ++ input ++ " returned []")
|
||||
False
|
||||
cs' -> return $ conjoin
|
||||
[ counterexample
|
||||
("length (backtrack " ++ input ++ ")")
|
||||
(length cs' ?== length cs - 1)
|
||||
, counterexample
|
||||
("(head (backtrack " ++ input ++ "))")
|
||||
((head cs') ?== (fst (cs!!1), snd (cs!!1) + 1))
|
||||
, counterexample
|
||||
("tail (backtrack " ++ input ++ ")")
|
||||
(tail cs' ?== tail (tail cs))
|
||||
]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
steps_4 = [[(1,1)]
|
||||
,[(2,1),(1,1)]
|
||||
,[(3,1),(2,3),(1,1)]
|
||||
,[(2,4),(1,1)]
|
||||
,[(3,1),(2,4),(1,1)]
|
||||
,[(4,1),(3,2),(2,4),(1,1)]
|
||||
,[(3,3),(2,4),(1,1)]
|
||||
,[(2,5),(1,1)]
|
||||
,[(1,2)]
|
||||
,[(2,1),(1,2)]
|
||||
,[(3,1),(2,4),(1,2)]
|
||||
,[(4,1),(3,1),(2,4),(1,2)]
|
||||
,[(5,1),(4,3),(3,1),(2,4),(1,2)]]
|
||||
|
||||
ex8_step_4 = conjoin [$(testing [|step 4 from|]) (?==to) | (from,to) <- zip steps_4 (tail steps_4)]
|
||||
|
||||
ex8_step_continue = property $ do
|
||||
n <- choose (5,10)
|
||||
k <- choose (1,n-1)
|
||||
(qs, dz, sz) <- queens n k
|
||||
let row = succ (fst (head qs))
|
||||
d = map snd $ filter ((==row).fst) dz
|
||||
s = map snd $ filter ((==row).fst) sz
|
||||
return $ not (null s) ==> do
|
||||
safec <- elements s
|
||||
let priors = takeWhile (`elem`d) [safec-1,safec-2..]
|
||||
col <- elements (safec:priors)
|
||||
return $ $(testing [|step n ((row,col):qs)|]) . was $ \res ->
|
||||
conjoin [counterexample (" length") (length res ?== length qs + 2)
|
||||
,counterexample (" index 1") ((res!!1) ?== (row,safec))
|
||||
,counterexample (" end of list") (drop 2 res ?== qs)]
|
||||
|
||||
ex8_step_backtrack = property $ do
|
||||
n <- choose (5,10)
|
||||
k <- choose (div n 2,n-1)
|
||||
(qs, dz, sz) <- queens n k
|
||||
let row = succ (fst (head qs))
|
||||
d = map snd $ filter ((==row).fst) dz
|
||||
end = takeWhile (`elem`d) [n,n-1..]
|
||||
return $ not (null end) ==> do
|
||||
col <- elements end
|
||||
return $ $(testing [|step n ((row,col):qs)|]) . was $ \res ->
|
||||
conjoin [counterexample (" length") (length res ?== length qs)
|
||||
,counterexample (" first element") (head res ?== nextCol (head qs))
|
||||
,counterexample (" end of list") (tail res ?== tail qs)]
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
m_finish_sol sol = forAllBlind (elements (init (tails sol))) $ \pre ->
|
||||
$(testing [|finish (length sol) pre|]) (?==sol)
|
||||
|
||||
ex9_finish_small = conjoin [$(testing [|finish 4 [(1,1)]|]) (?==[(4,3),(3,1),(2,4),(1,2)])
|
||||
,m_finish_sol [(4,2),(3,4),(2,1),(1,3)]
|
||||
,m_finish_sol [(4,2),(3,4),(2,1),(1,3)]
|
||||
,m_finish_sol [(5,4),(4,2),(3,5),(2,3),(1,1)]
|
||||
,m_finish_sol [(5,5),(4,3),(3,1),(2,4),(1,2)]
|
||||
,m_finish_sol [(5,5),(4,2),(3,4),(2,1),(1,3)]
|
||||
,m_finish_sol [(5,2),(4,5),(3,3),(2,1),(1,4)]
|
||||
,m_finish_sol [(5,3),(4,1),(3,4),(2,2),(1,5)]]
|
||||
|
||||
m_finish_n n = $(testing [|finish n [(1,1)]|]) . was $ \qs ->
|
||||
conjoin [ counterexample " length of list" $ length qs ?== n
|
||||
, counterexample " queens outside board" $ [] ==? [(i,j) | (i,j) <- qs, i<1 || i>n || j<1 || j>n]
|
||||
, let sz = foldr intersect (full n) . map (\q -> q : safeZone n q) $ qs
|
||||
in counterexample " these queens can capture each other: " $ (qs \\ sz) ?== []
|
||||
]
|
||||
|
||||
ex9_finish_medium = forAllBlind (choose (5,10)) m_finish_n
|
||||
ex9_finish_large = forAllBlind (choose (10,14)) m_finish_n
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="157.248pt" height="73.297pt" viewBox="0 0 157.248 73.297" version="1.1">
|
||||
<defs>
|
||||
<g>
|
||||
<symbol overflow="visible" id="glyph0-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-1">
|
||||
<path style="stroke:none;" d="M 1.171875 -2.171875 C 1.171875 -3.796875 1.984375 -4.21875 2.515625 -4.21875 C 2.609375 -4.21875 3.234375 -4.203125 3.578125 -3.84375 C 3.171875 -3.8125 3.109375 -3.515625 3.109375 -3.390625 C 3.109375 -3.125 3.296875 -2.9375 3.5625 -2.9375 C 3.828125 -2.9375 4.03125 -3.09375 4.03125 -3.40625 C 4.03125 -4.078125 3.265625 -4.46875 2.5 -4.46875 C 1.25 -4.46875 0.34375 -3.390625 0.34375 -2.15625 C 0.34375 -0.875 1.328125 0.109375 2.484375 0.109375 C 3.8125 0.109375 4.140625 -1.09375 4.140625 -1.1875 C 4.140625 -1.28125 4.03125 -1.28125 4 -1.28125 C 3.921875 -1.28125 3.890625 -1.25 3.875 -1.1875 C 3.59375 -0.265625 2.9375 -0.140625 2.578125 -0.140625 C 2.046875 -0.140625 1.171875 -0.5625 1.171875 -2.171875 Z M 1.171875 -2.171875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-2">
|
||||
<path style="stroke:none;" d="M 4.140625 -3.34375 C 4.390625 -3.984375 4.90625 -3.984375 5.0625 -3.984375 L 5.0625 -4.296875 C 4.828125 -4.28125 4.546875 -4.265625 4.3125 -4.265625 C 4.140625 -4.265625 3.671875 -4.28125 3.453125 -4.296875 L 3.453125 -3.984375 C 3.765625 -3.984375 3.921875 -3.8125 3.921875 -3.5625 C 3.921875 -3.453125 3.90625 -3.4375 3.859375 -3.3125 L 2.84375 -0.875 L 1.75 -3.546875 C 1.703125 -3.65625 1.6875 -3.6875 1.6875 -3.734375 C 1.6875 -3.984375 2.046875 -3.984375 2.25 -3.984375 L 2.25 -4.296875 C 1.984375 -4.28125 1.328125 -4.265625 1.15625 -4.265625 C 0.890625 -4.265625 0.484375 -4.28125 0.1875 -4.296875 L 0.1875 -3.984375 C 0.671875 -3.984375 0.859375 -3.984375 1 -3.640625 L 2.5 0 C 2.4375 0.125 2.296875 0.453125 2.25 0.59375 C 2.03125 1.140625 1.75 1.828125 1.109375 1.828125 C 1.0625 1.828125 0.828125 1.828125 0.640625 1.640625 C 0.953125 1.609375 1.03125 1.390625 1.03125 1.21875 C 1.03125 0.96875 0.84375 0.8125 0.609375 0.8125 C 0.40625 0.8125 0.1875 0.9375 0.1875 1.234375 C 0.1875 1.6875 0.609375 2.046875 1.109375 2.046875 C 1.734375 2.046875 2.140625 1.46875 2.375 0.90625 Z M 4.140625 -3.34375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-3">
|
||||
<path style="stroke:none;" d="M 1.765625 -6.921875 L 0.328125 -6.8125 L 0.328125 -6.5 C 1.03125 -6.5 1.109375 -6.4375 1.109375 -5.9375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.328125 -0.3125 L 0.328125 0 C 0.65625 -0.015625 1.1875 -0.03125 1.4375 -0.03125 C 1.6875 -0.03125 2.171875 -0.015625 2.546875 0 L 2.546875 -0.3125 C 1.875 -0.3125 1.765625 -0.3125 1.765625 -0.75 Z M 1.765625 -6.921875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-4">
|
||||
<path style="stroke:none;" d="M 1.109375 -2.515625 C 1.171875 -4 2.015625 -4.25 2.359375 -4.25 C 3.375 -4.25 3.484375 -2.90625 3.484375 -2.515625 Z M 1.109375 -2.296875 L 3.890625 -2.296875 C 4.109375 -2.296875 4.140625 -2.296875 4.140625 -2.515625 C 4.140625 -3.5 3.59375 -4.46875 2.359375 -4.46875 C 1.203125 -4.46875 0.28125 -3.4375 0.28125 -2.1875 C 0.28125 -0.859375 1.328125 0.109375 2.46875 0.109375 C 3.6875 0.109375 4.140625 -1 4.140625 -1.1875 C 4.140625 -1.28125 4.0625 -1.3125 4 -1.3125 C 3.921875 -1.3125 3.890625 -1.25 3.875 -1.171875 C 3.53125 -0.140625 2.625 -0.140625 2.53125 -0.140625 C 2.03125 -0.140625 1.640625 -0.4375 1.40625 -0.8125 C 1.109375 -1.28125 1.109375 -1.9375 1.109375 -2.296875 Z M 1.109375 -2.296875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-5">
|
||||
<path style="stroke:none;" d="M 2.71875 -4.453125 C 2.71875 -4.71875 2.546875 -4.984375 2.1875 -4.984375 C 1.984375 -4.984375 1.84375 -4.890625 1.78125 -4.828125 C 1.78125 -4.8125 1.765625 -4.796875 1.75 -4.796875 C 1.734375 -4.796875 1.734375 -4.9375 1.734375 -4.96875 C 1.734375 -5.296875 1.796875 -6.015625 2.4375 -6.625 C 2.546875 -6.75 2.546875 -6.765625 2.546875 -6.796875 C 2.546875 -6.875 2.5 -6.90625 2.453125 -6.90625 C 2.34375 -6.90625 1.515625 -6.15625 1.515625 -4.96875 C 1.515625 -4.375 1.75 -3.921875 2.1875 -3.921875 C 2.53125 -3.921875 2.71875 -4.203125 2.71875 -4.453125 Z M 4.640625 -4.453125 C 4.640625 -4.71875 4.46875 -4.984375 4.109375 -4.984375 C 3.921875 -4.984375 3.78125 -4.890625 3.71875 -4.828125 C 3.703125 -4.8125 3.703125 -4.796875 3.6875 -4.796875 C 3.671875 -4.796875 3.671875 -4.9375 3.671875 -4.96875 C 3.671875 -5.296875 3.734375 -6.015625 4.359375 -6.625 C 4.484375 -6.75 4.484375 -6.765625 4.484375 -6.796875 C 4.484375 -6.875 4.4375 -6.90625 4.390625 -6.90625 C 4.28125 -6.90625 3.453125 -6.15625 3.453125 -4.96875 C 3.453125 -4.375 3.6875 -3.921875 4.109375 -3.921875 C 4.46875 -3.921875 4.640625 -4.203125 4.640625 -4.453125 Z M 4.640625 -4.453125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-6">
|
||||
<path style="stroke:none;" d="M 3.3125 -0.75 C 3.359375 -0.359375 3.625 0.0625 4.09375 0.0625 C 4.3125 0.0625 4.921875 -0.078125 4.921875 -0.890625 L 4.921875 -1.453125 L 4.671875 -1.453125 L 4.671875 -0.890625 C 4.671875 -0.3125 4.421875 -0.25 4.3125 -0.25 C 3.984375 -0.25 3.9375 -0.703125 3.9375 -0.75 L 3.9375 -2.734375 C 3.9375 -3.15625 3.9375 -3.546875 3.578125 -3.921875 C 3.1875 -4.3125 2.6875 -4.46875 2.21875 -4.46875 C 1.390625 -4.46875 0.703125 -4 0.703125 -3.34375 C 0.703125 -3.046875 0.90625 -2.875 1.171875 -2.875 C 1.453125 -2.875 1.625 -3.078125 1.625 -3.328125 C 1.625 -3.453125 1.578125 -3.78125 1.109375 -3.78125 C 1.390625 -4.140625 1.875 -4.25 2.1875 -4.25 C 2.6875 -4.25 3.25 -3.859375 3.25 -2.96875 L 3.25 -2.609375 C 2.734375 -2.578125 2.046875 -2.546875 1.421875 -2.25 C 0.671875 -1.90625 0.421875 -1.390625 0.421875 -0.953125 C 0.421875 -0.140625 1.390625 0.109375 2.015625 0.109375 C 2.671875 0.109375 3.125 -0.296875 3.3125 -0.75 Z M 3.25 -2.390625 L 3.25 -1.390625 C 3.25 -0.453125 2.53125 -0.109375 2.078125 -0.109375 C 1.59375 -0.109375 1.1875 -0.453125 1.1875 -0.953125 C 1.1875 -1.5 1.609375 -2.328125 3.25 -2.390625 Z M 3.25 -2.390625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-7">
|
||||
<path style="stroke:none;" d="M 2.078125 -1.9375 C 2.296875 -1.890625 3.109375 -1.734375 3.109375 -1.015625 C 3.109375 -0.515625 2.765625 -0.109375 1.984375 -0.109375 C 1.140625 -0.109375 0.78125 -0.671875 0.59375 -1.53125 C 0.5625 -1.65625 0.5625 -1.6875 0.453125 -1.6875 C 0.328125 -1.6875 0.328125 -1.625 0.328125 -1.453125 L 0.328125 -0.125 C 0.328125 0.046875 0.328125 0.109375 0.4375 0.109375 C 0.484375 0.109375 0.5 0.09375 0.6875 -0.09375 C 0.703125 -0.109375 0.703125 -0.125 0.890625 -0.3125 C 1.328125 0.09375 1.78125 0.109375 1.984375 0.109375 C 3.125 0.109375 3.59375 -0.5625 3.59375 -1.28125 C 3.59375 -1.796875 3.296875 -2.109375 3.171875 -2.21875 C 2.84375 -2.546875 2.453125 -2.625 2.03125 -2.703125 C 1.46875 -2.8125 0.8125 -2.9375 0.8125 -3.515625 C 0.8125 -3.875 1.0625 -4.28125 1.921875 -4.28125 C 3.015625 -4.28125 3.078125 -3.375 3.09375 -3.078125 C 3.09375 -2.984375 3.1875 -2.984375 3.203125 -2.984375 C 3.34375 -2.984375 3.34375 -3.03125 3.34375 -3.21875 L 3.34375 -4.234375 C 3.34375 -4.390625 3.34375 -4.46875 3.234375 -4.46875 C 3.1875 -4.46875 3.15625 -4.46875 3.03125 -4.34375 C 3 -4.3125 2.90625 -4.21875 2.859375 -4.1875 C 2.484375 -4.46875 2.078125 -4.46875 1.921875 -4.46875 C 0.703125 -4.46875 0.328125 -3.796875 0.328125 -3.234375 C 0.328125 -2.890625 0.484375 -2.609375 0.75 -2.390625 C 1.078125 -2.140625 1.359375 -2.078125 2.078125 -1.9375 Z M 2.078125 -1.9375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-8">
|
||||
<path style="stroke:none;" d="M 3.78125 -0.546875 L 3.78125 0.109375 L 5.25 0 L 5.25 -0.3125 C 4.5625 -0.3125 4.46875 -0.375 4.46875 -0.875 L 4.46875 -6.921875 L 3.046875 -6.8125 L 3.046875 -6.5 C 3.734375 -6.5 3.8125 -6.4375 3.8125 -5.9375 L 3.8125 -3.78125 C 3.53125 -4.140625 3.09375 -4.40625 2.5625 -4.40625 C 1.390625 -4.40625 0.34375 -3.421875 0.34375 -2.140625 C 0.34375 -0.875 1.3125 0.109375 2.453125 0.109375 C 3.09375 0.109375 3.53125 -0.234375 3.78125 -0.546875 Z M 3.78125 -3.21875 L 3.78125 -1.171875 C 3.78125 -1 3.78125 -0.984375 3.671875 -0.8125 C 3.375 -0.328125 2.9375 -0.109375 2.5 -0.109375 C 2.046875 -0.109375 1.6875 -0.375 1.453125 -0.75 C 1.203125 -1.15625 1.171875 -1.71875 1.171875 -2.140625 C 1.171875 -2.5 1.1875 -3.09375 1.46875 -3.546875 C 1.6875 -3.859375 2.0625 -4.1875 2.609375 -4.1875 C 2.953125 -4.1875 3.375 -4.03125 3.671875 -3.59375 C 3.78125 -3.421875 3.78125 -3.40625 3.78125 -3.21875 Z M 3.78125 -3.21875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-9">
|
||||
<path style="stroke:none;" d="M 1.75 -4.296875 L 1.75 -5.453125 C 1.75 -6.328125 2.21875 -6.8125 2.65625 -6.8125 C 2.6875 -6.8125 2.84375 -6.8125 2.984375 -6.734375 C 2.875 -6.703125 2.6875 -6.5625 2.6875 -6.3125 C 2.6875 -6.09375 2.84375 -5.890625 3.125 -5.890625 C 3.40625 -5.890625 3.5625 -6.09375 3.5625 -6.328125 C 3.5625 -6.703125 3.1875 -7.03125 2.65625 -7.03125 C 1.96875 -7.03125 1.109375 -6.5 1.109375 -5.4375 L 1.109375 -4.296875 L 0.328125 -4.296875 L 0.328125 -3.984375 L 1.109375 -3.984375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.34375 -0.3125 L 0.34375 0 C 0.734375 -0.015625 1.203125 -0.03125 1.46875 -0.03125 C 1.875 -0.03125 2.34375 -0.03125 2.734375 0 L 2.734375 -0.3125 L 2.53125 -0.3125 C 1.796875 -0.3125 1.78125 -0.421875 1.78125 -0.78125 L 1.78125 -3.984375 L 2.90625 -3.984375 L 2.90625 -4.296875 Z M 1.75 -4.296875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-10">
|
||||
<path style="stroke:none;" d="M 1.53125 -5.875 C 1.53125 -6.46875 1.28125 -6.921875 0.859375 -6.921875 C 0.515625 -6.921875 0.328125 -6.65625 0.328125 -6.390625 C 0.328125 -6.125 0.5 -5.859375 0.859375 -5.859375 C 1.0625 -5.859375 1.203125 -5.96875 1.25 -6.015625 C 1.265625 -6.046875 1.28125 -6.046875 1.28125 -6.046875 C 1.3125 -6.046875 1.3125 -5.90625 1.3125 -5.875 C 1.3125 -5.546875 1.234375 -4.828125 0.609375 -4.21875 C 0.484375 -4.09375 0.484375 -4.078125 0.484375 -4.046875 C 0.484375 -3.984375 0.53125 -3.9375 0.59375 -3.9375 C 0.703125 -3.9375 1.53125 -4.6875 1.53125 -5.875 Z M 3.453125 -5.875 C 3.453125 -6.46875 3.21875 -6.921875 2.796875 -6.921875 C 2.4375 -6.921875 2.265625 -6.65625 2.265625 -6.390625 C 2.265625 -6.125 2.4375 -5.859375 2.796875 -5.859375 C 2.984375 -5.859375 3.125 -5.96875 3.1875 -6.015625 C 3.203125 -6.046875 3.203125 -6.046875 3.21875 -6.046875 C 3.234375 -6.046875 3.234375 -5.90625 3.234375 -5.875 C 3.234375 -5.546875 3.171875 -4.828125 2.546875 -4.21875 C 2.421875 -4.09375 2.421875 -4.078125 2.421875 -4.046875 C 2.421875 -3.984375 2.46875 -3.9375 2.515625 -3.9375 C 2.625 -3.9375 3.453125 -4.6875 3.453125 -5.875 Z M 3.453125 -5.875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-11">
|
||||
<path style="stroke:none;" d="M 3.296875 2.390625 C 3.296875 2.359375 3.296875 2.34375 3.125 2.171875 C 1.890625 0.921875 1.5625 -0.96875 1.5625 -2.5 C 1.5625 -4.234375 1.9375 -5.96875 3.171875 -7.203125 C 3.296875 -7.328125 3.296875 -7.34375 3.296875 -7.375 C 3.296875 -7.453125 3.265625 -7.484375 3.203125 -7.484375 C 3.09375 -7.484375 2.203125 -6.796875 1.609375 -5.53125 C 1.109375 -4.4375 0.984375 -3.328125 0.984375 -2.5 C 0.984375 -1.71875 1.09375 -0.515625 1.640625 0.625 C 2.25 1.84375 3.09375 2.5 3.203125 2.5 C 3.265625 2.5 3.296875 2.46875 3.296875 2.390625 Z M 3.296875 2.390625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-12">
|
||||
<path style="stroke:none;" d="M 1.90625 -4.453125 C 1.90625 -4.71875 1.75 -4.984375 1.390625 -4.984375 C 1.1875 -4.984375 1.046875 -4.890625 0.984375 -4.828125 C 0.984375 -4.8125 0.96875 -4.796875 0.953125 -4.796875 C 0.9375 -4.796875 0.9375 -4.9375 0.9375 -4.96875 C 0.9375 -5.296875 1 -6.015625 1.640625 -6.625 C 1.75 -6.75 1.75 -6.765625 1.75 -6.796875 C 1.75 -6.875 1.703125 -6.90625 1.65625 -6.90625 C 1.546875 -6.90625 0.71875 -6.15625 0.71875 -4.96875 C 0.71875 -4.375 0.953125 -3.921875 1.390625 -3.921875 C 1.734375 -3.921875 1.90625 -4.203125 1.90625 -4.453125 Z M 1.90625 -4.453125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-13">
|
||||
<path style="stroke:none;" d="M 2.046875 -5.875 C 2.046875 -6.46875 1.8125 -6.921875 1.390625 -6.921875 C 1.03125 -6.921875 0.859375 -6.65625 0.859375 -6.390625 C 0.859375 -6.125 1.03125 -5.859375 1.390625 -5.859375 C 1.578125 -5.859375 1.71875 -5.96875 1.78125 -6.015625 C 1.796875 -6.046875 1.796875 -6.046875 1.8125 -6.046875 C 1.828125 -6.046875 1.828125 -5.90625 1.828125 -5.875 C 1.828125 -5.546875 1.765625 -4.828125 1.140625 -4.21875 C 1.015625 -4.09375 1.015625 -4.078125 1.015625 -4.046875 C 1.015625 -3.984375 1.0625 -3.9375 1.109375 -3.9375 C 1.21875 -3.9375 2.046875 -4.6875 2.046875 -5.875 Z M 2.046875 -5.875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-14">
|
||||
<path style="stroke:none;" d="M 1.90625 -3.765625 C 1.90625 -4.0625 1.671875 -4.296875 1.390625 -4.296875 C 1.09375 -4.296875 0.859375 -4.0625 0.859375 -3.765625 C 0.859375 -3.484375 1.09375 -3.234375 1.390625 -3.234375 C 1.671875 -3.234375 1.90625 -3.484375 1.90625 -3.765625 Z M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-15">
|
||||
<path style="stroke:none;" d="M 2.875 -2.5 C 2.875 -3.265625 2.765625 -4.46875 2.21875 -5.609375 C 1.625 -6.828125 0.765625 -7.484375 0.671875 -7.484375 C 0.609375 -7.484375 0.5625 -7.4375 0.5625 -7.375 C 0.5625 -7.34375 0.5625 -7.328125 0.75 -7.140625 C 1.734375 -6.15625 2.296875 -4.578125 2.296875 -2.5 C 2.296875 -0.78125 1.9375 0.96875 0.703125 2.21875 C 0.5625 2.34375 0.5625 2.359375 0.5625 2.390625 C 0.5625 2.453125 0.609375 2.5 0.671875 2.5 C 0.765625 2.5 1.671875 1.8125 2.25 0.546875 C 2.765625 -0.546875 2.875 -1.65625 2.875 -2.5 Z M 2.875 -2.5 "/>
|
||||
</symbol>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="3.321" y="39.139"/>
|
||||
<use xlink:href="#glyph0-2" x="7.748379" y="39.139"/>
|
||||
<use xlink:href="#glyph0-1" x="13.00664" y="39.139"/>
|
||||
<use xlink:href="#glyph0-3" x="17.434019" y="39.139"/>
|
||||
<use xlink:href="#glyph0-4" x="20.201629" y="39.139"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="27.946555" y="39.139"/>
|
||||
<use xlink:href="#glyph0-6" x="32.927855" y="39.139"/>
|
||||
<use xlink:href="#glyph0-7" x="37.909155" y="39.139"/>
|
||||
<use xlink:href="#glyph0-8" x="41.838404" y="39.139"/>
|
||||
<use xlink:href="#glyph0-9" x="47.373625" y="39.139"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-10" x="51.195278" y="39.139"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-11" x="75.926" y="39.139"/>
|
||||
<use xlink:href="#glyph0-12" x="79.800455" y="39.139"/>
|
||||
<use xlink:href="#glyph0-6" x="82.568065" y="39.139"/>
|
||||
<use xlink:href="#glyph0-13" x="87.549365" y="39.139"/>
|
||||
<use xlink:href="#glyph0-14" x="90.316976" y="39.139"/>
|
||||
<use xlink:href="#glyph0-15" x="93.084586" y="39.139"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-11" x="104.798" y="10.793"/>
|
||||
<use xlink:href="#glyph0-12" x="108.672455" y="10.793"/>
|
||||
<use xlink:href="#glyph0-7" x="111.440065" y="10.793"/>
|
||||
<use xlink:href="#glyph0-13" x="115.369315" y="10.793"/>
|
||||
<use xlink:href="#glyph0-14" x="118.136925" y="10.793"/>
|
||||
<use xlink:href="#glyph0-15" x="120.904535" y="10.793"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-11" x="132.342" y="39.139"/>
|
||||
<use xlink:href="#glyph0-12" x="136.216455" y="39.139"/>
|
||||
<use xlink:href="#glyph0-8" x="138.984065" y="39.139"/>
|
||||
<use xlink:href="#glyph0-13" x="144.519286" y="39.139"/>
|
||||
<use xlink:href="#glyph0-14" x="147.286896" y="39.139"/>
|
||||
<use xlink:href="#glyph0-15" x="150.054507" y="39.139"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-11" x="104.854" y="67.486"/>
|
||||
<use xlink:href="#glyph0-12" x="108.728455" y="67.486"/>
|
||||
<use xlink:href="#glyph0-9" x="111.496065" y="67.486"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-13" x="115.317719" y="67.486"/>
|
||||
<use xlink:href="#glyph0-14" x="118.085329" y="67.486"/>
|
||||
<use xlink:href="#glyph0-15" x="120.852939" y="67.486"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 29.950219 0.0005625 L 42.200219 0.0005625 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
|
||||
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.194314 1.594313 C -1.096658 0.996656 0.00099875 0.0982188 0.297874 0.0005625 C 0.00099875 -0.101 -1.096658 -0.995531 -1.194314 -1.593187 " transform="matrix(1,0,0,-1,71.94822,36.649)"/>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 58.96975 8.500563 C 60.051781 16.453688 64.102563 21.688063 71.106469 24.551344 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
|
||||
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.196589 1.594396 C -1.095787 0.997796 0.00041427 0.0989642 0.301146 0.00111983 C -0.000438865 -0.0984224 -1.095804 -0.996384 -1.197467 -1.59426 " transform="matrix(0.92848,-0.38002,-0.38002,-0.92848,100.85363,12.09595)"/>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 98.551781 24.727125 C 105.977563 21.688063 110.028344 16.453688 111.047875 8.953688 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
|
||||
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.195717 1.592423 C -1.095615 0.995823 -0.00039703 0.0985073 0.297263 -0.00104224 C 0.000389063 -0.0985566 -1.094776 -0.997497 -1.195606 -1.594358 " transform="matrix(0.1348,0.99165,0.99165,-0.1348,140.7969,27.69336)"/>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.110375 -8.499437 C 110.012719 -16.468187 105.946313 -21.706469 98.918969 -24.56975 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
|
||||
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.195342 1.594526 C -1.094949 0.994081 -0.000119528 0.0979331 0.300979 0.00052249 C -0.000645038 -0.0995886 -1.097397 -0.994901 -1.194527 -1.594821 " transform="matrix(-0.92848,0.37822,0.37822,0.92848,128.66988,61.21771)"/>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 71.586938 -24.741625 C 64.133813 -21.706469 60.067406 -16.468187 59.03225 -8.956469 " transform="matrix(1,0,0,-1,29.749,36.649)"/>
|
||||
<path style="fill:none;stroke-width:0.31879;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -1.195362 1.595896 C -1.096801 0.9954 0.00108287 0.0998119 0.298511 -0.000206965 C 0.00101106 -0.101074 -1.095391 -0.998 -1.197185 -1.594559 " transform="matrix(-0.13647,-0.99165,-0.99165,0.13647,88.78272,45.60464)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 19 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 15 KiB |
+190
@@ -0,0 +1,190 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="321.677pt" height="185.575pt" viewBox="0 0 321.677 185.575" version="1.1">
|
||||
<defs>
|
||||
<g>
|
||||
<symbol overflow="visible" id="glyph0-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-1">
|
||||
<path style="stroke:none;" d="M 3.296875 2.390625 C 3.296875 2.359375 3.296875 2.34375 3.125 2.171875 C 1.890625 0.921875 1.5625 -0.96875 1.5625 -2.5 C 1.5625 -4.234375 1.9375 -5.96875 3.171875 -7.203125 C 3.296875 -7.328125 3.296875 -7.34375 3.296875 -7.375 C 3.296875 -7.453125 3.265625 -7.484375 3.203125 -7.484375 C 3.09375 -7.484375 2.203125 -6.796875 1.609375 -5.53125 C 1.109375 -4.4375 0.984375 -3.328125 0.984375 -2.5 C 0.984375 -1.71875 1.09375 -0.515625 1.640625 0.625 C 2.25 1.84375 3.09375 2.5 3.203125 2.5 C 3.265625 2.5 3.296875 2.46875 3.296875 2.390625 Z M 3.296875 2.390625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-2">
|
||||
<path style="stroke:none;" d="M 1.90625 -3.765625 C 1.90625 -4.0625 1.671875 -4.296875 1.390625 -4.296875 C 1.09375 -4.296875 0.859375 -4.0625 0.859375 -3.765625 C 0.859375 -3.484375 1.09375 -3.234375 1.390625 -3.234375 C 1.671875 -3.234375 1.90625 -3.484375 1.90625 -3.765625 Z M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-3">
|
||||
<path style="stroke:none;" d="M 2.875 -2.5 C 2.875 -3.265625 2.765625 -4.46875 2.21875 -5.609375 C 1.625 -6.828125 0.765625 -7.484375 0.671875 -7.484375 C 0.609375 -7.484375 0.5625 -7.4375 0.5625 -7.375 C 0.5625 -7.34375 0.5625 -7.328125 0.75 -7.140625 C 1.734375 -6.15625 2.296875 -4.578125 2.296875 -2.5 C 2.296875 -0.78125 1.9375 0.96875 0.703125 2.21875 C 0.5625 2.34375 0.5625 2.359375 0.5625 2.390625 C 0.5625 2.453125 0.609375 2.5 0.671875 2.5 C 0.765625 2.5 1.671875 1.8125 2.25 0.546875 C 2.765625 -0.546875 2.875 -1.65625 2.875 -2.5 Z M 2.875 -2.5 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-1">
|
||||
<path style="stroke:none;" d="M 3.328125 -3.015625 C 3.390625 -3.265625 3.625 -4.1875 4.3125 -4.1875 C 4.359375 -4.1875 4.609375 -4.1875 4.8125 -4.0625 C 4.53125 -4 4.34375 -3.765625 4.34375 -3.515625 C 4.34375 -3.359375 4.453125 -3.171875 4.71875 -3.171875 C 4.9375 -3.171875 5.25 -3.34375 5.25 -3.75 C 5.25 -4.265625 4.671875 -4.40625 4.328125 -4.40625 C 3.75 -4.40625 3.40625 -3.875 3.28125 -3.65625 C 3.03125 -4.3125 2.5 -4.40625 2.203125 -4.40625 C 1.171875 -4.40625 0.59375 -3.125 0.59375 -2.875 C 0.59375 -2.765625 0.703125 -2.765625 0.71875 -2.765625 C 0.796875 -2.765625 0.828125 -2.796875 0.84375 -2.875 C 1.1875 -3.9375 1.84375 -4.1875 2.1875 -4.1875 C 2.375 -4.1875 2.71875 -4.09375 2.71875 -3.515625 C 2.71875 -3.203125 2.546875 -2.546875 2.1875 -1.140625 C 2.03125 -0.53125 1.671875 -0.109375 1.234375 -0.109375 C 1.171875 -0.109375 0.953125 -0.109375 0.734375 -0.234375 C 0.984375 -0.296875 1.203125 -0.5 1.203125 -0.78125 C 1.203125 -1.046875 0.984375 -1.125 0.84375 -1.125 C 0.53125 -1.125 0.296875 -0.875 0.296875 -0.546875 C 0.296875 -0.09375 0.78125 0.109375 1.21875 0.109375 C 1.890625 0.109375 2.25 -0.59375 2.265625 -0.640625 C 2.390625 -0.28125 2.75 0.109375 3.34375 0.109375 C 4.375 0.109375 4.9375 -1.171875 4.9375 -1.421875 C 4.9375 -1.53125 4.859375 -1.53125 4.828125 -1.53125 C 4.734375 -1.53125 4.71875 -1.484375 4.6875 -1.421875 C 4.359375 -0.34375 3.6875 -0.109375 3.375 -0.109375 C 2.984375 -0.109375 2.828125 -0.421875 2.828125 -0.765625 C 2.828125 -0.984375 2.875 -1.203125 2.984375 -1.640625 Z M 3.328125 -3.015625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-2">
|
||||
<path style="stroke:none;" d="M 4.6875 -3.765625 C 4.703125 -3.8125 4.71875 -3.875 4.71875 -3.9375 C 4.71875 -4.109375 4.609375 -4.203125 4.4375 -4.203125 C 4.34375 -4.203125 4.0625 -4.140625 4.03125 -3.78125 C 3.84375 -4.140625 3.5 -4.40625 3.09375 -4.40625 C 1.96875 -4.40625 0.734375 -3.015625 0.734375 -1.578125 C 0.734375 -0.59375 1.328125 0 2.046875 0 C 2.640625 0 3.109375 -0.46875 3.203125 -0.578125 L 3.21875 -0.5625 C 3.015625 0.3125 2.890625 0.734375 2.890625 0.75 C 2.84375 0.84375 2.515625 1.828125 1.453125 1.828125 C 1.265625 1.828125 0.9375 1.8125 0.65625 1.71875 C 0.953125 1.640625 1.0625 1.375 1.0625 1.203125 C 1.0625 1.046875 0.953125 0.859375 0.6875 0.859375 C 0.46875 0.859375 0.15625 1.03125 0.15625 1.4375 C 0.15625 1.84375 0.515625 2.046875 1.46875 2.046875 C 2.71875 2.046875 3.4375 1.265625 3.59375 0.671875 Z M 3.40625 -1.28125 C 3.34375 -1.015625 3.109375 -0.765625 2.890625 -0.578125 C 2.6875 -0.40625 2.375 -0.21875 2.078125 -0.21875 C 1.578125 -0.21875 1.4375 -0.734375 1.4375 -1.140625 C 1.4375 -1.609375 1.71875 -2.796875 2 -3.296875 C 2.265625 -3.78125 2.6875 -4.1875 3.109375 -4.1875 C 3.765625 -4.1875 3.90625 -3.375 3.90625 -3.328125 C 3.90625 -3.28125 3.890625 -3.21875 3.875 -3.1875 Z M 3.40625 -1.28125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-1">
|
||||
<path style="stroke:none;" d="M 2.328125 -4.4375 C 2.328125 -4.625 2.328125 -4.625 2.125 -4.625 C 1.671875 -4.1875 1.046875 -4.1875 0.765625 -4.1875 L 0.765625 -3.9375 C 0.921875 -3.9375 1.390625 -3.9375 1.765625 -4.125 L 1.765625 -0.578125 C 1.765625 -0.34375 1.765625 -0.25 1.078125 -0.25 L 0.8125 -0.25 L 0.8125 0 C 0.9375 0 1.796875 -0.03125 2.046875 -0.03125 C 2.265625 -0.03125 3.140625 0 3.296875 0 L 3.296875 -0.25 L 3.03125 -0.25 C 2.328125 -0.25 2.328125 -0.34375 2.328125 -0.578125 Z M 2.328125 -4.4375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-2">
|
||||
<path style="stroke:none;" d="M 3.515625 -1.265625 L 3.28125 -1.265625 C 3.265625 -1.109375 3.1875 -0.703125 3.09375 -0.640625 C 3.046875 -0.59375 2.515625 -0.59375 2.40625 -0.59375 L 1.125 -0.59375 C 1.859375 -1.234375 2.109375 -1.4375 2.515625 -1.765625 C 3.03125 -2.171875 3.515625 -2.609375 3.515625 -3.265625 C 3.515625 -4.109375 2.78125 -4.625 1.890625 -4.625 C 1.03125 -4.625 0.4375 -4.015625 0.4375 -3.375 C 0.4375 -3.03125 0.734375 -2.984375 0.8125 -2.984375 C 0.96875 -2.984375 1.171875 -3.109375 1.171875 -3.359375 C 1.171875 -3.484375 1.125 -3.734375 0.765625 -3.734375 C 0.984375 -4.21875 1.453125 -4.375 1.78125 -4.375 C 2.484375 -4.375 2.84375 -3.828125 2.84375 -3.265625 C 2.84375 -2.65625 2.40625 -2.1875 2.1875 -1.9375 L 0.515625 -0.265625 C 0.4375 -0.203125 0.4375 -0.1875 0.4375 0 L 3.3125 0 Z M 3.515625 -1.265625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-3">
|
||||
<path style="stroke:none;" d="M 1.90625 -2.328125 C 2.453125 -2.328125 2.84375 -1.953125 2.84375 -1.203125 C 2.84375 -0.34375 2.328125 -0.078125 1.9375 -0.078125 C 1.65625 -0.078125 1.03125 -0.15625 0.75 -0.578125 C 1.078125 -0.578125 1.15625 -0.8125 1.15625 -0.96875 C 1.15625 -1.1875 0.984375 -1.34375 0.765625 -1.34375 C 0.578125 -1.34375 0.375 -1.21875 0.375 -0.9375 C 0.375 -0.28125 1.09375 0.140625 1.9375 0.140625 C 2.90625 0.140625 3.578125 -0.515625 3.578125 -1.203125 C 3.578125 -1.75 3.140625 -2.296875 2.375 -2.453125 C 3.09375 -2.71875 3.359375 -3.234375 3.359375 -3.671875 C 3.359375 -4.21875 2.734375 -4.625 1.953125 -4.625 C 1.1875 -4.625 0.59375 -4.25 0.59375 -3.6875 C 0.59375 -3.453125 0.75 -3.328125 0.953125 -3.328125 C 1.171875 -3.328125 1.3125 -3.484375 1.3125 -3.671875 C 1.3125 -3.875 1.171875 -4.03125 0.953125 -4.046875 C 1.203125 -4.34375 1.671875 -4.421875 1.9375 -4.421875 C 2.25 -4.421875 2.6875 -4.265625 2.6875 -3.671875 C 2.6875 -3.375 2.59375 -3.046875 2.40625 -2.84375 C 2.1875 -2.578125 1.984375 -2.5625 1.640625 -2.53125 C 1.46875 -2.515625 1.453125 -2.515625 1.421875 -2.515625 C 1.40625 -2.515625 1.34375 -2.5 1.34375 -2.421875 C 1.34375 -2.328125 1.40625 -2.328125 1.53125 -2.328125 Z M 1.90625 -2.328125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph3-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph3-1">
|
||||
<path style="stroke:none;" d="M 0.84375 -0.4375 C 0.828125 -0.34375 0.78125 -0.171875 0.78125 -0.15625 C 0.78125 0 0.90625 0.0625 1.015625 0.0625 C 1.140625 0.0625 1.25 -0.015625 1.296875 -0.078125 C 1.328125 -0.140625 1.375 -0.375 1.421875 -0.515625 C 1.453125 -0.640625 1.53125 -0.96875 1.5625 -1.140625 C 1.609375 -1.296875 1.65625 -1.453125 1.6875 -1.609375 C 1.765625 -1.890625 1.78125 -1.953125 1.984375 -2.234375 C 2.171875 -2.515625 2.5 -2.875 3.03125 -2.875 C 3.421875 -2.875 3.4375 -2.515625 3.4375 -2.390625 C 3.4375 -1.96875 3.140625 -1.203125 3.03125 -0.90625 C 2.953125 -0.703125 2.921875 -0.640625 2.921875 -0.53125 C 2.921875 -0.15625 3.21875 0.0625 3.578125 0.0625 C 4.28125 0.0625 4.578125 -0.890625 4.578125 -1 C 4.578125 -1.09375 4.5 -1.09375 4.46875 -1.09375 C 4.375 -1.09375 4.375 -1.046875 4.34375 -0.96875 C 4.1875 -0.40625 3.875 -0.125 3.609375 -0.125 C 3.453125 -0.125 3.421875 -0.21875 3.421875 -0.375 C 3.421875 -0.53125 3.46875 -0.625 3.59375 -0.9375 C 3.671875 -1.15625 3.953125 -1.890625 3.953125 -2.28125 C 3.953125 -2.953125 3.421875 -3.078125 3.046875 -3.078125 C 2.46875 -3.078125 2.078125 -2.71875 1.875 -2.4375 C 1.828125 -2.921875 1.421875 -3.078125 1.125 -3.078125 C 0.828125 -3.078125 0.671875 -2.859375 0.578125 -2.703125 C 0.421875 -2.4375 0.328125 -2.046875 0.328125 -2 C 0.328125 -1.921875 0.421875 -1.921875 0.453125 -1.921875 C 0.546875 -1.921875 0.546875 -1.9375 0.59375 -2.125 C 0.703125 -2.53125 0.84375 -2.875 1.109375 -2.875 C 1.296875 -2.875 1.34375 -2.71875 1.34375 -2.53125 C 1.34375 -2.40625 1.28125 -2.140625 1.21875 -1.953125 C 1.171875 -1.765625 1.109375 -1.484375 1.078125 -1.328125 Z M 0.84375 -0.4375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph4-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph4-1">
|
||||
<path style="stroke:none;" d="M 4.421875 -6.3125 C 4.5625 -6.3125 4.8125 -6.3125 4.8125 -6.609375 C 4.8125 -6.921875 4.578125 -6.921875 4.421875 -6.921875 L 2.609375 -6.921875 C 2.28125 -6.921875 2.21875 -6.828125 2.21875 -6.515625 L 2.21875 0.421875 C 2.21875 0.734375 2.265625 0.828125 2.609375 0.828125 L 4.421875 0.828125 C 4.5625 0.828125 4.8125 0.828125 4.8125 0.53125 C 4.8125 0.21875 4.578125 0.21875 4.421875 0.21875 L 2.90625 0.21875 L 2.90625 -6.3125 Z M 4.421875 -6.3125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph4-2">
|
||||
<path style="stroke:none;" d="M 3.015625 -6.515625 C 3.015625 -6.8125 2.953125 -6.921875 2.609375 -6.921875 L 0.8125 -6.921875 C 0.65625 -6.921875 0.40625 -6.921875 0.40625 -6.625 C 0.40625 -6.3125 0.640625 -6.3125 0.8125 -6.3125 L 2.328125 -6.3125 L 2.328125 0.21875 L 0.8125 0.21875 C 0.65625 0.21875 0.40625 0.21875 0.40625 0.515625 C 0.40625 0.828125 0.640625 0.828125 0.8125 0.828125 L 2.609375 0.828125 C 2.9375 0.828125 3.015625 0.734375 3.015625 0.421875 Z M 3.015625 -6.515625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph5-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph5-1">
|
||||
<path style="stroke:none;" d="M 17.984375 -8.109375 C 19.03125 -7.21875 20.296875 -6.5625 21.109375 -6.1875 C 20.21875 -5.796875 19 -5.15625 17.984375 -4.28125 L 2.25 -4.28125 C 1.828125 -4.28125 1.359375 -4.28125 1.359375 -3.796875 C 1.359375 -3.296875 1.8125 -3.296875 2.234375 -3.296875 L 16.875 -3.296875 C 15.6875 -2.15625 14.390625 0.03125 14.390625 0.34375 C 14.390625 0.625 14.71875 0.625 14.875 0.625 C 15.0625 0.625 15.234375 0.625 15.34375 0.421875 C 15.859375 -0.515625 16.546875 -1.828125 18.171875 -3.265625 C 19.875 -4.78125 21.53125 -5.453125 22.828125 -5.828125 C 23.25 -5.96875 23.265625 -6 23.3125 -6.046875 C 23.375 -6.078125 23.375 -6.140625 23.375 -6.1875 C 23.375 -6.25 23.375 -6.296875 23.34375 -6.34375 L 23.265625 -6.390625 C 23.21875 -6.421875 23.1875 -6.4375 22.71875 -6.59375 C 19.375 -7.578125 16.90625 -9.84375 15.515625 -12.484375 C 15.234375 -12.984375 15.21875 -13.015625 14.875 -13.015625 C 14.71875 -13.015625 14.390625 -13.015625 14.390625 -12.734375 C 14.390625 -12.421875 15.65625 -10.265625 16.875 -9.09375 L 2.234375 -9.09375 C 1.8125 -9.09375 1.359375 -9.09375 1.359375 -8.59375 C 1.359375 -8.109375 1.828125 -8.109375 2.25 -8.109375 Z M 17.984375 -8.109375 "/>
|
||||
</symbol>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="24.404" y="10.792"/>
|
||||
<use xlink:href="#glyph0-2" x="28.278455" y="10.792"/>
|
||||
<use xlink:href="#glyph0-3" x="31.046065" y="10.792"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="3.321" y="52.219"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-1" x="9.014" y="53.713"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -4.251844 -8.499781 L -18.056531 -36.109156 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="45.664" y="53.312"/>
|
||||
<use xlink:href="#glyph0-2" x="49.538455" y="53.312"/>
|
||||
<use xlink:href="#glyph0-3" x="52.306065" y="53.312"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 4.252063 -8.499781 L 17.009875 -34.019312 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="24.58" y="94.738"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-2" x="30.274" y="96.233"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 17.009875 -51.023219 L 3.205188 -78.628687 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="66.924" y="95.831"/>
|
||||
<use xlink:href="#glyph0-2" x="70.798455" y="95.831"/>
|
||||
<use xlink:href="#glyph0-3" x="73.566065" y="95.831"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 25.509875 -51.023219 L 38.271594 -76.538844 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="45.84" y="137.258"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-3" x="51.534" y="138.752"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 38.271594 -93.54275 L 24.463 -121.148219 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="88.183" y="138.351"/>
|
||||
<use xlink:href="#glyph0-2" x="92.057455" y="138.351"/>
|
||||
<use xlink:href="#glyph0-3" x="94.825065" y="138.351"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 46.771594 -93.54275 L 59.533313 -119.058375 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="66.623" y="179.778"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph3-1" x="72.317" y="181.272"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 59.529406 -136.062281 L 45.724719 -163.66775 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph4-1" x="109.471" y="181.424"/>
|
||||
<use xlink:href="#glyph4-2" x="114.701365" y="181.424"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 68.029406 -136.062281 L 81.345812 -162.687281 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph5-1" x="144.827" y="97.888"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="222.829" y="10.792"/>
|
||||
<use xlink:href="#glyph0-2" x="226.703455" y="10.792"/>
|
||||
<use xlink:href="#glyph0-3" x="229.471065" y="10.792"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="197.531" y="51.997"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="205.95936" y="51.997"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-1" x="211.655" y="53.492"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 194.177844 -8.499781 L 180.482531 -35.8865 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="244.089" y="53.312"/>
|
||||
<use xlink:href="#glyph0-2" x="247.963455" y="53.312"/>
|
||||
<use xlink:href="#glyph0-3" x="250.731065" y="53.312"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 202.677844 -8.499781 L 215.439562 -34.019312 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="218.79" y="94.517"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="227.21836" y="94.517"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-2" x="232.915" y="96.011"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 215.439562 -51.023219 L 201.74425 -78.406031 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="265.349" y="95.831"/>
|
||||
<use xlink:href="#glyph0-2" x="269.223455" y="95.831"/>
|
||||
<use xlink:href="#glyph0-3" x="271.991065" y="95.831"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 223.939562 -51.023219 L 236.697375 -76.538844 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="240.05" y="137.037"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="248.47836" y="137.037"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-3" x="254.174" y="138.531"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 236.697375 -93.54275 L 223.002062 -120.925562 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="286.609" y="138.351"/>
|
||||
<use xlink:href="#glyph0-2" x="290.483455" y="138.351"/>
|
||||
<use xlink:href="#glyph0-3" x="293.251065" y="138.351"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 245.197375 -93.54275 L 257.959094 -119.058375 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="260.833" y="179.556"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="269.26136" y="179.556"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph3-1" x="274.957" y="181.051"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 257.959094 -136.062281 L 244.263781 -163.449 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph4-1" x="307.896" y="181.424"/>
|
||||
<use xlink:href="#glyph4-2" x="313.126365" y="181.424"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 266.455188 -136.062281 L 279.771594 -162.687281 " transform="matrix(1,0,0,-1,29.662,8.301)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,193 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256.353pt" height="142.641pt" viewBox="0 0 256.353 142.641" version="1.1">
|
||||
<defs>
|
||||
<g>
|
||||
<symbol overflow="visible" id="glyph0-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-1">
|
||||
<path style="stroke:none;" d="M 2.3125 -6.671875 C 2.21875 -6.796875 2.21875 -6.8125 2.03125 -6.8125 L 0.328125 -6.8125 L 0.328125 -6.5 L 0.625 -6.5 C 0.765625 -6.5 0.96875 -6.484375 1.109375 -6.484375 C 1.34375 -6.453125 1.359375 -6.4375 1.359375 -6.25 L 1.359375 -1.046875 C 1.359375 -0.78125 1.359375 -0.3125 0.328125 -0.3125 L 0.328125 0 C 0.671875 -0.015625 1.171875 -0.03125 1.5 -0.03125 C 1.828125 -0.03125 2.3125 -0.015625 2.65625 0 L 2.65625 -0.3125 C 1.640625 -0.3125 1.640625 -0.78125 1.640625 -1.046875 L 1.640625 -6.234375 C 1.6875 -6.1875 1.6875 -6.171875 1.734375 -6.109375 L 5.796875 -0.125 C 5.890625 -0.015625 5.90625 0 5.96875 0 C 6.109375 0 6.109375 -0.0625 6.109375 -0.265625 L 6.109375 -5.765625 C 6.109375 -6.03125 6.109375 -6.5 7.140625 -6.5 L 7.140625 -6.8125 C 6.78125 -6.796875 6.296875 -6.78125 5.96875 -6.78125 C 5.640625 -6.78125 5.15625 -6.796875 4.8125 -6.8125 L 4.8125 -6.5 C 5.828125 -6.5 5.828125 -6.03125 5.828125 -5.765625 L 5.828125 -1.5 Z M 2.3125 -6.671875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-2">
|
||||
<path style="stroke:none;" d="M 4.6875 -2.140625 C 4.6875 -3.40625 3.703125 -4.46875 2.5 -4.46875 C 1.25 -4.46875 0.28125 -3.375 0.28125 -2.140625 C 0.28125 -0.84375 1.3125 0.109375 2.484375 0.109375 C 3.6875 0.109375 4.6875 -0.875 4.6875 -2.140625 Z M 2.5 -0.140625 C 2.0625 -0.140625 1.625 -0.34375 1.359375 -0.8125 C 1.109375 -1.25 1.109375 -1.859375 1.109375 -2.21875 C 1.109375 -2.609375 1.109375 -3.140625 1.34375 -3.578125 C 1.609375 -4.03125 2.078125 -4.25 2.484375 -4.25 C 2.921875 -4.25 3.34375 -4.03125 3.609375 -3.59375 C 3.875 -3.171875 3.875 -2.59375 3.875 -2.21875 C 3.875 -1.859375 3.875 -1.3125 3.65625 -0.875 C 3.421875 -0.421875 2.984375 -0.140625 2.5 -0.140625 Z M 2.5 -0.140625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-3">
|
||||
<path style="stroke:none;" d="M 3.78125 -0.546875 L 3.78125 0.109375 L 5.25 0 L 5.25 -0.3125 C 4.5625 -0.3125 4.46875 -0.375 4.46875 -0.875 L 4.46875 -6.921875 L 3.046875 -6.8125 L 3.046875 -6.5 C 3.734375 -6.5 3.8125 -6.4375 3.8125 -5.9375 L 3.8125 -3.78125 C 3.53125 -4.140625 3.09375 -4.40625 2.5625 -4.40625 C 1.390625 -4.40625 0.34375 -3.421875 0.34375 -2.140625 C 0.34375 -0.875 1.3125 0.109375 2.453125 0.109375 C 3.09375 0.109375 3.53125 -0.234375 3.78125 -0.546875 Z M 3.78125 -3.21875 L 3.78125 -1.171875 C 3.78125 -1 3.78125 -0.984375 3.671875 -0.8125 C 3.375 -0.328125 2.9375 -0.109375 2.5 -0.109375 C 2.046875 -0.109375 1.6875 -0.375 1.453125 -0.75 C 1.203125 -1.15625 1.171875 -1.71875 1.171875 -2.140625 C 1.171875 -2.5 1.1875 -3.09375 1.46875 -3.546875 C 1.6875 -3.859375 2.0625 -4.1875 2.609375 -4.1875 C 2.953125 -4.1875 3.375 -4.03125 3.671875 -3.59375 C 3.78125 -3.421875 3.78125 -3.40625 3.78125 -3.21875 Z M 3.78125 -3.21875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-4">
|
||||
<path style="stroke:none;" d="M 1.109375 -2.515625 C 1.171875 -4 2.015625 -4.25 2.359375 -4.25 C 3.375 -4.25 3.484375 -2.90625 3.484375 -2.515625 Z M 1.109375 -2.296875 L 3.890625 -2.296875 C 4.109375 -2.296875 4.140625 -2.296875 4.140625 -2.515625 C 4.140625 -3.5 3.59375 -4.46875 2.359375 -4.46875 C 1.203125 -4.46875 0.28125 -3.4375 0.28125 -2.1875 C 0.28125 -0.859375 1.328125 0.109375 2.46875 0.109375 C 3.6875 0.109375 4.140625 -1 4.140625 -1.1875 C 4.140625 -1.28125 4.0625 -1.3125 4 -1.3125 C 3.921875 -1.3125 3.890625 -1.25 3.875 -1.171875 C 3.53125 -0.140625 2.625 -0.140625 2.53125 -0.140625 C 2.03125 -0.140625 1.640625 -0.4375 1.40625 -0.8125 C 1.109375 -1.28125 1.109375 -1.9375 1.109375 -2.296875 Z M 1.109375 -2.296875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-5">
|
||||
<path style="stroke:none;" d="M 3.296875 2.390625 C 3.296875 2.359375 3.296875 2.34375 3.125 2.171875 C 1.890625 0.921875 1.5625 -0.96875 1.5625 -2.5 C 1.5625 -4.234375 1.9375 -5.96875 3.171875 -7.203125 C 3.296875 -7.328125 3.296875 -7.34375 3.296875 -7.375 C 3.296875 -7.453125 3.265625 -7.484375 3.203125 -7.484375 C 3.09375 -7.484375 2.203125 -6.796875 1.609375 -5.53125 C 1.109375 -4.4375 0.984375 -3.328125 0.984375 -2.5 C 0.984375 -1.71875 1.09375 -0.515625 1.640625 0.625 C 2.25 1.84375 3.09375 2.5 3.203125 2.5 C 3.265625 2.5 3.296875 2.46875 3.296875 2.390625 Z M 3.296875 2.390625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-6">
|
||||
<path style="stroke:none;" d="M 2.875 -2.5 C 2.875 -3.265625 2.765625 -4.46875 2.21875 -5.609375 C 1.625 -6.828125 0.765625 -7.484375 0.671875 -7.484375 C 0.609375 -7.484375 0.5625 -7.4375 0.5625 -7.375 C 0.5625 -7.34375 0.5625 -7.328125 0.75 -7.140625 C 1.734375 -6.15625 2.296875 -4.578125 2.296875 -2.5 C 2.296875 -0.78125 1.9375 0.96875 0.703125 2.21875 C 0.5625 2.34375 0.5625 2.359375 0.5625 2.390625 C 0.5625 2.453125 0.609375 2.5 0.671875 2.5 C 0.765625 2.5 1.671875 1.8125 2.25 0.546875 C 2.765625 -0.546875 2.875 -1.65625 2.875 -2.5 Z M 2.875 -2.5 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-7">
|
||||
<path style="stroke:none;" d="M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-8">
|
||||
<path style="stroke:none;" d="M 5.796875 -2.578125 L 5.546875 -2.578125 C 5.4375 -1.5625 5.296875 -0.3125 3.546875 -0.3125 L 2.734375 -0.3125 C 2.265625 -0.3125 2.25 -0.375 2.25 -0.703125 L 2.25 -6.015625 C 2.25 -6.359375 2.25 -6.5 3.1875 -6.5 L 3.515625 -6.5 L 3.515625 -6.8125 C 3.15625 -6.78125 2.25 -6.78125 1.84375 -6.78125 C 1.453125 -6.78125 0.671875 -6.78125 0.328125 -6.8125 L 0.328125 -6.5 L 0.5625 -6.5 C 1.328125 -6.5 1.359375 -6.390625 1.359375 -6.03125 L 1.359375 -0.78125 C 1.359375 -0.421875 1.328125 -0.3125 0.5625 -0.3125 L 0.328125 -0.3125 L 0.328125 0 L 5.515625 0 Z M 5.796875 -2.578125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-9">
|
||||
<path style="stroke:none;" d="M 3.3125 -0.75 C 3.359375 -0.359375 3.625 0.0625 4.09375 0.0625 C 4.3125 0.0625 4.921875 -0.078125 4.921875 -0.890625 L 4.921875 -1.453125 L 4.671875 -1.453125 L 4.671875 -0.890625 C 4.671875 -0.3125 4.421875 -0.25 4.3125 -0.25 C 3.984375 -0.25 3.9375 -0.703125 3.9375 -0.75 L 3.9375 -2.734375 C 3.9375 -3.15625 3.9375 -3.546875 3.578125 -3.921875 C 3.1875 -4.3125 2.6875 -4.46875 2.21875 -4.46875 C 1.390625 -4.46875 0.703125 -4 0.703125 -3.34375 C 0.703125 -3.046875 0.90625 -2.875 1.171875 -2.875 C 1.453125 -2.875 1.625 -3.078125 1.625 -3.328125 C 1.625 -3.453125 1.578125 -3.78125 1.109375 -3.78125 C 1.390625 -4.140625 1.875 -4.25 2.1875 -4.25 C 2.6875 -4.25 3.25 -3.859375 3.25 -2.96875 L 3.25 -2.609375 C 2.734375 -2.578125 2.046875 -2.546875 1.421875 -2.25 C 0.671875 -1.90625 0.421875 -1.390625 0.421875 -0.953125 C 0.421875 -0.140625 1.390625 0.109375 2.015625 0.109375 C 2.671875 0.109375 3.125 -0.296875 3.3125 -0.75 Z M 3.25 -2.390625 L 3.25 -1.390625 C 3.25 -0.453125 2.53125 -0.109375 2.078125 -0.109375 C 1.59375 -0.109375 1.1875 -0.453125 1.1875 -0.953125 C 1.1875 -1.5 1.609375 -2.328125 3.25 -2.390625 Z M 3.25 -2.390625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-10">
|
||||
<path style="stroke:none;" d="M 1.75 -4.296875 L 1.75 -5.453125 C 1.75 -6.328125 2.21875 -6.8125 2.65625 -6.8125 C 2.6875 -6.8125 2.84375 -6.8125 2.984375 -6.734375 C 2.875 -6.703125 2.6875 -6.5625 2.6875 -6.3125 C 2.6875 -6.09375 2.84375 -5.890625 3.125 -5.890625 C 3.40625 -5.890625 3.5625 -6.09375 3.5625 -6.328125 C 3.5625 -6.703125 3.1875 -7.03125 2.65625 -7.03125 C 1.96875 -7.03125 1.109375 -6.5 1.109375 -5.4375 L 1.109375 -4.296875 L 0.328125 -4.296875 L 0.328125 -3.984375 L 1.109375 -3.984375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.34375 -0.3125 L 0.34375 0 C 0.734375 -0.015625 1.203125 -0.03125 1.46875 -0.03125 C 1.875 -0.03125 2.34375 -0.03125 2.734375 0 L 2.734375 -0.3125 L 2.53125 -0.3125 C 1.796875 -0.3125 1.78125 -0.421875 1.78125 -0.78125 L 1.78125 -3.984375 L 2.90625 -3.984375 L 2.90625 -4.296875 Z M 1.75 -4.296875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-1">
|
||||
<path style="stroke:none;" d="M 4.6875 -3.765625 C 4.703125 -3.8125 4.71875 -3.875 4.71875 -3.9375 C 4.71875 -4.109375 4.609375 -4.203125 4.4375 -4.203125 C 4.34375 -4.203125 4.0625 -4.140625 4.03125 -3.78125 C 3.84375 -4.140625 3.5 -4.40625 3.09375 -4.40625 C 1.96875 -4.40625 0.734375 -3.015625 0.734375 -1.578125 C 0.734375 -0.59375 1.328125 0 2.046875 0 C 2.640625 0 3.109375 -0.46875 3.203125 -0.578125 L 3.21875 -0.5625 C 3.015625 0.3125 2.890625 0.734375 2.890625 0.75 C 2.84375 0.84375 2.515625 1.828125 1.453125 1.828125 C 1.265625 1.828125 0.9375 1.8125 0.65625 1.71875 C 0.953125 1.640625 1.0625 1.375 1.0625 1.203125 C 1.0625 1.046875 0.953125 0.859375 0.6875 0.859375 C 0.46875 0.859375 0.15625 1.03125 0.15625 1.4375 C 0.15625 1.84375 0.515625 2.046875 1.46875 2.046875 C 2.71875 2.046875 3.4375 1.265625 3.59375 0.671875 Z M 3.40625 -1.28125 C 3.34375 -1.015625 3.109375 -0.765625 2.890625 -0.578125 C 2.6875 -0.40625 2.375 -0.21875 2.078125 -0.21875 C 1.578125 -0.21875 1.4375 -0.734375 1.4375 -1.140625 C 1.4375 -1.609375 1.71875 -2.796875 2 -3.296875 C 2.265625 -3.78125 2.6875 -4.1875 3.109375 -4.1875 C 3.765625 -4.1875 3.90625 -3.375 3.90625 -3.328125 C 3.90625 -3.28125 3.890625 -3.21875 3.875 -3.1875 Z M 3.40625 -1.28125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-2">
|
||||
<path style="stroke:none;" d="M 3.328125 -3.015625 C 3.390625 -3.265625 3.625 -4.1875 4.3125 -4.1875 C 4.359375 -4.1875 4.609375 -4.1875 4.8125 -4.0625 C 4.53125 -4 4.34375 -3.765625 4.34375 -3.515625 C 4.34375 -3.359375 4.453125 -3.171875 4.71875 -3.171875 C 4.9375 -3.171875 5.25 -3.34375 5.25 -3.75 C 5.25 -4.265625 4.671875 -4.40625 4.328125 -4.40625 C 3.75 -4.40625 3.40625 -3.875 3.28125 -3.65625 C 3.03125 -4.3125 2.5 -4.40625 2.203125 -4.40625 C 1.171875 -4.40625 0.59375 -3.125 0.59375 -2.875 C 0.59375 -2.765625 0.703125 -2.765625 0.71875 -2.765625 C 0.796875 -2.765625 0.828125 -2.796875 0.84375 -2.875 C 1.1875 -3.9375 1.84375 -4.1875 2.1875 -4.1875 C 2.375 -4.1875 2.71875 -4.09375 2.71875 -3.515625 C 2.71875 -3.203125 2.546875 -2.546875 2.1875 -1.140625 C 2.03125 -0.53125 1.671875 -0.109375 1.234375 -0.109375 C 1.171875 -0.109375 0.953125 -0.109375 0.734375 -0.234375 C 0.984375 -0.296875 1.203125 -0.5 1.203125 -0.78125 C 1.203125 -1.046875 0.984375 -1.125 0.84375 -1.125 C 0.53125 -1.125 0.296875 -0.875 0.296875 -0.546875 C 0.296875 -0.09375 0.78125 0.109375 1.21875 0.109375 C 1.890625 0.109375 2.25 -0.59375 2.265625 -0.640625 C 2.390625 -0.28125 2.75 0.109375 3.34375 0.109375 C 4.375 0.109375 4.9375 -1.171875 4.9375 -1.421875 C 4.9375 -1.53125 4.859375 -1.53125 4.828125 -1.53125 C 4.734375 -1.53125 4.71875 -1.484375 4.6875 -1.421875 C 4.359375 -0.34375 3.6875 -0.109375 3.375 -0.109375 C 2.984375 -0.109375 2.828125 -0.421875 2.828125 -0.765625 C 2.828125 -0.984375 2.875 -1.203125 2.984375 -1.640625 Z M 3.328125 -3.015625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-1">
|
||||
<path style="stroke:none;" d="M 2.328125 -4.4375 C 2.328125 -4.625 2.328125 -4.625 2.125 -4.625 C 1.671875 -4.1875 1.046875 -4.1875 0.765625 -4.1875 L 0.765625 -3.9375 C 0.921875 -3.9375 1.390625 -3.9375 1.765625 -4.125 L 1.765625 -0.578125 C 1.765625 -0.34375 1.765625 -0.25 1.078125 -0.25 L 0.8125 -0.25 L 0.8125 0 C 0.9375 0 1.796875 -0.03125 2.046875 -0.03125 C 2.265625 -0.03125 3.140625 0 3.296875 0 L 3.296875 -0.25 L 3.03125 -0.25 C 2.328125 -0.25 2.328125 -0.34375 2.328125 -0.578125 Z M 2.328125 -4.4375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-2">
|
||||
<path style="stroke:none;" d="M 3.515625 -1.265625 L 3.28125 -1.265625 C 3.265625 -1.109375 3.1875 -0.703125 3.09375 -0.640625 C 3.046875 -0.59375 2.515625 -0.59375 2.40625 -0.59375 L 1.125 -0.59375 C 1.859375 -1.234375 2.109375 -1.4375 2.515625 -1.765625 C 3.03125 -2.171875 3.515625 -2.609375 3.515625 -3.265625 C 3.515625 -4.109375 2.78125 -4.625 1.890625 -4.625 C 1.03125 -4.625 0.4375 -4.015625 0.4375 -3.375 C 0.4375 -3.03125 0.734375 -2.984375 0.8125 -2.984375 C 0.96875 -2.984375 1.171875 -3.109375 1.171875 -3.359375 C 1.171875 -3.484375 1.125 -3.734375 0.765625 -3.734375 C 0.984375 -4.21875 1.453125 -4.375 1.78125 -4.375 C 2.484375 -4.375 2.84375 -3.828125 2.84375 -3.265625 C 2.84375 -2.65625 2.40625 -2.1875 2.1875 -1.9375 L 0.515625 -0.265625 C 0.4375 -0.203125 0.4375 -0.1875 0.4375 0 L 3.3125 0 Z M 3.515625 -1.265625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-3">
|
||||
<path style="stroke:none;" d="M 1.90625 -2.328125 C 2.453125 -2.328125 2.84375 -1.953125 2.84375 -1.203125 C 2.84375 -0.34375 2.328125 -0.078125 1.9375 -0.078125 C 1.65625 -0.078125 1.03125 -0.15625 0.75 -0.578125 C 1.078125 -0.578125 1.15625 -0.8125 1.15625 -0.96875 C 1.15625 -1.1875 0.984375 -1.34375 0.765625 -1.34375 C 0.578125 -1.34375 0.375 -1.21875 0.375 -0.9375 C 0.375 -0.28125 1.09375 0.140625 1.9375 0.140625 C 2.90625 0.140625 3.578125 -0.515625 3.578125 -1.203125 C 3.578125 -1.75 3.140625 -2.296875 2.375 -2.453125 C 3.09375 -2.71875 3.359375 -3.234375 3.359375 -3.671875 C 3.359375 -4.21875 2.734375 -4.625 1.953125 -4.625 C 1.1875 -4.625 0.59375 -4.25 0.59375 -3.6875 C 0.59375 -3.453125 0.75 -3.328125 0.953125 -3.328125 C 1.171875 -3.328125 1.3125 -3.484375 1.3125 -3.671875 C 1.3125 -3.875 1.171875 -4.03125 0.953125 -4.046875 C 1.203125 -4.34375 1.671875 -4.421875 1.9375 -4.421875 C 2.25 -4.421875 2.6875 -4.265625 2.6875 -3.671875 C 2.6875 -3.375 2.59375 -3.046875 2.40625 -2.84375 C 2.1875 -2.578125 1.984375 -2.5625 1.640625 -2.53125 C 1.46875 -2.515625 1.453125 -2.515625 1.421875 -2.515625 C 1.40625 -2.515625 1.34375 -2.5 1.34375 -2.421875 C 1.34375 -2.328125 1.40625 -2.328125 1.53125 -2.328125 Z M 1.90625 -2.328125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-4">
|
||||
<path style="stroke:none;" d="M 3.6875 -1.140625 L 3.6875 -1.390625 L 2.90625 -1.390625 L 2.90625 -4.5 C 2.90625 -4.640625 2.90625 -4.703125 2.765625 -4.703125 C 2.671875 -4.703125 2.640625 -4.703125 2.578125 -4.59375 L 0.265625 -1.390625 L 0.265625 -1.140625 L 2.328125 -1.140625 L 2.328125 -0.578125 C 2.328125 -0.328125 2.328125 -0.25 1.75 -0.25 L 1.5625 -0.25 L 1.5625 0 C 1.921875 -0.015625 2.359375 -0.03125 2.609375 -0.03125 C 2.875 -0.03125 3.3125 -0.015625 3.671875 0 L 3.671875 -0.25 L 3.484375 -0.25 C 2.90625 -0.25 2.90625 -0.328125 2.90625 -0.578125 L 2.90625 -1.140625 Z M 2.375 -3.9375 L 2.375 -1.390625 L 0.53125 -1.390625 Z M 2.375 -3.9375 "/>
|
||||
</symbol>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="87.593" y="10.793"/>
|
||||
<use xlink:href="#glyph0-2" x="95.06495" y="10.793"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="100.325203" y="10.793"/>
|
||||
<use xlink:href="#glyph0-4" x="105.860423" y="10.793"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="113.605349" y="10.793"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="117.481" y="10.793"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="125.90936" y="10.793"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-1" x="131.605" y="12.287"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-6" x="136.074" y="10.793"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="16.727" y="53.313"/>
|
||||
<use xlink:href="#glyph0-2" x="24.19895" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="29.459203" y="53.313"/>
|
||||
<use xlink:href="#glyph0-4" x="34.994423" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="42.739349" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="46.615" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="55.04336" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-2" x="60.739" y="54.807"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-6" x="65.208" y="53.313"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -14.169438 -8.502688 L -56.704594 -34.018313 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-7" x="3.321" y="93.867"/>
|
||||
<use xlink:href="#glyph0-7" x="6.08861" y="93.867"/>
|
||||
<use xlink:href="#glyph0-7" x="8.856221" y="93.867"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -77.950688 -51.022219 L -102.931156 -80.994875 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-7" x="74.187" y="93.867"/>
|
||||
<use xlink:href="#glyph0-7" x="76.95461" y="93.867"/>
|
||||
<use xlink:href="#glyph0-7" x="79.722221" y="93.867"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -63.782719 -51.022219 L -38.80225 -80.994875 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="158.459" y="53.313"/>
|
||||
<use xlink:href="#glyph0-2" x="165.93095" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="171.191203" y="53.313"/>
|
||||
<use xlink:href="#glyph0-4" x="176.726423" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="184.471349" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="188.347" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="196.77536" y="53.313"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-3" x="202.471" y="54.807"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-6" x="206.941" y="53.313"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14.1665 -8.502688 L 56.701656 -34.018313 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-7" x="145.053" y="93.867"/>
|
||||
<use xlink:href="#glyph0-7" x="147.82061" y="93.867"/>
|
||||
<use xlink:href="#glyph0-7" x="150.588221" y="93.867"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 63.783687 -51.022219 L 38.803219 -80.994875 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="193.892" y="95.832"/>
|
||||
<use xlink:href="#glyph0-2" x="201.36395" y="95.832"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="206.624203" y="95.832"/>
|
||||
<use xlink:href="#glyph0-4" x="212.159423" y="95.832"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="219.904349" y="95.832"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="223.78" y="95.832"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-2" x="232.20836" y="95.832"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-4" x="237.904" y="97.327"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-6" x="242.374" y="95.832"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 77.951656 -51.022219 L 99.217281 -76.537844 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-8" x="187.108" y="139.32"/>
|
||||
<use xlink:href="#glyph0-4" x="193.334625" y="139.32"/>
|
||||
<use xlink:href="#glyph0-9" x="197.762004" y="139.32"/>
|
||||
<use xlink:href="#glyph0-10" x="202.743304" y="139.32"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 101.576656 -93.54175 L 86.553219 -120.580813 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-8" x="234.352" y="139.32"/>
|
||||
<use xlink:href="#glyph0-4" x="240.578625" y="139.32"/>
|
||||
<use xlink:href="#glyph0-9" x="245.006004" y="139.32"/>
|
||||
<use xlink:href="#glyph0-10" x="249.987304" y="139.32"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 111.021969 -93.54175 L 126.045406 -120.580813 " transform="matrix(1,0,0,-1,113.771,8.302)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256.353pt" height="141.866pt" viewBox="0 0 256.353 141.866" version="1.1">
|
||||
<defs>
|
||||
<g>
|
||||
<symbol overflow="visible" id="glyph0-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-1">
|
||||
<path style="stroke:none;" d="M 2.3125 -6.671875 C 2.21875 -6.796875 2.21875 -6.8125 2.03125 -6.8125 L 0.328125 -6.8125 L 0.328125 -6.5 L 0.625 -6.5 C 0.765625 -6.5 0.96875 -6.484375 1.109375 -6.484375 C 1.34375 -6.453125 1.359375 -6.4375 1.359375 -6.25 L 1.359375 -1.046875 C 1.359375 -0.78125 1.359375 -0.3125 0.328125 -0.3125 L 0.328125 0 C 0.671875 -0.015625 1.171875 -0.03125 1.5 -0.03125 C 1.828125 -0.03125 2.3125 -0.015625 2.65625 0 L 2.65625 -0.3125 C 1.640625 -0.3125 1.640625 -0.78125 1.640625 -1.046875 L 1.640625 -6.234375 C 1.6875 -6.1875 1.6875 -6.171875 1.734375 -6.109375 L 5.796875 -0.125 C 5.890625 -0.015625 5.90625 0 5.96875 0 C 6.109375 0 6.109375 -0.0625 6.109375 -0.265625 L 6.109375 -5.765625 C 6.109375 -6.03125 6.109375 -6.5 7.140625 -6.5 L 7.140625 -6.8125 C 6.78125 -6.796875 6.296875 -6.78125 5.96875 -6.78125 C 5.640625 -6.78125 5.15625 -6.796875 4.8125 -6.8125 L 4.8125 -6.5 C 5.828125 -6.5 5.828125 -6.03125 5.828125 -5.765625 L 5.828125 -1.5 Z M 2.3125 -6.671875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-2">
|
||||
<path style="stroke:none;" d="M 4.6875 -2.140625 C 4.6875 -3.40625 3.703125 -4.46875 2.5 -4.46875 C 1.25 -4.46875 0.28125 -3.375 0.28125 -2.140625 C 0.28125 -0.84375 1.3125 0.109375 2.484375 0.109375 C 3.6875 0.109375 4.6875 -0.875 4.6875 -2.140625 Z M 2.5 -0.140625 C 2.0625 -0.140625 1.625 -0.34375 1.359375 -0.8125 C 1.109375 -1.25 1.109375 -1.859375 1.109375 -2.21875 C 1.109375 -2.609375 1.109375 -3.140625 1.34375 -3.578125 C 1.609375 -4.03125 2.078125 -4.25 2.484375 -4.25 C 2.921875 -4.25 3.34375 -4.03125 3.609375 -3.59375 C 3.875 -3.171875 3.875 -2.59375 3.875 -2.21875 C 3.875 -1.859375 3.875 -1.3125 3.65625 -0.875 C 3.421875 -0.421875 2.984375 -0.140625 2.5 -0.140625 Z M 2.5 -0.140625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-3">
|
||||
<path style="stroke:none;" d="M 3.78125 -0.546875 L 3.78125 0.109375 L 5.25 0 L 5.25 -0.3125 C 4.5625 -0.3125 4.46875 -0.375 4.46875 -0.875 L 4.46875 -6.921875 L 3.046875 -6.8125 L 3.046875 -6.5 C 3.734375 -6.5 3.8125 -6.4375 3.8125 -5.9375 L 3.8125 -3.78125 C 3.53125 -4.140625 3.09375 -4.40625 2.5625 -4.40625 C 1.390625 -4.40625 0.34375 -3.421875 0.34375 -2.140625 C 0.34375 -0.875 1.3125 0.109375 2.453125 0.109375 C 3.09375 0.109375 3.53125 -0.234375 3.78125 -0.546875 Z M 3.78125 -3.21875 L 3.78125 -1.171875 C 3.78125 -1 3.78125 -0.984375 3.671875 -0.8125 C 3.375 -0.328125 2.9375 -0.109375 2.5 -0.109375 C 2.046875 -0.109375 1.6875 -0.375 1.453125 -0.75 C 1.203125 -1.15625 1.171875 -1.71875 1.171875 -2.140625 C 1.171875 -2.5 1.1875 -3.09375 1.46875 -3.546875 C 1.6875 -3.859375 2.0625 -4.1875 2.609375 -4.1875 C 2.953125 -4.1875 3.375 -4.03125 3.671875 -3.59375 C 3.78125 -3.421875 3.78125 -3.40625 3.78125 -3.21875 Z M 3.78125 -3.21875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-4">
|
||||
<path style="stroke:none;" d="M 1.109375 -2.515625 C 1.171875 -4 2.015625 -4.25 2.359375 -4.25 C 3.375 -4.25 3.484375 -2.90625 3.484375 -2.515625 Z M 1.109375 -2.296875 L 3.890625 -2.296875 C 4.109375 -2.296875 4.140625 -2.296875 4.140625 -2.515625 C 4.140625 -3.5 3.59375 -4.46875 2.359375 -4.46875 C 1.203125 -4.46875 0.28125 -3.4375 0.28125 -2.1875 C 0.28125 -0.859375 1.328125 0.109375 2.46875 0.109375 C 3.6875 0.109375 4.140625 -1 4.140625 -1.1875 C 4.140625 -1.28125 4.0625 -1.3125 4 -1.3125 C 3.921875 -1.3125 3.890625 -1.25 3.875 -1.171875 C 3.53125 -0.140625 2.625 -0.140625 2.53125 -0.140625 C 2.03125 -0.140625 1.640625 -0.4375 1.40625 -0.8125 C 1.109375 -1.28125 1.109375 -1.9375 1.109375 -2.296875 Z M 1.109375 -2.296875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-5">
|
||||
<path style="stroke:none;" d="M 1.90625 -0.53125 C 1.90625 -0.8125 1.671875 -1.0625 1.390625 -1.0625 C 1.09375 -1.0625 0.859375 -0.8125 0.859375 -0.53125 C 0.859375 -0.234375 1.09375 0 1.390625 0 C 1.671875 0 1.90625 -0.234375 1.90625 -0.53125 Z M 1.90625 -0.53125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-6">
|
||||
<path style="stroke:none;" d="M 5.796875 -2.578125 L 5.546875 -2.578125 C 5.4375 -1.5625 5.296875 -0.3125 3.546875 -0.3125 L 2.734375 -0.3125 C 2.265625 -0.3125 2.25 -0.375 2.25 -0.703125 L 2.25 -6.015625 C 2.25 -6.359375 2.25 -6.5 3.1875 -6.5 L 3.515625 -6.5 L 3.515625 -6.8125 C 3.15625 -6.78125 2.25 -6.78125 1.84375 -6.78125 C 1.453125 -6.78125 0.671875 -6.78125 0.328125 -6.8125 L 0.328125 -6.5 L 0.5625 -6.5 C 1.328125 -6.5 1.359375 -6.390625 1.359375 -6.03125 L 1.359375 -0.78125 C 1.359375 -0.421875 1.328125 -0.3125 0.5625 -0.3125 L 0.328125 -0.3125 L 0.328125 0 L 5.515625 0 Z M 5.796875 -2.578125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-7">
|
||||
<path style="stroke:none;" d="M 3.3125 -0.75 C 3.359375 -0.359375 3.625 0.0625 4.09375 0.0625 C 4.3125 0.0625 4.921875 -0.078125 4.921875 -0.890625 L 4.921875 -1.453125 L 4.671875 -1.453125 L 4.671875 -0.890625 C 4.671875 -0.3125 4.421875 -0.25 4.3125 -0.25 C 3.984375 -0.25 3.9375 -0.703125 3.9375 -0.75 L 3.9375 -2.734375 C 3.9375 -3.15625 3.9375 -3.546875 3.578125 -3.921875 C 3.1875 -4.3125 2.6875 -4.46875 2.21875 -4.46875 C 1.390625 -4.46875 0.703125 -4 0.703125 -3.34375 C 0.703125 -3.046875 0.90625 -2.875 1.171875 -2.875 C 1.453125 -2.875 1.625 -3.078125 1.625 -3.328125 C 1.625 -3.453125 1.578125 -3.78125 1.109375 -3.78125 C 1.390625 -4.140625 1.875 -4.25 2.1875 -4.25 C 2.6875 -4.25 3.25 -3.859375 3.25 -2.96875 L 3.25 -2.609375 C 2.734375 -2.578125 2.046875 -2.546875 1.421875 -2.25 C 0.671875 -1.90625 0.421875 -1.390625 0.421875 -0.953125 C 0.421875 -0.140625 1.390625 0.109375 2.015625 0.109375 C 2.671875 0.109375 3.125 -0.296875 3.3125 -0.75 Z M 3.25 -2.390625 L 3.25 -1.390625 C 3.25 -0.453125 2.53125 -0.109375 2.078125 -0.109375 C 1.59375 -0.109375 1.1875 -0.453125 1.1875 -0.953125 C 1.1875 -1.5 1.609375 -2.328125 3.25 -2.390625 Z M 3.25 -2.390625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph0-8">
|
||||
<path style="stroke:none;" d="M 1.75 -4.296875 L 1.75 -5.453125 C 1.75 -6.328125 2.21875 -6.8125 2.65625 -6.8125 C 2.6875 -6.8125 2.84375 -6.8125 2.984375 -6.734375 C 2.875 -6.703125 2.6875 -6.5625 2.6875 -6.3125 C 2.6875 -6.09375 2.84375 -5.890625 3.125 -5.890625 C 3.40625 -5.890625 3.5625 -6.09375 3.5625 -6.328125 C 3.5625 -6.703125 3.1875 -7.03125 2.65625 -7.03125 C 1.96875 -7.03125 1.109375 -6.5 1.109375 -5.4375 L 1.109375 -4.296875 L 0.328125 -4.296875 L 0.328125 -3.984375 L 1.109375 -3.984375 L 1.109375 -0.75 C 1.109375 -0.3125 1 -0.3125 0.34375 -0.3125 L 0.34375 0 C 0.734375 -0.015625 1.203125 -0.03125 1.46875 -0.03125 C 1.875 -0.03125 2.34375 -0.03125 2.734375 0 L 2.734375 -0.3125 L 2.53125 -0.3125 C 1.796875 -0.3125 1.78125 -0.421875 1.78125 -0.78125 L 1.78125 -3.984375 L 2.90625 -3.984375 L 2.90625 -4.296875 Z M 1.75 -4.296875 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph1-1">
|
||||
<path style="stroke:none;" d="M 3.328125 -3.015625 C 3.390625 -3.265625 3.625 -4.1875 4.3125 -4.1875 C 4.359375 -4.1875 4.609375 -4.1875 4.8125 -4.0625 C 4.53125 -4 4.34375 -3.765625 4.34375 -3.515625 C 4.34375 -3.359375 4.453125 -3.171875 4.71875 -3.171875 C 4.9375 -3.171875 5.25 -3.34375 5.25 -3.75 C 5.25 -4.265625 4.671875 -4.40625 4.328125 -4.40625 C 3.75 -4.40625 3.40625 -3.875 3.28125 -3.65625 C 3.03125 -4.3125 2.5 -4.40625 2.203125 -4.40625 C 1.171875 -4.40625 0.59375 -3.125 0.59375 -2.875 C 0.59375 -2.765625 0.703125 -2.765625 0.71875 -2.765625 C 0.796875 -2.765625 0.828125 -2.796875 0.84375 -2.875 C 1.1875 -3.9375 1.84375 -4.1875 2.1875 -4.1875 C 2.375 -4.1875 2.71875 -4.09375 2.71875 -3.515625 C 2.71875 -3.203125 2.546875 -2.546875 2.1875 -1.140625 C 2.03125 -0.53125 1.671875 -0.109375 1.234375 -0.109375 C 1.171875 -0.109375 0.953125 -0.109375 0.734375 -0.234375 C 0.984375 -0.296875 1.203125 -0.5 1.203125 -0.78125 C 1.203125 -1.046875 0.984375 -1.125 0.84375 -1.125 C 0.53125 -1.125 0.296875 -0.875 0.296875 -0.546875 C 0.296875 -0.09375 0.78125 0.109375 1.21875 0.109375 C 1.890625 0.109375 2.25 -0.59375 2.265625 -0.640625 C 2.390625 -0.28125 2.75 0.109375 3.34375 0.109375 C 4.375 0.109375 4.9375 -1.171875 4.9375 -1.421875 C 4.9375 -1.53125 4.859375 -1.53125 4.828125 -1.53125 C 4.734375 -1.53125 4.71875 -1.484375 4.6875 -1.421875 C 4.359375 -0.34375 3.6875 -0.109375 3.375 -0.109375 C 2.984375 -0.109375 2.828125 -0.421875 2.828125 -0.765625 C 2.828125 -0.984375 2.875 -1.203125 2.984375 -1.640625 Z M 3.328125 -3.015625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-0">
|
||||
<path style="stroke:none;" d=""/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-1">
|
||||
<path style="stroke:none;" d="M 2.328125 -4.4375 C 2.328125 -4.625 2.328125 -4.625 2.125 -4.625 C 1.671875 -4.1875 1.046875 -4.1875 0.765625 -4.1875 L 0.765625 -3.9375 C 0.921875 -3.9375 1.390625 -3.9375 1.765625 -4.125 L 1.765625 -0.578125 C 1.765625 -0.34375 1.765625 -0.25 1.078125 -0.25 L 0.8125 -0.25 L 0.8125 0 C 0.9375 0 1.796875 -0.03125 2.046875 -0.03125 C 2.265625 -0.03125 3.140625 0 3.296875 0 L 3.296875 -0.25 L 3.03125 -0.25 C 2.328125 -0.25 2.328125 -0.34375 2.328125 -0.578125 Z M 2.328125 -4.4375 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-2">
|
||||
<path style="stroke:none;" d="M 3.515625 -1.265625 L 3.28125 -1.265625 C 3.265625 -1.109375 3.1875 -0.703125 3.09375 -0.640625 C 3.046875 -0.59375 2.515625 -0.59375 2.40625 -0.59375 L 1.125 -0.59375 C 1.859375 -1.234375 2.109375 -1.4375 2.515625 -1.765625 C 3.03125 -2.171875 3.515625 -2.609375 3.515625 -3.265625 C 3.515625 -4.109375 2.78125 -4.625 1.890625 -4.625 C 1.03125 -4.625 0.4375 -4.015625 0.4375 -3.375 C 0.4375 -3.03125 0.734375 -2.984375 0.8125 -2.984375 C 0.96875 -2.984375 1.171875 -3.109375 1.171875 -3.359375 C 1.171875 -3.484375 1.125 -3.734375 0.765625 -3.734375 C 0.984375 -4.21875 1.453125 -4.375 1.78125 -4.375 C 2.484375 -4.375 2.84375 -3.828125 2.84375 -3.265625 C 2.84375 -2.65625 2.40625 -2.1875 2.1875 -1.9375 L 0.515625 -0.265625 C 0.4375 -0.203125 0.4375 -0.1875 0.4375 0 L 3.3125 0 Z M 3.515625 -1.265625 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-3">
|
||||
<path style="stroke:none;" d="M 1.90625 -2.328125 C 2.453125 -2.328125 2.84375 -1.953125 2.84375 -1.203125 C 2.84375 -0.34375 2.328125 -0.078125 1.9375 -0.078125 C 1.65625 -0.078125 1.03125 -0.15625 0.75 -0.578125 C 1.078125 -0.578125 1.15625 -0.8125 1.15625 -0.96875 C 1.15625 -1.1875 0.984375 -1.34375 0.765625 -1.34375 C 0.578125 -1.34375 0.375 -1.21875 0.375 -0.9375 C 0.375 -0.28125 1.09375 0.140625 1.9375 0.140625 C 2.90625 0.140625 3.578125 -0.515625 3.578125 -1.203125 C 3.578125 -1.75 3.140625 -2.296875 2.375 -2.453125 C 3.09375 -2.71875 3.359375 -3.234375 3.359375 -3.671875 C 3.359375 -4.21875 2.734375 -4.625 1.953125 -4.625 C 1.1875 -4.625 0.59375 -4.25 0.59375 -3.6875 C 0.59375 -3.453125 0.75 -3.328125 0.953125 -3.328125 C 1.171875 -3.328125 1.3125 -3.484375 1.3125 -3.671875 C 1.3125 -3.875 1.171875 -4.03125 0.953125 -4.046875 C 1.203125 -4.34375 1.671875 -4.421875 1.9375 -4.421875 C 2.25 -4.421875 2.6875 -4.265625 2.6875 -3.671875 C 2.6875 -3.375 2.59375 -3.046875 2.40625 -2.84375 C 2.1875 -2.578125 1.984375 -2.5625 1.640625 -2.53125 C 1.46875 -2.515625 1.453125 -2.515625 1.421875 -2.515625 C 1.40625 -2.515625 1.34375 -2.5 1.34375 -2.421875 C 1.34375 -2.328125 1.40625 -2.328125 1.53125 -2.328125 Z M 1.90625 -2.328125 "/>
|
||||
</symbol>
|
||||
<symbol overflow="visible" id="glyph2-4">
|
||||
<path style="stroke:none;" d="M 3.6875 -1.140625 L 3.6875 -1.390625 L 2.90625 -1.390625 L 2.90625 -4.5 C 2.90625 -4.640625 2.90625 -4.703125 2.765625 -4.703125 C 2.671875 -4.703125 2.640625 -4.703125 2.578125 -4.59375 L 0.265625 -1.390625 L 0.265625 -1.140625 L 2.328125 -1.140625 L 2.328125 -0.578125 C 2.328125 -0.328125 2.328125 -0.25 1.75 -0.25 L 1.5625 -0.25 L 1.5625 0 C 1.921875 -0.015625 2.359375 -0.03125 2.609375 -0.03125 C 2.875 -0.03125 3.3125 -0.015625 3.671875 0 L 3.671875 -0.25 L 3.484375 -0.25 C 2.90625 -0.25 2.90625 -0.328125 2.90625 -0.578125 L 2.90625 -1.140625 Z M 2.375 -3.9375 L 2.375 -1.390625 L 0.53125 -1.390625 Z M 2.375 -3.9375 "/>
|
||||
</symbol>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface1">
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="95.682" y="10.239"/>
|
||||
<use xlink:href="#glyph0-2" x="103.15395" y="10.239"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="108.414203" y="10.239"/>
|
||||
<use xlink:href="#glyph0-4" x="113.949423" y="10.239"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="121.696" y="10.239"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-1" x="127.39" y="11.734"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="24.816" y="52.759"/>
|
||||
<use xlink:href="#glyph0-2" x="32.28795" y="52.759"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="37.548203" y="52.759"/>
|
||||
<use xlink:href="#glyph0-4" x="43.083423" y="52.759"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="50.83" y="52.759"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-2" x="56.524" y="54.253"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M -12.872563 -7.726906 L -57.993656 -34.793312 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="3.321" y="93.092"/>
|
||||
<use xlink:href="#glyph0-5" x="6.08861" y="93.092"/>
|
||||
<use xlink:href="#glyph0-5" x="8.856221" y="93.092"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -77.306156 -50.246437 L -102.931156 -80.996437 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="74.187" y="93.092"/>
|
||||
<use xlink:href="#glyph0-5" x="76.95461" y="93.092"/>
|
||||
<use xlink:href="#glyph0-5" x="79.722221" y="93.092"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M -64.42725 -50.246437 L -38.80225 -80.996437 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="166.549" y="52.759"/>
|
||||
<use xlink:href="#glyph0-2" x="174.02095" y="52.759"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="179.281203" y="52.759"/>
|
||||
<use xlink:href="#glyph0-4" x="184.816423" y="52.759"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="192.562" y="52.759"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-3" x="198.256" y="54.253"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 12.873531 -7.726906 L 57.994625 -34.793312 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-5" x="145.053" y="93.092"/>
|
||||
<use xlink:href="#glyph0-5" x="147.82061" y="93.092"/>
|
||||
<use xlink:href="#glyph0-5" x="150.588221" y="93.092"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 64.428219 -50.246437 L 38.803219 -80.996437 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-1" x="201.982" y="95.279"/>
|
||||
<use xlink:href="#glyph0-2" x="209.45395" y="95.279"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-3" x="214.714203" y="95.279"/>
|
||||
<use xlink:href="#glyph0-4" x="220.249423" y="95.279"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph1-1" x="227.995" y="95.279"/>
|
||||
</g>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph2-4" x="233.689" y="96.773"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.3985,1.99255;stroke-miterlimit:10;" d="M 77.303219 -50.246437 L 99.865719 -77.312844 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-6" x="187.108" y="138.545"/>
|
||||
<use xlink:href="#glyph0-4" x="193.334625" y="138.545"/>
|
||||
<use xlink:href="#glyph0-7" x="197.762004" y="138.545"/>
|
||||
<use xlink:href="#glyph0-8" x="202.743304" y="138.545"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 102.006344 -92.765969 L 86.553219 -120.582375 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
||||
<use xlink:href="#glyph0-6" x="234.352" y="138.545"/>
|
||||
<use xlink:href="#glyph0-4" x="240.578625" y="138.545"/>
|
||||
<use xlink:href="#glyph0-7" x="245.006004" y="138.545"/>
|
||||
<use xlink:href="#glyph0-8" x="249.987304" y="138.545"/>
|
||||
</g>
|
||||
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 110.592281 -92.765969 L 126.045406 -120.582375 " transform="matrix(1,0,0,-1,113.771,7.527)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
+3291
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user