Adds prototype docsite with existing tutorials.

This commit is contained in:
David Vollbracht 2023-11-06 16:54:22 -06:00
parent 5f3fca5d1c
commit e9ad7d1086
63 changed files with 2871 additions and 0 deletions

7
.gitignore vendored
View File

@ -27,3 +27,10 @@ instantclient*
# We use a ci compose file that keeps some extra bits locally to cache
# They are ignored below to avoid them being included in various operations, locally and in ci
.stack-root
# Ignore Hakyll build directories
orville-docsite/site-builder/_cache
orville-docsite/site-builder/_site
# Ignore directories created by samples
orville-docsite/samples/getting-started/orville-getting-started

View File

@ -0,0 +1,4 @@
FROM ghcr.io/flipstone/haskell-tools:debian-stable-ghc-9.4.7-2023-10-31-3286ef4
ADD samples/install-packages.sh /install-packages.sh
RUN sh /install-packages.sh

View File

@ -0,0 +1,20 @@
version: "3"
services:
dev:
build: .
environment:
STACK_ROOT: /stack-root
volumes:
- .:/orville-docsite
- stack-root:/stack-root
- ./stack-config.yaml:/stack-root/config.yaml
working_dir: /orville-docsite
# A TTY is required for the test-loop script to use
# stack test. stdin_open would be sufficient, but
# allocating a tty provides colorful test output :)
tty: true
ports:
- 8000:8000
volumes:
stack-root:

View File

@ -0,0 +1,26 @@
module Main
( main
) where
import qualified Orville.PostgreSQL as O
import qualified Orville.PostgreSQL.Execution as Execution
import qualified Orville.PostgreSQL.Raw.Connection as Connection
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import qualified Orville.PostgreSQL.Raw.SqlValue as SqlValue
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
Connection.withPoolConnection pool $ \connection -> do
result <- RawSql.execute connection (RawSql.fromString "SELECT 1+1")
[[(_, sqlValue)]] <- Execution.readRows result
print (SqlValue.toInt sqlValue)

View File

@ -0,0 +1,5 @@
42c42,43
< # extra-deps: []
---
> extra-deps:
> - orville-postgresql-1.0.0.0

View File

@ -0,0 +1,4 @@
22c22
< build-depends: base >= 4.7 && < 5
---
> build-depends: base >= 4.7 && < 5, orville-postgresql ^>= 1.0.0.0

View File

@ -0,0 +1 @@
Right 2

View File

@ -0,0 +1,31 @@
# SNIPPET: hidden
set -e
rm -rf orville-getting-started
service postgresql start
# SNIPPET: initProject
mkdir orville-getting-started
cd orville-getting-started
stack new orville-getting-started --bare simple --resolver lts-21.19
# SNIPPET: hidden
echo "system-ghc: true" >> stack.yaml
echo "install-ghc: false" >> stack.yaml
# SNIPPET: hidden
patch stack.yaml ../add-orville-extra-dep-to-stack-yaml.patch
# SNIPPET: hidden
patch orville-getting-started.cabal ../add-orville-to-cabal-file.patch
# SNIPPET: hidden
cp ../Main.hs src/Main.hs
# SNIPPET: buildAndExecute
stack build
stack exec orville-getting-started
# SNIPPET: hidden
expected=$(cat ../expected-output.txt)
actual=$(stack exec orville-getting-started)
if [ "$expected" = "$actual" ]; then
echo "Output matches expected"
else
echo "Expected output to be: $expected"
echo "But it was actually : $actual"
exit 1
fi;

View File

@ -0,0 +1 @@
Spot found!

View File

@ -0,0 +1,32 @@
cabal-version: 2.2
name: hero
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/flipstone/hero#readme
license: BSD-3-Clause
author: Flipstone Technology Partners, Inc
maintainer: maintainers@flipstone.com
copyright:
category: sample
build-type: Simple
executable hero
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
orville-postgresql,
text
ghc-options: -Wall
-Wcompat
-Widentities
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wmissing-export-lists
-Wmissing-home-modules
-Wpartial-fields
-Wredundant-constraints

View File

@ -0,0 +1,13 @@
set -e
service postgresql start
stack build
expected=$(cat expected-output.txt)
actual=$(stack exec hero)
if [ "$expected" = "$actual" ]; then
echo "Output matches expected"
else
echo "Expected output to be: $expected"
echo "But it was actually : $actual"
exit 1
fi;

View File

@ -0,0 +1,106 @@
module Main (main) where
import Data.Int (Int32)
import qualified Data.Text as T
import qualified Orville.PostgreSQL as O
import qualified Orville.PostgreSQL.AutoMigration as AutoMigration
{- |
Pet is a plain old Haskell record that will be marshalled to and from the
@pet@ table.
-}
data Pet =
Pet
{ petId :: PetId
, petName :: T.Text
}
{- |
It's good practice to create newtype specific to each entity to hold its
primary key value
-}
newtype PetId = PetId Int32
{- |
A marshaller must be defined to convert Pet to and from SQL.
-}
petMarshaller :: O.SqlMarshaller Pet Pet
petMarshaller =
Pet
<$> O.marshallField petId petIdField
<*> O.marshallField petName nameField
{- |
Defines the @id@ field for the marshaller to marshall the 'petId' record
field to and from.
-}
petIdField :: O.FieldDefinition O.NotNull PetId
petIdField =
O.coerceField (O.integerField "id")
{- |
Defines the @name@ field for the marshaller to marshall the 'petName' record
field to and from.
-}
nameField :: O.FieldDefinition O.NotNull T.Text
nameField =
O.unboundedTextField "name"
{- |
Marshaller above is associated with the @pet@ table. The marshallers fields
will define the column of the table.
-}
petTable :: O.TableDefinition (O.HasKey PetId) Pet Pet
petTable =
O.mkTableDefinition
"pet"
(O.primaryKey petIdField)
petMarshaller
{- |
A simple demo that connects to a database, inserts 2 pets and then finds the
pet named "Spot"
-}
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
, O.connectionPoolLingerTime = 10
}
mbSpot <- O.runOrville pool insertAndFindSpot
case mbSpot of
Nothing -> putStrLn "No Spot Found!"
Just _spot -> putStrLn "Spot found!"
{- |
The Orville monad provides a starter pack for running Orville operations
against a connection pool.
-}
insertAndFindSpot :: O.Orville (Maybe Pet)
insertAndFindSpot = do
AutoMigration.autoMigrateSchema
AutoMigration.defaultOptions
[AutoMigration.SchemaTable petTable]
O.insertEntity petTable $
Pet
{ petId = PetId 1
, petName = T.pack "FuFu"
}
O.insertEntity petTable $
Pet
{ petId = PetId 2
, petName = T.pack "Spot"
}
O.findFirstEntityBy
petTable
(O.where_ (O.fieldEquals nameField (T.pack "Spot")))

View File

@ -0,0 +1,69 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-21.13
# resolver: nightly-2023-09-24
# resolver: ghc-9.6.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2023-01-01.yaml
resolver: lts-21.19
system-ghc: true
install-ghc: false
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
extra-deps:
- orville-postgresql-1.0.0.0
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.13"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

View File

@ -0,0 +1,19 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages:
- completed:
hackage: orville-postgresql-1.0.0.0@sha256:35e9b9f8bc0bc1ee1847bcb5340fa39bed320f1573099ec16ca394726a50593a,9018
pantry-tree:
sha256: b8d324f2ad94f12ac419996cc2947ee0c69c5178b2caf13dc92135118602bbd8
size: 12020
original:
hackage: orville-postgresql-1.0.0.0
snapshots:
- completed:
sha256: fb482b8e2d5d061cdda4ba1da2957c012740c893a5ee1c1b99001adae7b1fbe7
size: 640046
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
original: lts-21.19

View File

@ -0,0 +1,13 @@
# SNIPPET: hidden
set -e
# SNIPPET: installLibPqClient
apt update
apt install -y libpq-dev
# SNIPPET: hidden
apt install -y postgresql
sed \
-i \
"s/#listen_addresses = 'localhost'/listen_addresses = 'localhost' /" \
/etc/postgresql/15/main/postgresql.conf
service postgresql start
echo "ALTER USER postgres PASSWORD 'postgres'" | su postgres -c psql

View File

@ -0,0 +1,2 @@
Just (Foo {fooId = 0, fooTags = Array [Number 1.0,Number 2.0,Number 3.0]})
[(0,Number 1.0),(0,Number 2.0),(0,Number 3.0)]

View File

@ -0,0 +1,17 @@
# SNIPPET: hidden
set -e
service postgresql start
# SNIPPET: buildAndExecute
stack build
stack exec using-json
# SNIPPET: hidden
expected=$(cat expected-output.txt)
actual=$(stack exec using-json)
if [ "$expected" = "$actual" ]; then
echo "Output matches expected"
else
echo "Expected output to be: $expected"
echo "But it was actually : $actual"
exit 1
fi;

View File

@ -0,0 +1,94 @@
-- SNIPPET: moduleHeader
module Main
( main
) where
import qualified Orville.PostgreSQL as O
import qualified Orville.PostgreSQL.AutoMigration as AutoMigration
import qualified Orville.PostgreSQL.Marshall as Marshall
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import Control.Monad.IO.Class (MonadIO(liftIO))
import Data.Aeson (Value, eitherDecodeStrict')
import Data.Aeson.Text (encodeToLazyText)
import qualified Data.Aeson as Aeson
import qualified Data.Int as Int
import qualified Data.Text as T
import qualified Data.Text.Encoding as Enc
import qualified Data.Text.Lazy as LazyText
import qualified Data.Vector as Vector
-- SNIPPET: dataTypes
data Foo = Foo
{ fooId :: Int.Int32
, fooTags :: Value
}
deriving Show
fooIdField :: O.FieldDefinition O.NotNull Int.Int32
fooIdField =
O.integerField "id"
fooTagsField :: O.FieldDefinition O.NotNull Value
fooTagsField =
aesonValueField "tags"
-- SNIPPET: aesonValueField
aesonValueField :: String -> O.FieldDefinition O.NotNull Value
aesonValueField name =
O.convertField
(O.tryConvertSqlType encodeJSON decodeJSON)
(O.jsonbField name)
decodeJSON :: T.Text -> Either String Value
decodeJSON =
eitherDecodeStrict' . Enc.encodeUtf8
encodeJSON :: Value -> T.Text
encodeJSON =
LazyText.toStrict . encodeToLazyText
-- SNIPPET: tableDefinition
fooMarshaller :: O.SqlMarshaller Foo Foo
fooMarshaller =
Foo
<$> O.marshallField fooId fooIdField
<*> O.marshallField fooTags fooTagsField
table :: O.TableDefinition (O.HasKey Int.Int32) Foo Foo
table =
O.mkTableDefinition "json_demo" (O.primaryKey fooIdField) fooMarshaller
-- SNIPPET: mainFunction
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
O.runOrville pool $ do
AutoMigration.autoMigrateSchema AutoMigration.defaultOptions [ AutoMigration.SchemaTable table ]
_ <- O.deleteEntity table 0
-- SNIPPET: insertEntity
_ <- O.insertEntity table Foo { fooId = 0
, fooTags = Aeson.Array $ Vector.fromList
[ Aeson.Number 1
, Aeson.Number 2
, Aeson.Number 3
]
}
liftIO . print =<< O.findEntity table 0
-- SNIPPET: selectJSONArray
let
marshaller :: O.SqlMarshaller w (Int.Int32, Value)
marshaller =
(,) <$> O.marshallReadOnlyField fooIdField
<*> O.marshallReadOnlyField (aesonValueField "tag")
readEntities <-
O.executeAndDecode
O.SelectQuery
(RawSql.fromString "SELECT id, jsonb_array_elements(tags) AS tag FROM json_demo")
(Marshall.annotateSqlMarshallerEmptyAnnotation marshaller)
liftIO $ print readEntities

View File

@ -0,0 +1,69 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-21.13
# resolver: nightly-2023-09-24
# resolver: ghc-9.6.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2023-01-01.yaml
resolver: lts-21.19
system-ghc: true
install-ghc: false
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
extra-deps:
- orville-postgresql-1.0.0.0
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.13"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

View File

@ -0,0 +1,19 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages:
- completed:
hackage: orville-postgresql-1.0.0.0@sha256:35e9b9f8bc0bc1ee1847bcb5340fa39bed320f1573099ec16ca394726a50593a,9018
pantry-tree:
sha256: b8d324f2ad94f12ac419996cc2947ee0c69c5178b2caf13dc92135118602bbd8
size: 12020
original:
hackage: orville-postgresql-1.0.0.0
snapshots:
- completed:
sha256: fb482b8e2d5d061cdda4ba1da2957c012740c893a5ee1c1b99001adae7b1fbe7
size: 640046
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
original: lts-21.19

View File

@ -0,0 +1,34 @@
cabal-version: 2.2
name: using-json
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/flipstone/using-json#readme
license: BSD-3-Clause
author: Flipstone Technology Partners, Inc
maintainer: maintainers@flipstone.com
copyright:
category: sample
build-type: Simple
executable using-json
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
orville-postgresql,
aeson,
vector,
text
ghc-options: -Wall
-Wcompat
-Widentities
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wmissing-export-lists
-Wmissing-home-modules
-Wpartial-fields
-Wredundant-constraints

View File

@ -0,0 +1,2 @@
Just (Foo3 {foo3Id = 0, foo3Age = 91})
Just (Foo1 {foo1Id = 0})

View File

@ -0,0 +1,17 @@
# SNIPPET: hidden
set -e
service postgresql start
# SNIPPET: buildAndExecute
stack build
stack exec using-migrations
# SNIPPET: hidden
expected=$(cat expected-output.txt)
actual=$(stack exec using-migrations)
if [ "$expected" = "$actual" ]; then
echo "Output matches expected"
else
echo "Expected output to be: $expected"
echo "But it was actually : $actual"
exit 1
fi;

View File

@ -0,0 +1,89 @@
-- SNIPPET: moduleHeaderAndTypes
module Main
( main
) where
import qualified Orville.PostgreSQL as O
import qualified Orville.PostgreSQL.AutoMigration as AutoMigration
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import Control.Monad.IO.Class (MonadIO(liftIO))
import qualified Data.Int as Int
data Foo1 = Foo1
{ foo1Id :: Int.Int32
}
deriving Show
data Foo2 = Foo2
{ foo2Id :: Int.Int32
, foo2Age :: Maybe Int.Int32
}
deriving Show
data Foo3 = Foo3
{ foo3Id :: Int.Int32
, foo3Age :: Int.Int32
}
deriving Show
fooIdField :: O.FieldDefinition O.NotNull Int.Int32
fooIdField =
O.integerField "id"
fooAgeField :: O.FieldDefinition O.NotNull Int.Int32
fooAgeField =
O.integerField "age"
foo1Marshaller :: O.SqlMarshaller Foo1 Foo1
foo1Marshaller =
Foo1
<$> O.marshallField foo1Id fooIdField
foo2Marshaller :: O.SqlMarshaller Foo2 Foo2
foo2Marshaller =
Foo2
<$> O.marshallField foo2Id fooIdField
<*> O.marshallField foo2Age (O.nullableField fooAgeField)
foo3Marshaller :: O.SqlMarshaller Foo3 Foo3
foo3Marshaller =
Foo3
<$> O.marshallField foo3Id fooIdField
<*> O.marshallField foo3Age fooAgeField
-- SNIPPET: tableDefinitions
table1 :: O.TableDefinition (O.HasKey Int.Int32) Foo1 Foo1
table1 =
O.mkTableDefinition "migration_demo1" (O.primaryKey fooIdField) foo1Marshaller
table2 :: O.TableDefinition (O.HasKey Int.Int32) Foo2 Foo2
table2 =
O.mkTableDefinition "migration_demo1" (O.primaryKey fooIdField) foo2Marshaller
table3 :: O.TableDefinition (O.HasKey Int.Int32) Foo3 Foo3
table3 =
O.mkTableDefinition "migration_demo1" (O.primaryKey fooIdField) foo3Marshaller
-- SNIPPET: mainFunction
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
O.runOrville pool $ do
O.executeVoid O.DDLQuery (RawSql.fromString "DROP TABLE IF EXISTS migration_demo1")
AutoMigration.autoMigrateSchema AutoMigration.defaultOptions [ AutoMigration.SchemaTable table1 ]
_ <- O.insertEntity table1 Foo1 { foo1Id = 0 }
AutoMigration.autoMigrateSchema AutoMigration.defaultOptions [ AutoMigration.SchemaTable table2 ]
_ <- O.updateEntity table2 0 Foo2 { foo2Id = 0, foo2Age = Just 91 }
AutoMigration.autoMigrateSchema AutoMigration.defaultOptions [ AutoMigration.SchemaTable table3 ]
liftIO . print =<< O.findEntity table3 0
-- SNIPPET: droppingColumns
AutoMigration.autoMigrateSchema AutoMigration.defaultOptions [ AutoMigration.SchemaTable $ O.dropColumns ["age"] table1 ]
liftIO . print =<< O.findEntity table1 0

View File

@ -0,0 +1,69 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-21.13
# resolver: nightly-2023-09-24
# resolver: ghc-9.6.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2023-01-01.yaml
resolver: lts-21.19
system-ghc: true
install-ghc: false
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
extra-deps:
- orville-postgresql-1.0.0.0
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.13"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

View File

@ -0,0 +1,19 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages:
- completed:
hackage: orville-postgresql-1.0.0.0@sha256:35e9b9f8bc0bc1ee1847bcb5340fa39bed320f1573099ec16ca394726a50593a,9018
pantry-tree:
sha256: b8d324f2ad94f12ac419996cc2947ee0c69c5178b2caf13dc92135118602bbd8
size: 12020
original:
hackage: orville-postgresql-1.0.0.0
snapshots:
- completed:
sha256: fb482b8e2d5d061cdda4ba1da2957c012740c893a5ee1c1b99001adae7b1fbe7
size: 640046
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
original: lts-21.19

View File

@ -0,0 +1,32 @@
cabal-version: 2.2
name: using-migrations
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/flipstone/using-migrations#readme
license: BSD-3-Clause
author: Flipstone Technology Partners, Inc
maintainer: maintainers@flipstone.com
copyright:
category: sample
build-type: Simple
executable using-migrations
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
orville-postgresql,
text
ghc-options: -Wall
-Wcompat
-Widentities
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wmissing-export-lists
-Wmissing-home-modules
-Wpartial-fields
-Wredundant-constraints

View File

@ -0,0 +1,7 @@
Just (Student {studentId = 0, studentName = "Name", studentAge = 91})
Just (Student {studentId = 1, studentName = "Other Name", studentAge = 42})
[Just (Student {studentId = 1, studentName = "Other Name", studentAge = 42}),Just (Student {studentId = 0, studentName = "Name", studentAge = 91})]
Class {classId = 1, classSubject = "Cooking"}
["SELECT \"student_id\",\"id\",\"class_id\",\"student_id\" FROM \"plan_demo_student_class\" WHERE (\"student_id\") = ($1)","SELECT \"id\",\"id\",\"subject\" FROM \"plan_demo_class\" WHERE (\"id\") IN ($1, $2)"]
["SELECT \"student_id\",\"id\",\"class_id\",\"student_id\" FROM \"plan_demo_student_class\" WHERE (\"student_id\") IN ($1, $2)","SELECT \"id\",\"id\",\"subject\" FROM \"plan_demo_class\" WHERE (\"id\") IN ($1, $2)"]
[[Class {classId = 0, classSubject = "Painting"},Class {classId = 2, classSubject = "Swimming"}]]

View File

@ -0,0 +1,17 @@
# SNIPPET: hidden
set -e
service postgresql start
# SNIPPET: buildAndExecute
stack build
stack exec using-plans
# SNIPPET: hidden
expected=$(cat expected-output.txt)
actual=$(stack exec using-plans)
if [ "$expected" = "$actual" ]; then
echo "Output matches expected"
else
echo "Expected output to be: $expected"
echo "But it was actually : $actual"
exit 1
fi;

View File

@ -0,0 +1,178 @@
-- SNIPPET: moduleHeader
module Main
( main
) where
import qualified Orville.PostgreSQL as O
import qualified Orville.PostgreSQL.AutoMigration as AutoMigration
import qualified Orville.PostgreSQL.Plan as Plan
import Data.List (sort)
import Data.List.NonEmpty (NonEmpty((:|)))
import qualified Data.Int as Int
import qualified Data.Text as T
-------------
-- Student --
-------------
type StudentId = Int.Int32
type StudentName = T.Text
type StudentAge = Int.Int32
data Student = Student
{ studentId :: StudentId
, studentName :: StudentName
, studentAge :: StudentAge
}
deriving Show
studentIdField :: O.FieldDefinition O.NotNull StudentId
studentIdField =
O.integerField "id"
studentNameField :: O.FieldDefinition O.NotNull StudentName
studentNameField =
O.unboundedTextField "name"
studentAgeField :: O.FieldDefinition O.NotNull StudentAge
studentAgeField =
O.integerField "age"
studentMarshaller :: O.SqlMarshaller Student Student
studentMarshaller =
Student
<$> O.marshallField studentId studentIdField
<*> O.marshallField studentName studentNameField
<*> O.marshallField studentAge studentAgeField
studentTable :: O.TableDefinition (O.HasKey StudentId) Student Student
studentTable =
O.mkTableDefinition "plan_demo_student" (O.primaryKey studentIdField) studentMarshaller
----------------------------
-- Student to Class Table --
----------------------------
studentClassIdField :: O.FieldDefinition O.NotNull Int.Int32
studentClassIdField =
O.integerField "id"
studentClassClassIdField :: O.FieldDefinition O.NotNull Int.Int32
studentClassClassIdField =
O.integerField "class_id"
studentClassStudentIdField :: O.FieldDefinition O.NotNull Int.Int32
studentClassStudentIdField =
O.integerField "student_id"
data StudentClass = StudentClass
{ studentClassId :: Int.Int32
, studentClassClassId :: Int.Int32
, studentClassStudentId :: Int.Int32
}
studentClassMarshaller :: O.SqlMarshaller StudentClass StudentClass
studentClassMarshaller =
StudentClass
<$> O.marshallField studentClassId studentClassIdField
<*> O.marshallField studentClassClassId studentClassClassIdField
<*> O.marshallField studentClassStudentId studentClassStudentIdField
studentClassTable :: O.TableDefinition (O.HasKey Int.Int32) StudentClass StudentClass
studentClassTable =
O.addTableConstraints
[ O.foreignKeyConstraint (O.tableIdentifier classTable) $
O.foreignReference (O.fieldName studentClassClassIdField) (O.fieldName classIdField) :| []
, O.foreignKeyConstraint (O.tableIdentifier studentTable) $
O.foreignReference (O.fieldName studentClassStudentIdField) (O.fieldName studentIdField) :| []
]
$ O.mkTableDefinition "plan_demo_student_class" (O.primaryKey studentClassIdField) studentClassMarshaller
-----------
-- Class --
-----------
classIdField :: O.FieldDefinition O.NotNull Int.Int32
classIdField =
O.integerField "id"
classSubjectField :: O.FieldDefinition O.NotNull T.Text
classSubjectField =
O.unboundedTextField "subject"
data Class = Class
{ classId :: Int.Int32
, classSubject :: T.Text
}
deriving (Show, Eq, Ord)
classMarshaller :: O.SqlMarshaller Class Class
classMarshaller =
Class
<$> O.marshallField classId classIdField
<*> O.marshallField classSubject classSubjectField
classTable :: O.TableDefinition (O.HasKey Int.Int32) Class Class
classTable =
O.mkTableDefinition "plan_demo_class" (O.primaryKey classIdField) classMarshaller
-- SNIPPET: mainFunction
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
O.runOrville pool $ do
AutoMigration.autoMigrateSchema AutoMigration.defaultOptions [AutoMigration.SchemaTable studentTable, AutoMigration.SchemaTable classTable, AutoMigration.SchemaTable studentClassTable]
_ <- O.deleteEntity studentClassTable 0
_ <- O.deleteEntity studentClassTable 1
_ <- O.deleteEntity studentClassTable 2
_ <- O.deleteEntity classTable 0
_ <- O.deleteEntity classTable 1
_ <- O.deleteEntity classTable 2
_ <- O.deleteEntity studentTable 0
_ <- O.deleteEntity studentTable 1
_ <- O.insertEntity studentTable Student { studentId = 0, studentName = T.pack "Name", studentAge = 91 }
_ <- O.insertEntity studentTable Student { studentId = 1, studentName = T.pack "Other Name", studentAge = 42 }
_ <- O.insertEntity classTable Class { classId = 0, classSubject = T.pack "Painting" }
_ <- O.insertEntity classTable Class { classId = 1, classSubject = T.pack "Cooking" }
_ <- O.insertEntity classTable Class { classId = 2, classSubject = T.pack "Swimming" }
_ <- O.insertEntity studentClassTable $ StudentClass {studentClassId=0, studentClassClassId=0, studentClassStudentId=0}
_ <- O.insertEntity studentClassTable $ StudentClass {studentClassId=1, studentClassClassId=2, studentClassStudentId=0}
_ <- O.insertEntity studentClassTable $ StudentClass {studentClassId=2, studentClassClassId=1, studentClassStudentId=1}
pure ()
-- SNIPPET: findByStudentId
print =<< O.runOrville pool (Plan.execute (Plan.findMaybeOne studentTable studentIdField) 0)
-- SNIPPET: findByStudentName
print =<< O.runOrville pool (Plan.execute (Plan.findMaybeOne studentTable studentNameField) (T.pack "Other Name"))
-- SNIPPET: findByStudentNameList
print =<< O.runOrville pool (Plan.execute (Plan.planList (Plan.findMaybeOne studentTable studentNameField)) [T.pack "Other Name", T.pack "Name"])
-- SNIPPET: findStudentAndClass
(print =<<) . O.runOrville pool $ Plan.execute
( Plan.findOne studentTable studentNameField
`Plan.chain` Plan.focusParam studentId (Plan.findOne studentClassTable studentClassStudentIdField)
`Plan.chain` Plan.focusParam studentClassClassId (Plan.findOne classTable classIdField)
)
(T.pack "Other Name")
-- SNIPPET: studentsToClassesPlan
let
studentToClassesPlan :: Plan.Plan scope Student [Class]
studentToClassesPlan =
Plan.focusParam studentId (Plan.findAll studentClassTable studentClassStudentIdField)
`Plan.chain` Plan.planList (Plan.focusParam studentClassClassId $ Plan.findOne classTable classIdField)
-- SNIPPET: explainStudentsToClassesPlan
print $ Plan.explain studentToClassesPlan
print $ Plan.explain (Plan.planList studentToClassesPlan)
-- SNIPPET: executeStudentsToClassesPlan
(print =<<) . fmap (fmap sort) . O.runOrville pool $ Plan.execute
( Plan.findAll studentTable studentNameField
`Plan.chain` Plan.planList studentToClassesPlan
)
(T.pack "Name")

View File

@ -0,0 +1,69 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-21.13
# resolver: nightly-2023-09-24
# resolver: ghc-9.6.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2023-01-01.yaml
resolver: lts-21.19
system-ghc: true
install-ghc: false
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
extra-deps:
- orville-postgresql-1.0.0.0
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.13"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

View File

@ -0,0 +1,19 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages:
- completed:
hackage: orville-postgresql-1.0.0.0@sha256:35e9b9f8bc0bc1ee1847bcb5340fa39bed320f1573099ec16ca394726a50593a,9018
pantry-tree:
sha256: b8d324f2ad94f12ac419996cc2947ee0c69c5178b2caf13dc92135118602bbd8
size: 12020
original:
hackage: orville-postgresql-1.0.0.0
snapshots:
- completed:
sha256: fb482b8e2d5d061cdda4ba1da2957c012740c893a5ee1c1b99001adae7b1fbe7
size: 640046
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
original: lts-21.19

View File

@ -0,0 +1,32 @@
cabal-version: 2.2
name: using-plans
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/flipstone/using-plans#readme
license: BSD-3-Clause
author: Flipstone Technology Partners, Inc
maintainer: maintainers@flipstone.com
copyright:
category: sample
build-type: Simple
executable using-plans
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
orville-postgresql,
text
ghc-options: -Wall
-Wcompat
-Widentities
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wmissing-export-lists
-Wmissing-home-modules
-Wpartial-fields
-Wredundant-constraints

View File

@ -0,0 +1 @@
Just (Foo {fooId = 0, fooName = "Name", fooAge = 91})

View File

@ -0,0 +1,17 @@
# SNIPPET: hidden
set -e
service postgresql start
# SNIPPET: buildAndExecute
stack build
stack exec using-sql-marshaller
# SNIPPET: hidden
expected=$(cat expected-output.txt)
actual=$(stack exec using-sql-marshaller)
if [ "$expected" = "$actual" ]; then
echo "Output matches expected"
else
echo "Expected output to be: $expected"
echo "But it was actually : $actual"
exit 1
fi;

View File

@ -0,0 +1,63 @@
-- SNIPPET: moduleHeader
module Main
( main
) where
import qualified Orville.PostgreSQL as O
import qualified Orville.PostgreSQL.AutoMigration as AutoMigration
import qualified Data.Int as Int
import qualified Data.Text as T
-- SNIPPET: dataTypes
type FooId = Int.Int32
type FooName = T.Text
type FooAge = Int.Int32
data Foo = Foo
{ fooId :: FooId
, fooName :: FooName
, fooAge :: FooAge
}
deriving (Eq, Show)
-- SNIPPET: fieldDefinitions
fooIdField :: O.FieldDefinition O.NotNull FooId
fooIdField =
O.integerField "id"
fooNameField :: O.FieldDefinition O.NotNull FooName
fooNameField =
O.unboundedTextField "name"
fooAgeField :: O.FieldDefinition O.NotNull FooAge
fooAgeField =
O.integerField "age"
-- SNIPPET: sqlMarshaller
fooMarshaller :: O.SqlMarshaller Foo Foo
fooMarshaller =
Foo
<$> O.marshallField fooId fooIdField
<*> O.marshallField fooName fooNameField
<*> O.marshallField fooAge fooAgeField
-- SNIPPET: tableDefinition
table :: O.TableDefinition (O.HasKey FooId) Foo Foo
table =
O.mkTableDefinition "foo" (O.primaryKey fooIdField) fooMarshaller
-- SNIPPET: mainFunction
main :: IO ()
main = do
pool <-
O.createConnectionPool
O.ConnectionOptions
{ O.connectionString = "host=localhost user=postgres password=postgres"
, O.connectionNoticeReporting = O.DisableNoticeReporting
, O.connectionPoolStripes = O.OneStripePerCapability
, O.connectionPoolLingerTime = 10
, O.connectionPoolMaxConnections = O.MaxConnectionsPerStripe 1
}
mbFoo <- O.runOrville pool $ do
AutoMigration.autoMigrateSchema AutoMigration.defaultOptions [AutoMigration.SchemaTable table]
_ <- O.deleteEntity table 0
_ <- O.insertEntity table Foo { fooId = 0, fooName = T.pack "Name", fooAge = 91 }
O.findEntity table 0
print mbFoo

View File

@ -0,0 +1,69 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-21.13
# resolver: nightly-2023-09-24
# resolver: ghc-9.6.2
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2023-01-01.yaml
resolver: lts-21.19
system-ghc: true
install-ghc: false
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
extra-deps:
- orville-postgresql-1.0.0.0
# Override default flag values for local packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=2.13"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

View File

@ -0,0 +1,19 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages:
- completed:
hackage: orville-postgresql-1.0.0.0@sha256:35e9b9f8bc0bc1ee1847bcb5340fa39bed320f1573099ec16ca394726a50593a,9018
pantry-tree:
sha256: b8d324f2ad94f12ac419996cc2947ee0c69c5178b2caf13dc92135118602bbd8
size: 12020
original:
hackage: orville-postgresql-1.0.0.0
snapshots:
- completed:
sha256: fb482b8e2d5d061cdda4ba1da2957c012740c893a5ee1c1b99001adae7b1fbe7
size: 640046
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
original: lts-21.19

View File

@ -0,0 +1,32 @@
cabal-version: 2.2
name: using-sql-marshaller
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/flipstone/using-sql-marshaller#readme
license: BSD-3-Clause
author: Flipstone Technology Partners, Inc
maintainer: maintainers@flipstone.com
copyright:
category: sample
build-type: Simple
executable using-sql-marshaller
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
orville-postgresql,
text
ghc-options: -Wall
-Wcompat
-Widentities
-Wincomplete-record-updates
-Wincomplete-uni-patterns
-Wmissing-export-lists
-Wmissing-home-modules
-Wpartial-fields
-Wredundant-constraints

View File

@ -0,0 +1,5 @@
#!/bin/sh
./scripts/stack.sh install
./scripts/test-all-samples.sh
./scripts/site.sh rebuild

View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
docker compose run --rm dev bash

10
orville-docsite/scripts/site.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
set -e
docker compose run \
--rm \
--service-ports \
--workdir /orville-docsite/site-builder \
dev \
stack exec site -- "$@"

View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
docker compose run --rm dev stack "$@"

View File

@ -0,0 +1,11 @@
#!/bin/sh
set -e
for sample_dir in samples/*; do
# If anything in the samples directory is not directory then don't try
# to run it as a sample
if [ -d "$sample_dir" ]; then
./scripts/test-sample.sh $sample_dir
fi
done

View File

@ -0,0 +1,20 @@
#!/bin/sh
set -e
sample_dir=$1
if [ "$1" = "" ]; then
echo "path to sample directory must be specified"
exit 1
fi;
echo "===================================================="
echo "Running $sample_dir"
echo "============================i======================="
docker compose run \
--rm \
--workdir /orville-docsite/$sample_dir \
dev \
sh ./run.sh

View File

@ -0,0 +1,7 @@
---
title: Contact
---
Orville is written and maintained by [Flipstone Technology
Partners](http://flipstone.com). You can reach the package maintainers at <a
href="mailto:maintainers@flipstone.com">maintainers@flipstone.com</a>.

View File

@ -0,0 +1,87 @@
html {
font-size: 62.5%;
background-color: #0d0d13;
}
body {
font-size: 1.6rem;
color: #c7c2c2;
max-width: 1200px;
margin: 0 auto;
}
header {
border-bottom: 0.2rem solid #232629;
}
.leftbar {
position: fixed;
top: 0;
bottom: 0;
width: 200px;
padding-left: 20px;
padding-right: 20px;
}
nav {
margin-top: 20px;
margin-bottom: 20px;
}
main {
margin-left: 260px;
}
nav a {
display: block;
}
a {
text-decoration: none;
color: #8383ff;
}
a:visited {
color: #6455f7;
}
a:hover {
color: #e768d4;
}
footer {
margin-top: 3rem;
padding: 1.2rem 0;
border-top: 0.2rem solid #232629;
font-size: 1.2rem;
}
h1 {
font-size: 2.4rem;
}
h2 {
font-size: 2rem;
}
article .header {
font-size: 1.4rem;
font-style: italic;
color: #555;
}
.logo a {
font-weight: bold;
}
div.sourceCode {
padding: 5px 10px;
margin-top: 0px;
}
.codeblock-label {
background: #1f1f80;
display: inline-block;
padding: 3px 10px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,392 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.8.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.2" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 201 200" overflow="visible" xml:space="preserve">
<g id="Layer_1_00000106848644063259509600000005299531540001616283_">
<path fill="#F4CB68" d="M72.8,46c0.9,0.7,1.7,1.1,2.5,1.2c-0.6,0.6-1.2,1.1-1.8,1.1c-0.6-0.3-1.1-0.6-1.7-1
C72.2,47,72.6,46.5,72.8,46z"/>
<path fill="#EEBC4A" d="M72.9,46c-0.2,0.5,1.3,1.3,1,2c0,0.1-0.1,0.2-0.1,0.2c0.1,0.1,1.2-0.4,1.3-1.1c0.1-0.8-1-1.5-1.8-1.3
C73.2,45.7,73,45.8,72.9,46z"/>
<path fill="#E1B759" d="M73.5,47.2C73,46.3,73,45.1,73,44.4c-0.7,0.4-1.7,1.2-1.8,1.9c0.2,0.6,0.5,1.2,0.8,1.8
C72.4,47.5,72.9,47.3,73.5,47.2z"/>
<path fill="#E1B759" d="M106.7,5.4c0.5-0.5,0.9-1,1.4-1.5c-0.1,1.3,0.7,3.1,1.8,4.8c-0.4,0.4-0.7,0.8-1.1,1.1
C107.9,8.6,107,7,106.7,5.4z"/>
<g>
<path fill="#CB4417" d="M97.5,28C97.2,28.2,74.3,45.5,74,45.7c0,0,0,0,0.1,0.1L84.3,54c2.6,1.8,5.1,3.8,7.5,5.9
c1.6,1.4,3.1,2.8,4.6,4.3c1.9,1.9,3.7,3.9,5.4,5.9c2.5,3,4.8,6.1,6.8,9.4c2,3.2,3.9,6.4,5.9,9.6c1.9,3.1,4.2,5.9,6.8,8.2
c3.2,2.8,6.7,5,10.6,6.6c4,1.7,8.2,2.9,12.4,3.9c2.7,0.6,5.4,1.2,8,1.8c7.1,1.8,13.8,4.6,20.1,8.4c3.1,1.9,6.1,4,8.9,6.3
c2.3,1.9,4.5,3.9,6.7,6c2.1,2,4.1,4,6.2,6c1.3,1.2,2.6,2.4,3.9,3.5c0.1,0.1,0.3,0.2,0.4,0.2c0.1-0.1,0.1-0.1,0.2-0.2
c-0.3-2.5-0.9-5-1.7-7.4c-1.7-5.6-4-11-6.7-16.1c-1.6-3-3.5-5.9-5.5-8.6c-1.9-2.5-3.9-5-6-7.3c-1.9-2.1-3.9-4-5.9-5.9
c-1.7-1.5-3.4-2.9-5.1-4.4c-1.3-1.1-2.5-2.2-3.8-3.4c-1-1-2-2-3-3c-1.6-1.7-3.2-3.5-4.7-5.4c-3.6-4.6-6.5-9.6-9.1-14.8
c-1.8-3.6-3.5-7.3-4.9-11.2c-0.6-1.6-1.1-3.3-1.5-5c-1.3-5.1-3-9.9-5.2-14.6c-1.6-3.3-3.4-6.4-5.5-9.3c-1.6-2.3-3.4-4.4-5.2-6.5
c-0.1-0.1-0.1-0.2-0.1-0.2c-0.9-0.9-1.7-1.8-2.6-2.6c-0.2-0.2-0.5-0.4-0.7-0.6c-2.9-2.7-6-5.2-9.3-7.3c-0.3-0.2-0.5-0.3-0.8-0.5
c0,0.2-0.1,0.4-0.1,0.6L97.5,28z"/>
</g>
<path fill="#F4CB68" d="M199.5,139.8c-0.3-2.4-0.9-4.9-1.7-7.6c-1.8-5.8-4.1-11.2-6.8-16.3c-1.6-2.9-3.4-5.7-5.6-8.7
c-1.9-2.6-3.9-5-6-7.4c-1.9-2.1-3.9-4.1-6-6c-1-0.9-2-1.8-3-2.6c-0.7-0.6-1.4-1.2-2.1-1.8c-1.3-1.2-2.5-2.3-3.7-3.4
c-1-0.9-2-1.9-3-3c-1.5-1.6-3-3.3-4.6-5.4c-3.2-4-6.1-8.7-9.1-14.7c-2.1-4.1-3.6-7.7-4.9-11.1c-0.6-1.6-1.1-3.2-1.5-4.9
c-1.3-5.3-3.1-10.2-5.3-14.7c-1.6-3.3-3.5-6.5-5.6-9.4c-1.7-2.4-3.5-4.6-5.3-6.5l0,0c0,0,0-0.1-0.1-0.1l-0.1-0.1l-2.6-2.7l-0.1-0.1
c-0.1-0.1-0.2-0.1-0.2-0.2c-0.1-0.1-0.3-0.2-0.4-0.3c-2.9-2.8-6.1-5.3-9.4-7.4L112.1,5c-0.5-0.3-0.9-0.6-1.4-0.9
c-0.1,0-0.1-0.1-0.2-0.1c-0.7-0.4-1.4-0.5-2.3-0.4c-0.5,0.6-1,1.2-1.5,1.8c0.8-0.2,1.8,0.1,2.9,0.5c-1.3,2.3-2.6,4.7-3.9,7
c-1.6,2.8-3.3,5.4-5.3,7.8c-1.7,2.1-3.5,4-5.4,5.8l-15.3,14L74,44.7c-0.4-0.2-0.7-0.4-1-0.5c-0.8,0.3-1.5,0.8-1.7,1.7
c1,0.1,2.4,0.7,3.5,1.4l9,7.2l0,0c2.6,1.8,5.1,3.8,7.4,5.9c1.5,1.3,3,2.7,4.5,4.3c1.8,1.8,3.6,3.8,5.4,5.9c2.6,3,4.8,6.2,6.8,9.3
c1.3,2,2.5,4.1,3.7,6.1c0.7,1.2,1.5,2.4,2.2,3.6c2,3.2,4.3,6,7,8.4c3.1,2.8,6.6,5,10.8,6.7c3.7,1.5,7.6,2.8,12.5,3.9
c1.1,0.3,2.3,0.5,3.4,0.8c1.5,0.3,3.1,0.7,4.6,1.1c6.9,1.7,13.6,4.5,19.8,8.3c3,1.8,6,3.9,8.8,6.2c2.2,1.8,4.4,3.7,6.7,5.9
c0.7,0.7,1.4,1.3,2,2c1.4,1.3,2.8,2.7,4.2,4c1,0.9,2,1.8,3,2.7c0.3,0.3,0.6,0.6,1,0.9c0.2,0.1,0.3,0.2,0.4,0.3h0.1l0.5,0.3l0.9-0.9
L199.5,139.8z M197.7,138.4c-1-0.9-2-1.8-2.9-2.7c-1.4-1.3-2.8-2.7-4.2-4c-0.7-0.7-1.4-1.3-2-2c-2.3-2.2-4.5-4.2-6.8-6
c-2.9-2.3-5.9-4.5-9-6.3c-6.4-3.9-13.2-6.7-20.3-8.5c-1.6-0.4-3.1-0.7-4.7-1.1c-1.1-0.2-2.2-0.5-3.3-0.8c-4.8-1.1-8.7-2.4-12.3-3.8
c-4-1.7-7.4-3.8-10.4-6.4c-2.6-2.3-4.8-5-6.7-8.1c-0.7-1.2-1.5-2.4-2.2-3.6c-1.2-2-2.5-4.1-3.7-6.1c-2-3.2-4.3-6.4-6.9-9.5
c-1.8-2.1-3.6-4.1-5.5-6c-1.6-1.6-3.1-3-4.6-4.3c-2.4-2.1-4.9-4.1-7.5-6l-6.9-5.5l2.5-2.3l17.4-15.9c2.2-2,4.1-4.1,5.9-6.3
c2.1-2.6,4-5.4,5.6-8.4c0.8-1.4,1.6-2.9,2.4-4.3l1.7-2.9c2.6,1.8,5.2,3.9,7.6,6.1c0.2,0.2,0.3,0.3,0.5,0.4c0.1,0,0.1,0.1,0.2,0.1
L124,17c0,0.1,0.1,0.2,0.2,0.3c1.8,1.9,3.5,4.1,5.2,6.4c2,2.9,3.9,5.9,5.5,9.2c2.1,4.4,3.9,9.3,5.2,14.4c0.4,1.8,1,3.5,1.6,5.1
c1.3,3.5,2.9,7.1,4.9,11.2c3,6.1,6,10.9,9.2,15c1.7,2.1,3.2,3.9,4.7,5.5c1.1,1.1,2.1,2.1,3.1,3.1c1.2,1.1,2.4,2.2,3.8,3.4
c0.7,0.6,1.4,1.2,2.1,1.8c1,0.8,2,1.7,2.9,2.6c2.1,1.9,4,3.8,5.9,5.9c2.1,2.3,4.1,4.7,5.9,7.2c2.1,2.9,3.9,5.7,5.4,8.5
c2.6,4.9,4.9,10.3,6.7,16C196.9,134.7,197.4,136.6,197.7,138.4L197.7,138.4z"/>
<g>
<path fill="#F4CB68" d="M96.6,42c5.3-4.5,10.3-9.4,15-14.6c1.9-2.3,7.2-7.2,9.9-3.3c2.5,3.7,0.3,9.3-2.4,12.3
c-4.4,4.8-9,9.3-13.9,13.4c-3.2,2.8-8.3,4.2-12,1.7C89.2,48.8,94.4,43.7,96.6,42z M102.2,47.4c5.3-4.4,10.2-9.2,14.8-14.3
c1.8-2.1,1.9-3.6,1.2-4.5c-0.8-1-1.9-0.7-3.7,1.4c-4.8,5.3-9.8,10.2-15.2,14.8c-2.2,1.7-2.5,2.8-1.5,3.6
C98.6,49.1,100.1,49.1,102.2,47.4z M101.6,55.7c8.8-6.5,16.4-13.9,23.3-22.6c0.7-0.9,1.3-1.1,1.7-0.4c0.9,1.6,1.4,2.4,2.2,4
c1.9,3.8,0.4,8.7-2.3,11.6c-0.5,0.6-0.8,0.9-1.3,1.6c-1.5,1.5-3.4,3.6-5.8,2.6c0,0,0,0-0.1,0.1c0.4,2.8-1.8,5.3-3.7,6.8
c-1.4,1.2-2.9,2.4-4.4,3.5c-0.7,0.5-1.2,0.9-1.7,1.3c-0.2,0.2-0.3,0.3-0.4,0.4c-0.6,0.4-1.2,0.3-1.6-0.2s-0.6-0.7-1-1.2
c-0.5-0.5-0.4-1.2,0.3-1.8c0.4-0.3,1-0.8,2.1-1.6c1.7-1.2,3.3-2.4,4.8-3.8c1.5-1.1,2.9-2.9,1.7-4.7c-0.3-0.4-0.5-0.6-0.8-1.1
c-3.3,2.9-6.7,5.6-10.3,8.2c-0.9,0.6-1.8,0.6-2.3,0.1c-0.4-0.4-0.6-0.6-1-1C100.4,57,100.6,56.3,101.6,55.7z M118.9,47.9
c0.8,1.2,1.9,1.3,3.7-0.7c0.7-0.8,1.1-1.2,1.8-2c1.6-1.9,2-3.3,1.3-4.5c-0.3-0.6-0.5-0.9-0.9-1.5c-2.1,2.6-4.4,5.2-6.7,7.6
C118.5,47.2,118.6,47.5,118.9,47.9z M112.3,68.2c7.2-6.8,13.2-14.5,18.6-22.9c0.2-0.3,0.2-0.3,0.2-0.4c0.5-0.8,1-0.8,1.3-0.1
c0.2,0.5,0.3,0.8,0.5,1.4c0.3,0.7,0.1,1.6-0.5,2.6c-4.3,6.7-8.9,13-14.4,18.7c0,0,0,0,0,0.1c5.8-4,11-8.6,15.9-13.9
c0.6-0.7,1-0.7,1.2,0.1c0.1,0.4,0.2,0.6,0.3,1.1c0.2,0.7,0.1,1.6-0.4,2.3c-0.1,0.1-0.1,0.1-0.2,0.3c-5.9,6.2-12.2,11.3-19.6,15.4
c-0.8,0.4-1.4,0.2-1.8-0.4c-0.6-0.9-0.9-1.4-1.6-2.3C111.5,69.4,111.6,68.8,112.3,68.2z M118.3,77.1c6.7-5.1,12.3-11.1,17.4-18
c0.5-0.8,1-0.8,1.3-0.1c0.2,0.5,0.3,0.8,0.5,1.4c0.3,0.7,0.2,1.6-0.3,2.4c-4.9,6.7-10.2,12.6-16.7,17.6c-0.7,0.5-1.3,0.3-1.7-0.3
c-0.3-0.5-0.5-0.7-0.8-1.2C117.5,78.3,117.6,77.6,118.3,77.1z M122,82.7c6.3-4.9,11.6-10.6,16.3-17.2c0.5-0.7,1-0.8,1.3,0
c0.2,0.5,0.4,0.8,0.6,1.3c0.3,0.7,0.3,1.6-0.2,2.3c-4,5.8-8.4,10.8-13.7,15.2c1.3,1.6,2,2.3,3.5,3.7c0.6,0.5,0.5,1.1,0,1.5
c-0.3,0.2-0.5,0.4-0.8,0.6c-0.6,0.4-1.3,0.4-1.9-0.1c-1.9-1.8-3.6-3.6-5.3-5.6C121.2,83.8,121.4,83.2,122,82.7z M130.3,91.3
c5.4-4.3,9.8-9.1,13.6-14.9c0.4-0.6,0.8-0.6,1.2,0c0.3,0.5,0.4,0.7,0.7,1.2c0.4,0.7,0.5,1.4,0.1,2c-3.2,4.9-6.7,9-11.1,12.7
c1.6,1.2,2.5,1.7,4.2,2.8c0.6,0.4,0.7,0.8,0.2,1.2c-0.3,0.2-0.4,0.3-0.7,0.5c-0.5,0.3-1.2,0.3-1.9,0c-2.2-1.3-4.4-2.6-6.5-4
C129.7,92.3,129.7,91.7,130.3,91.3z M140.3,97.6c4.4-3.3,7.8-6.8,10.8-11.5c0.3-0.5,0.7-0.5,1.2,0.1c1.8,2,3.6,3.9,5.5,5.8
c0.5,0.5,0.8,1.1,0.6,1.5c-0.1,0.2-0.2,0.3-0.3,0.5c-0.2,0.4-0.7,0.3-1.2-0.2c-1.6-1.4-2.4-2.1-3.9-3.6c-0.9,1.5-1.4,2.1-2.4,3.4
c1.2,0.9,1.9,1.4,3.2,2.3c0.6,0.4,0.8,0.9,0.5,1.2c-0.2,0.2-0.2,0.3-0.4,0.4c-0.3,0.3-0.9,0.2-1.5-0.2c-1.3-0.8-2-1.3-3.3-2.1
c-1.4,1.4-2.2,2-3.9,3.2c1.9,1,2.8,1.4,4.7,2.3c0.7,0.3,0.8,0.7,0.4,0.9c-0.2,0.1-0.3,0.2-0.6,0.3c-0.4,0.2-1.1,0.2-1.8-0.1
c-2.4-1-4.8-2.1-7.2-3.2C139.9,98.4,139.8,98,140.3,97.6z M96.6,42c5.3-4.5,10.3-9.4,15-14.6c1.9-2.3,7.2-7.2,9.9-3.3
c2.5,3.7,0.3,9.3-2.4,12.3c-4.4,4.8-9,9.3-13.9,13.4c-3.2,2.8-8.3,4.2-12,1.7C89.2,48.8,94.4,43.7,96.6,42z M102.2,47.4
c5.3-4.4,10.2-9.2,14.8-14.3c1.8-2.1,1.9-3.6,1.2-4.5c-0.8-1-1.9-0.7-3.7,1.4c-4.8,5.3-9.8,10.2-15.2,14.8
c-2.2,1.7-2.5,2.8-1.5,3.6C98.6,49.1,100.1,49.1,102.2,47.4z M101.6,55.7c8.8-6.5,16.4-13.9,23.3-22.6c0.7-0.9,1.3-1.1,1.7-0.4
c0.9,1.6,1.4,2.4,2.2,4c1.9,3.8,0.4,8.7-2.3,11.6c-0.5,0.6-0.8,0.9-1.3,1.6c-1.5,1.5-3.4,3.6-5.8,2.6c0,0,0,0-0.1,0.1
c0.4,2.8-1.8,5.3-3.7,6.8c-1.4,1.2-2.9,2.4-4.4,3.5c-0.7,0.5-1.2,0.9-1.7,1.3c-0.2,0.2-0.3,0.3-0.4,0.4c-0.6,0.4-1.2,0.3-1.6-0.2
s-0.6-0.7-1-1.2c-0.5-0.5-0.4-1.2,0.3-1.8c0.4-0.3,1-0.8,2.1-1.6c1.7-1.2,3.3-2.4,4.8-3.8c1.5-1.1,2.9-2.9,1.7-4.7
c-0.3-0.4-0.5-0.6-0.8-1.1c-3.3,2.9-6.7,5.6-10.3,8.2c-0.9,0.6-1.8,0.6-2.3,0.1c-0.4-0.4-0.6-0.6-1-1
C100.4,57,100.6,56.3,101.6,55.7z M118.9,47.9c0.8,1.2,1.9,1.3,3.7-0.7c0.7-0.8,1.1-1.2,1.8-2c1.6-1.9,2-3.3,1.3-4.5
c-0.3-0.6-0.5-0.9-0.9-1.5c-2.1,2.6-4.4,5.2-6.7,7.6C118.5,47.2,118.6,47.5,118.9,47.9z M112.3,68.2c7.2-6.8,13.2-14.5,18.6-22.9
c0.2-0.3,0.2-0.3,0.2-0.4c0.5-0.8,1-0.8,1.3-0.1c0.2,0.5,0.3,0.8,0.5,1.4c0.3,0.7,0.1,1.6-0.5,2.6c-4.3,6.7-8.9,13-14.4,18.7
c0,0,0,0,0,0.1c5.8-4,11-8.6,15.9-13.9c0.6-0.7,1-0.7,1.2,0.1c0.1,0.4,0.2,0.6,0.3,1.1c0.2,0.7,0.1,1.6-0.4,2.3
c-0.1,0.1-0.1,0.1-0.2,0.3c-5.9,6.2-12.2,11.3-19.6,15.4c-0.8,0.4-1.4,0.2-1.8-0.4c-0.6-0.9-0.9-1.4-1.6-2.3
C111.5,69.4,111.6,68.8,112.3,68.2z M118.3,77.1c6.7-5.1,12.3-11.1,17.4-18c0.5-0.8,1-0.8,1.3-0.1c0.2,0.5,0.3,0.8,0.5,1.4
c0.3,0.7,0.2,1.6-0.3,2.4c-4.9,6.7-10.2,12.6-16.7,17.6c-0.7,0.5-1.3,0.3-1.7-0.3c-0.3-0.5-0.5-0.7-0.8-1.2
C117.5,78.3,117.6,77.6,118.3,77.1z M122,82.7c6.3-4.9,11.6-10.6,16.3-17.2c0.5-0.7,1-0.8,1.3,0c0.2,0.5,0.4,0.8,0.6,1.3
c0.3,0.7,0.3,1.6-0.2,2.3c-4,5.8-8.4,10.8-13.7,15.2c1.3,1.6,2,2.3,3.5,3.7c0.6,0.5,0.5,1.1,0,1.5c-0.3,0.2-0.5,0.4-0.8,0.6
c-0.6,0.4-1.3,0.4-1.9-0.1c-1.9-1.8-3.6-3.6-5.3-5.6C121.2,83.8,121.4,83.2,122,82.7z M130.3,91.3c5.4-4.3,9.8-9.1,13.6-14.9
c0.4-0.6,0.8-0.6,1.2,0c0.3,0.5,0.4,0.7,0.7,1.2c0.4,0.7,0.5,1.4,0.1,2c-3.2,4.9-6.7,9-11.1,12.7c1.6,1.2,2.5,1.7,4.2,2.8
c0.6,0.4,0.7,0.8,0.2,1.2c-0.3,0.2-0.4,0.3-0.7,0.5c-0.5,0.3-1.2,0.3-1.9,0c-2.2-1.3-4.4-2.6-6.5-4
C129.7,92.3,129.7,91.7,130.3,91.3z M140.3,97.6c4.4-3.3,7.8-6.8,10.8-11.5c0.3-0.5,0.7-0.5,1.2,0.1c1.8,2,3.6,3.9,5.5,5.8
c0.5,0.5,0.8,1.1,0.6,1.5c-0.1,0.2-0.2,0.3-0.3,0.5c-0.2,0.4-0.7,0.3-1.2-0.2c-1.6-1.4-2.4-2.1-3.9-3.6c-0.9,1.5-1.4,2.1-2.4,3.4
c1.2,0.9,1.9,1.4,3.2,2.3c0.6,0.4,0.8,0.9,0.5,1.2c-0.2,0.2-0.2,0.3-0.4,0.4c-0.3,0.3-0.9,0.2-1.5-0.2c-1.3-0.8-2-1.3-3.3-2.1
c-1.4,1.4-2.2,2-3.9,3.2c1.9,1,2.8,1.4,4.7,2.3c0.7,0.3,0.8,0.7,0.4,0.9c-0.2,0.1-0.3,0.2-0.6,0.3c-0.4,0.2-1.1,0.2-1.8-0.1
c-2.4-1-4.8-2.1-7.2-3.2C139.9,98.4,139.8,98,140.3,97.6z"/>
</g>
<g>
<path fill="#885C00" d="M39.8,97c-4-27,27-39.5,39-39.5c20.5,0,39.8,17.4,43.1,32.9c2.5,11.7-2.5,20.8-2.5,25.7"/>
</g>
<g>
<path fill="#885C00" d="M43,129.4V99.8c-7.1,19.1-15.8,20.5-23.2,22.7c-5.2,1.5-9.9,0.8-11.1,3.6c-1.9,4.6,7.2,15.9,17,16.1
c7.2,0.1,12.4-5.7,17.5-11.8C43,130.1,43,129.7,43,129.4z"/>
</g>
<g>
<path fill-rule="evenodd" fill="#FAE5B8" d="M98.1,104.5l-4,82.8c3.3-0.2,6.6-0.4,9.7-0.7l5.8-82.1
C109.6,104.5,98.1,104.5,98.1,104.5z"/>
</g>
<g>
<path fill-rule="evenodd" fill="#CB4417" d="M40.4,104.5l8.3,81.1c3,0.4,6.3,0.8,9.7,1.1l-6.6-82.2L40.4,104.5L40.4,104.5z"/>
</g>
<g>
<path fill-rule="evenodd" fill="#FAE5B8" d="M52,104.5l5.8,82.1c3.1,0.3,6.3,0.5,9.7,0.7l-4-82.8H52z"/>
</g>
<g>
<path fill-rule="evenodd" fill="#CB4417" d="M63.8,104.5l3.3,82.8c3.1,0.2,6.3,0.3,9.6,0.3l-1.4-83.1
C75.3,104.5,63.8,104.5,63.8,104.5z"/>
</g>
<g>
<g>
<path fill-rule="evenodd" fill="#FAE5B8" d="M75,104.5l1.2,83.1c1.5,0,3,0,4.6,0c1.7,0,3.4,0,5,0l0.7-83.1
C86.5,104.5,75,104.5,75,104.5z"/>
</g>
</g>
<g>
<path fill-rule="evenodd" fill="#CB4417" d="M86.3,104.5l-1.4,83.1c3.3,0,6.5-0.2,9.6-0.3l3.3-82.8H86.3z"/>
</g>
<g>
<path fill-rule="evenodd" fill="#CB4417" d="M109.9,104.5l-6.6,82.2c3.4-0.3,6.7-0.7,9.7-1.1l8.3-81L109.9,104.5L109.9,104.5z"/>
</g>
<g>
<path fill-rule="evenodd" fill="#F4CB68" d="M84.8,100.7C84.8,100.7,84.8,100.6,84.8,100.7v-9.3H64.6v8.8l-3.2,2.4H41.3
c-0.1,2.4,1.4,4.9,3.5,5.4c0.9,0.2,1.7,0.3,2.3,0.2c1.6,1.8,4.2,2.8,5.9,2.1c0.2,0.9,0.5,1.7,1.1,2.3c0.9,0.9,2.2,1.4,3.6,1.3
c1.5-0.1,3-0.8,4-2c0.1-0.1,0.2-0.3,0.2-0.4c0.5,0.1,1.1,0.2,1.6,0.1c1.2-0.2,2.4-0.9,3.3-2c0.8-1.1,1.3-2.4,1.3-3.8
c0.5,0.5,1.1,1,1.9,1.3c0.4,0.2,0.9,0.3,1.3,0.4v0.1c0.7,3.1,3.4,5.4,6.5,5.4c2.5,0.1,4.9-1.4,6.2-3.7c0.1-0.2,0.1-0.5,0-0.7
c0.7,0,1.4-0.1,2-0.3c0.5-0.2,1.1-0.5,1.5-0.9c0.4,2,1.9,3.8,3.9,4.4c0.7,0.2,1.3,0.2,2,0.2c0.5,0.7,1.2,1.2,1.9,1.6
c1.4,0.6,3.2,0.6,4.8-0.2c1.3-0.6,2.2-1.6,2.5-2.8c0.1-0.3,0.1-0.5,0.1-0.8c0.3-0.1,0.6-0.2,0.8-0.3v-6.1h-16L84.8,100.7z"/>
</g>
<g>
<path fill="#885C00" d="M102.2,94.9c0.4,18.7,4.3,34.1,9.4,40.2c5.3,6.5,10.8,12.8,20.1,13c12.6,0.3,26.6-10.8,25.1-15.6
c-0.9-2.9-6.9-4.2-13.5-4.3c-21.5-0.3-24.3-14.3-20.6-28.5"/>
</g>
<path fill="#936037" d="M116.9,107.2c1.8,1.3,3.4,2.5,4.7,3.5l1.1-10c-2.9-2.9-7.3-6.6-13.2-9.9c-0.1-0.8-0.2-1.6-0.5-2.4
c-1.6-5-5.8-7.4-7.4-8.2c-6.5-3.6-13.2-1.6-14.9-1.1c-2.1,0.7-5.3,1.8-7.3,4.7c-0.3,0-0.5-0.1-0.8-0.1c-2.5-0.3-5-0.3-7.4-0.1
c-1.7,0.2-3.4,0.4-5,0.6c-0.2-0.3-0.4-0.5-0.6-0.8c-2.6-3-6.4-3.5-8.8-3.8c-1.8-0.2-8.7-0.8-14.4,4c-1.3,1.1-5,4.3-5.6,9.5
c-0.5,4.6,1.7,8,2.6,9.3c0.2,0.3,0.5,0.7,0.8,1.2l0.4,4.3c0.5-0.6,1.1-1.2,1.8-1.9c1.2,1.1,2.8,2.1,4.8,2.7
c4.8,1.4,8.8-0.5,10.4-1.2c0.7-0.3,8.1-3.9,9.9-12.1c0.1-0.3,0.1-0.6,0.2-1.1c2.9-0.4,6.1-0.6,9.6-0.5c0.3,0,0.5,0,0.8,0
c0.4,1.3,0.8,2.3,1.1,2.9c3.4,7.7,11.4,9.7,12.1,9.9c1.8,0.4,6.1,1.4,10.5-0.9c2.3-1.2,3.8-2.9,4.8-4.5c0.6,0.3,1.3,0.6,1.9,1
c-0.3,9.5,2.4,20,7,28.4c1,1.8,3.2,2.2,4.7,0.8c0.1-0.1,0.1-0.1,0.2-0.2l0,0c1-1.1,1.7-2.5,2-4c0.2-1.2,0.2-2.7-0.7-3.7
C118,119.1,116.8,112.9,116.9,107.2z"/>
<path fill="#683C11" d="M53,81.5c-2.5,0-6.3,0.6-9.5,3.4c-1,0.9-4.1,3.5-4.5,7.8c-0.4,3.8,1.5,6.7,2.1,7.7s2.6,4,6.5,5.2
c1,0.3,2,0.4,3,0.4c2.6,0,4.6-0.9,5.6-1.4c0.4-0.2,2-1,3.6-2.5c2.2-2,3.7-4.5,4.3-7.3c0.1-0.7,0.5-2.2,0.4-4
c-0.1-2.4-0.8-4.4-2.2-5.9c-2.3-2.6-5.4-3-7.3-3.2C54.3,81.6,53.6,81.5,53,81.5"/>
<g>
<path fill="#B8AC47" d="M61.6,85.3c2.7,3,1.7,7.3,1.4,8.6c-1.3,5.9-6.6,8.5-7.1,8.7c-1.2,0.5-4.1,1.9-7.5,0.9
c-3.3-1-5-3.6-5.6-4.5s-2.2-3.4-1.8-6.7c0.4-3.8,3-6,4-6.8c4.1-3.5,9-3,10.3-2.9C57,82.8,59.7,83.1,61.6,85.3z"/>
</g>
<g>
<path fill="#D3C684" d="M50.7,82.7l-0.9,3.4l0,0l-4.3,15.7c0.2,0.2,0.5,0.4,0.8,0.6l0.6-2.1l0,0l4.8-17.7
C51.3,82.6,51,82.6,50.7,82.7z"/>
<path fill="#D3C684" d="M44.8,101.3l0.6-2.2l0,0l4.4-16.2c-1.6,0.4-3.3,1.2-4.8,2.5c-0.4,0.3-1,0.9-1.7,1.7l-0.9,3.3l0,0l-1.2,4.5
c0.4,1.9,1.3,3.3,1.7,4C43.1,99.4,43.8,100.4,44.8,101.3z"/>
</g>
<circle fill="#F2C897" cx="118.8" cy="126.8" r="1.5"/>
<circle fill="#F2C897" cx="116.4" cy="123.1" r="1.3"/>
<circle fill="#F2C897" cx="114.5" cy="119.1" r="1"/>
<g>
<ellipse transform="matrix(0.9998 -1.893504e-02 1.893504e-02 0.9998 -2.497 1.6749)" fill="#FCF2DD" cx="87.2" cy="132.7" rx="7.6" ry="16.3"/>
</g>
<g>
<ellipse transform="matrix(0.9998 -1.893504e-02 1.893504e-02 0.9998 -2.4933 1.2696)" fill="#FCF2DD" cx="65.8" cy="132.3" rx="7.6" ry="16.3"/>
</g>
<g>
<path fill="#F4CB68" d="M110.8,154.6c-0.1-0.1-0.3-0.1-0.4,0c-0.7,0.2-1.6,0.5-2.7,0.8c-2.5,0.6-3.7,0.9-4.9,1c-3.2,0.2-5.8-1-8-2
c-1.9-0.9-1.7-1.1-4.4-2.7c-3.9-2.2-6.2-3.5-9.2-3.5c-1.1,0-3.6,0-5.6,1.7c-0.2,0.2-0.4,0.3-0.5,0.5c-0.2-0.2-0.3-0.3-0.5-0.5
c-2-1.7-4.4-1.7-5.6-1.7c-3.1,0-5.4,1.3-9.2,3.5c-2.7,1.5-2.4,1.7-4.4,2.7c-2.1,1-4.7,2.2-8,2c-1.3-0.1-2.5-0.4-4.9-1
c-1.1-0.3-2-0.5-2.7-0.8c-0.1,0-0.3,0-0.4,0c-0.2,0.1-0.3,0.4-0.2,0.6c0.9,1.8,2.6,4.7,5.9,7c0.8,0.6,2.6,1.8,5.3,2.3
c2.9,0.6,5.1,0.2,7.4-0.3c1.4-0.3,3.5-0.6,5.7-1.6l0,0c0.1,0.3-0.1,0.6-0.5,1.1c-0.7,0.9-1.3,1.1-1.3,1.4c0.1,0.4,0.5,0.6,0.6,0.6
c1.4,0.7,6.5,0.6,10.6-3c0.6-0.5,1.4-1.3,2.1-2.3c0.8,1,1.5,1.8,2.1,2.3c4.1,3.7,9.2,3.7,10.6,3c0.2-0.1,0.6-0.3,0.6-0.6
c0.1-0.4-0.5-0.5-1.3-1.4c-0.4-0.5-0.5-0.8-0.5-1.1l0,0c2.2,1,4.3,1.3,5.7,1.6c2.3,0.4,4.5,0.9,7.4,0.3c2.7-0.6,4.5-1.8,5.3-2.3
c3.3-2.2,5-5.2,5.9-7C111.1,155,111,154.7,110.8,154.6z"/>
</g>
<g>
<path fill="#FAE5B8" d="M78.3,142.3c-1.2-1.6-3.1-2.4-5.2-2c-2.8,0.5-4.7,3.3-4.2,6.1s3.3,4.7,6.1,4.2c1.6-0.3,3-1.4,3.7-2.7"/>
</g>
<path fill="#683C11" d="M106.9,88.3c-1.3-4.2-4.8-6.1-6-6.8c-2.1-1.1-4.3-1.7-6.8-1.7c-2.2,0-4,0.5-5.1,0.8
c-1.8,0.6-4.8,1.6-6.5,4.6c-1,1.8-1.4,3.9-1,6.3c0.3,1.8,0.9,3.2,1.2,3.8c1.1,2.6,3.1,4.7,5.7,6.3c1.9,1.1,3.6,1.6,4.1,1.7
c0.7,0.2,2,0.5,3.5,0.5c1.8,0,3.5-0.4,5.1-1.2c3.6-1.9,4.9-5.2,5.3-6.3C106.8,95.2,108.1,92,106.9,88.3z"/>
<path fill="#FCF2DD" d="M32.5,107.5C32.5,107.5,32.5,107.4,32.5,107.5c-0.2-0.2-0.2-0.3-0.3-0.4l-0.1-0.1c-0.1-0.1-0.1-0.2-0.2-0.2
l-0.1-0.1c-0.1-0.1-0.2-0.2-0.3-0.3c0,0,0,0-0.1,0c-0.1-0.1-0.3-0.2-0.5-0.3c0,0-0.1,0-0.1-0.1c-0.1-0.1-0.3-0.1-0.4-0.2
c-0.1,0-0.1,0-0.2-0.1s-0.3-0.1-0.4-0.2c-0.1,0-0.1,0-0.2-0.1c-0.2-0.1-0.3-0.1-0.5-0.1c0,0,0,0-0.1,0c0,0,0.1,0,0.1-0.1
c0.2-0.1,0.3-0.3,0.5-0.4c0.1,0,0.1-0.1,0.2-0.2s0.3-0.2,0.4-0.4c0.1-0.1,0.1-0.1,0.2-0.2s0.3-0.3,0.4-0.4s0.1-0.1,0.2-0.2
c0.2-0.2,0.4-0.4,0.5-0.7c2.3-3.2,3.6-8.7,0.7-11.8c-0.2-0.2-0.4-0.4-0.7-0.6c-0.1,0-0.1-0.1-0.2-0.1c-0.2-0.2-0.5-0.3-0.7-0.4
c0,0-0.1,0-0.1-0.1c-0.2-0.1-0.4-0.2-0.7-0.3c0,0-0.1,0-0.1-0.1c-0.2-0.1-0.5-0.2-0.7-0.2c-0.1,0-0.1,0-0.2,0
C28.6,89,28.3,89,28.1,89c0,0,0,0-0.1,0c-0.2,0-0.5-0.1-0.7-0.1h-0.1c-0.2,0-0.4,0-0.6,0l0,0c-0.2,0-0.4,0-0.5,0l0,0
c0-0.5-0.1-1-0.1-1.4c0-0.1,0-0.3-0.1-0.4c0-0.3-0.1-0.6-0.2-1c0-0.1,0-0.2-0.1-0.4c-0.1-0.4-0.2-0.8-0.3-1.2l0,0
c-0.1-0.4-0.2-0.7-0.3-1.1c0-0.1-0.1-0.2-0.1-0.3c-0.1-0.2-0.2-0.5-0.3-0.7c0-0.1-0.1-0.2-0.1-0.3c-0.1-0.3-0.2-0.6-0.3-0.8
c-1.8-4.1-3.4-4.5-4-4.6c-0.2,0-0.5,0-0.7,0c-0.5,0.1-0.9,0.2-1.3,0.4c-0.2,0.1-0.4,0.2-0.6,0.3c-0.4,0.2-0.6,0.4-0.9,0.6
c-0.2,0.2-0.3,0.3-0.4,0.3c-0.2,0.2-0.3,0.3-0.4,0.5c0,0.1-0.1,0.1-0.1,0.2c-0.1,0.1-0.1,0.2-0.2,0.4c0,0.1-0.1,0.1-0.1,0.2
s-0.1,0.2-0.1,0.3c0,0.1,0,0.2-0.1,0.3c0,0.1-0.1,0.2-0.1,0.4c0,0.1,0,0.2,0,0.3c0,0.1,0,0.3,0,0.4s0,0.2,0,0.3c0,0.1,0,0.3,0,0.5
c0,0.1,0,0.2,0,0.3c0,0.2,0.1,0.4,0.1,0.6c0,0.1,0,0.2,0,0.3l0,0c-0.3,0.1-0.5,0.1-0.8,0.3c0,0-1.4,0.6-2.1,2
c-0.1,0.2-0.2,0.4-0.2,0.5v0.1c0,0.1-0.1,0.3-0.1,0.5c0,0,0,0,0,0.1c-0.1,0-0.1,0-0.2,0c-0.1,0-0.2,0-0.3,0s-0.3,0-0.4,0
c-0.1,0-0.2,0-0.3,0c-0.2,0-0.3,0-0.5,0c-0.1,0-0.2,0-0.3,0c-0.2,0-0.5,0.1-0.7,0.2c-1.1,0.4-1.8,1.1-2.2,1.7
C7,89,6.8,89.3,6.7,89.5C7,89.8,6.9,90,6.8,90.3c0,0.1,0,0.2-0.1,0.2c0,0.2-0.1,0.3-0.1,0.5c0,0.1,0,0.2,0,0.3c0,0.2,0,0.3-0.1,0.5
c0,0.1,0,0.2,0,0.3c0,0.2,0,0.4,0,0.5s0,0.2,0,0.3c0,0.2,0,0.4,0.1,0.6c0,0.1,0,0.1,0,0.2c0.1,0.6,0.3,1.1,0.5,1.7
c0,0.1,0,0.1,0.1,0.2c0.1,0.2,0.2,0.4,0.3,0.6v0.1c0,0.3-0.1,0.5-0.1,0.8c0,0.1,0,0.2,0,0.2c0,0.2,0,0.5,0,0.7c0,0.1,0,0.2,0,0.3
c0,0.3,0,0.7,0,1c0,0.5,0.2,2.3,0.9,4.2c0.6,1.4,1.4,3,2.9,4c0.5,0.4,1,0.7,1.6,0.9c0.3,0.1,0.6,0.2,0.9,0.3c0.1,0,0.1,0,0.2,0
c0.3,0.1,0.6,0.1,0.9,0.2l0,0l-0.1,0.1c-0.1,0.1-0.2,0.1-0.2,0.2c-0.2,0.2-0.3,0.3-0.5,0.5c-0.1,0.1-0.1,0.2-0.2,0.2
c-0.2,0.2-0.3,0.4-0.4,0.5c0,0.1-0.1,0.1-0.1,0.2c-0.2,0.2-0.3,0.5-0.4,0.7c0,0.1,0,0.1-0.1,0.2c-0.1,0.2-0.1,0.4-0.2,0.5
c0,0.1,0,0.2-0.1,0.2c0,0.2-0.1,0.3-0.1,0.5c0,0.1,0,0.1,0,0.2c0,0.2,0,0.5,0.1,0.7c0.8,2.8,6,3.8,11.6,2.2s9.5-5.2,8.7-8
C32.6,107.8,32.6,107.6,32.5,107.5z"/>
<path fill="#FCF2DD" d="M153.9,163c-0.6-1.6-3.2-1.9-3.5-2c-3.7-0.4-4.9,2.9-8.4,2.6c-2.4-0.2-2.7-1.8-5.3-2.1
c-0.8-0.1-1.5,0-2.2,0.1c0-0.2,0-0.4,0-0.6c0.1-0.7,0-1.3-0.3-1.8c-1.3-1.9-5.8-1.2-9.9,1.6c-3.5,2.4-5.7,5.6-5.4,7.7
c-0.1,0.7,0,1.3,0.4,1.8c0.6,0.9,1.8,1.2,3.3,1.1c0.1,1.5,0.4,2.7,0.5,3.1c0.3,1.1,0.7,2.3,1.1,3.2c0.8,2.1,1.3,4.3,1.2,6.5
l-0.2,3.5c-0.1,0.2-0.7,2.5-0.6,4.6c-0.1,1.7,0.2,3.5,1.6,4.3c1.2,0.7,3.2,0.5,4.4-0.3c0.7-0.5,1.1-1.2,1.3-2.2
c0.2,0.3,1.5,2.2,3.2,2.1c0.3,0,1.8,0,2.8-2c0.3-0.3,0.6-0.7,0.9-1.2c0.1,0,0.2,0.1,0.3,0.1l-0.2,0.9c1.4,0.7,3.4,1.5,5.1,0.6
c0.2-0.1,0.5-0.3,0.8-0.6c0,0,0.1,0,0.2-0.1c0.6-0.4,2.3-1.8,1.6-9.9c-0.1-0.6-0.1-1.3-0.2-2c-0.2-3.1-0.6-6.9-1.7-11.2
c1.5,0.1,3.7-0.1,5.8-1.4c1.8-1.1,4.1-3.6,3.8-5.5C154.1,163.8,154.1,163.4,153.9,163z M132,192.6l0.4,0.5l-0.6,1.1
C131.9,193.8,132,193.2,132,192.6z M144,171.9c-0.1-0.3-0.2-0.6-0.3-0.9c0.2,0,0.3,0,0.5,0.1L144,171.9z"/>
<g>
<path fill="#B8AC47" d="M83.2,85.6c-2,3.5-0.2,7.5,0.3,8.7c2.5,5.5,8.2,7,8.7,7.1c1.3,0.3,4.4,1,7.5-0.6s4.2-4.5,4.6-5.5
s1.5-3.7,0.5-6.9c-1.1-3.6-4.2-5.3-5.3-5.9c-4.7-2.6-9.4-1.2-10.6-0.8C87.2,82.2,84.7,83.1,83.2,85.6z"/>
</g>
<g>
<path fill="#D3C684" d="M93.2,80.9c-2,0.1-3.6,0.5-4.3,0.8c-0.9,0.3-2,0.7-3.1,1.4l-3.4,5.7c-0.2,2.5,0.8,4.8,1.2,5.6
c0.2,0.5,0.4,0.9,0.7,1.3L93.2,80.9z"/>
<path fill="#D3C684" d="M84.7,96.3c0.2,0.3,0.4,0.5,0.6,0.8L95.1,81c-0.3,0-0.7-0.1-1-0.1L84.7,96.3z"/>
</g>
<path fill="#F2C897" d="M156.3,135.4c-2.6,5.3-14.1,13-24.6,12.8c-1.6,0-3.1-0.3-4.5-0.6v0.1c0,1.6,1.2,2.9,2.8,2.9
c1,0,2-0.5,2.5-1.4c0.4,1,1.4,1.8,2.6,1.8c1.2,0,2.2-0.7,2.7-1.7c0.5,0.5,1.2,0.8,1.9,0.8c1.1,0,2.1-0.6,2.6-1.6
c0.5,0.5,1.2,0.8,1.9,0.8c1.5,0,2.7-1,2.9-2.5c0.4,0.2,0.7,0.3,1.2,0.3c1.6,0,2.9-1.2,2.9-2.8c0-0.1,0-0.1,0-0.2l0,0
c1.6,0,2.9-1.2,2.9-2.8c0-0.4-0.1-0.7-0.2-1.1c0.3,0.1,0.7,0.2,1,0.2c1.6,0,2.9-1.2,2.9-2.8C157.7,136.8,157.1,135.9,156.3,135.4z"
/>
</g>
<g id="Black">
<g>
<path fill="#27271F" d="M100,81.5c-2-1.1-4.2-1.7-6.5-1.7c-2.1,0-3.9,0.4-4.9,0.8c-1.7,0.6-4.6,1.6-6.2,4.4
c-1,1.7-1.3,3.7-0.9,5.9c0.3,1.7,0.9,3.1,1.2,3.7c2.6,5.9,8.7,7.5,9.4,7.7c0.7,0.2,1.9,0.4,3.4,0.4c1.7,0,3.4-0.4,4.8-1.2
c3.4-1.8,4.7-5,5.1-6.1s1.6-4.1,0.5-7.6C104.5,84,101.1,82.1,100,81.5z M104.3,95.2c-0.4,1-1.5,3.9-4.6,5.5
c-1.5,0.8-3,1.1-4.4,1.1s-2.5-0.3-3.1-0.4c-0.5-0.1-6.2-1.6-8.7-7.1c-0.5-1.1-2.3-5.2-0.3-8.7c1.4-2.5,4-3.4,5.6-3.9
c0.7-0.2,2.4-0.8,4.6-0.8c1.8,0,3.9,0.4,6,1.5c1.1,0.6,4.1,2.3,5.3,5.9C105.8,91.5,104.7,94.2,104.3,95.2z"/>
<path fill="#27271F" d="M48.1,104.4c0.9,0.3,1.9,0.4,2.8,0.4c2.5,0,4.4-0.9,5.4-1.3c0.6-0.3,6.3-3.1,7.7-9.4
c0.1-0.6,0.5-2.1,0.4-3.9c-0.1-2.2-0.8-4.1-2.1-5.6c-2.1-2.5-5.2-2.8-7-3.1c-0.6-0.1-1.3-0.1-1.9-0.1v1v-1c-2.5,0-6,0.6-9.2,3.2
c-0.5,0.4-1.5,1.3-2.4,2.5c-1.1,1.5-1.8,3.2-2,5c-0.4,3.7,1.3,6.3,2,7.3C42.6,100.4,44.4,103.3,48.1,104.4z M41,92.2
c0.4-3.8,3-6,4-6.8c2.9-2.5,6.4-3,8.5-3c0.8,0,1.4,0.1,1.8,0.1c1.8,0.2,4.4,0.6,6.3,2.7c2.7,3,1.7,7.3,1.4,8.6
c-1.3,5.9-6.6,8.5-7.1,8.7c-0.9,0.4-2.7,1.2-4.9,1.2c-0.8,0-1.6-0.1-2.5-0.4c-3.3-1-5-3.6-5.6-4.5C42.2,98,40.6,95.5,41,92.2z"/>
</g>
<g>
<path fill="#27271F" d="M110.5,4.1c0.1,0,0.1,0,0.2,0.1c0.4,0.3,0.8,0.5,1.2,0.8c0.1-0.1,0.2-0.3,0.3-0.4c0.5-0.7,0.4-1.7-0.3-2.2
c-0.7-0.5-1.7-0.4-2.2,0.3c-0.3,0.4-0.6,0.7-0.9,1.1C109.6,3.7,110,3.8,110.5,4.1z"/>
<path fill="#27271F" d="M102.1,107.2C102.1,107.2,102.2,107.2,102.1,107.2c0.1,0,0.1,0.2,0.1,0.3
C102.2,107.5,102.1,107.4,102.1,107.2z"/>
<path fill="#27271F" d="M73.9,44.8l5.7-4.2l9.6-8.7c5.7-6.3,11.3-12.8,16.8-19.5c1.2-2.1,2.3-4.2,3.5-6.3c-0.7-0.3-1.4-0.5-2-0.5
C99,16.2,90.2,26.4,81.2,36c-2.7,2.9-5.4,5.7-8.2,8.5C73.4,44.4,73.6,44.6,73.9,44.8z"/>
</g>
</g>
<g>
<path fill="#2C2C22" d="M110.5,4.1c0.1,0,0.1,0,0.2,0.1c0.4,0.3,0.8,0.5,1.2,0.8c0.1-0.1,0.2-0.3,0.3-0.4c0.5-0.7,0.4-1.7-0.3-2.2
c-0.7-0.5-1.7-0.4-2.2,0.3c-0.3,0.4-0.6,0.7-0.9,1.1C109.6,3.7,110,3.8,110.5,4.1z"/>
<path fill="#2C2C22" d="M102.1,107.2c0,0,0.1,0,0.1-0.1c0,0.1,0,0.3,0,0.4C102.2,107.5,102.1,107.4,102.1,107.2z"/>
<path fill="#2C2C22" d="M73.9,44.8l5.7-4.2l9.6-8.7c5.7-6.3,11.3-12.8,16.8-19.5c1.2-2.1,2.3-4.2,3.5-6.3c-0.7-0.3-1.4-0.5-2-0.5
c-8.5,10.6-17.3,20.8-26.3,30.4c-2.7,2.9-5.4,5.7-8.2,8.5C73.4,44.4,73.6,44.6,73.9,44.8z"/>
</g>
<path fill="#2C2C22" d="M157.4,135.3c0.4-1,0.5-2,0.2-2.8c-0.5-1.6-2.2-2.9-5.1-3.7c-2.4-0.7-5.5-1.1-9.1-1.1
c-8.5-0.1-14.6-2.4-18-6.9c-1.9-2.6-2.9-5.6-3.1-8.8l1.3-11.6l-0.1-0.1c0-0.1,0-0.1,0-0.2h-0.1c0.2-3,0.2-6.3-0.6-9.8
c-0.8-3.9-2.7-8-5.4-12c-2.7-3.9-6.1-7.6-10-10.8c-8.7-7-18.8-10.8-28.5-10.8c-4.3,0-10.2,1.5-15.8,3.9c-1.6,0.7-3.3,1.6-5.2,2.6
c5.4-4.9,10.7-10,16-15.3c0.1-0.5-0.6-1-0.9-1.4c-0.6-0.2-1.1-0.4-1.6-0.5c-5.9,5.9-11.8,11.5-17.7,16.8c-8.8,7.6-18,14.7-27.4,21.6
c-0.3-1.1-0.7-2.2-1.1-3.2c-1.4-3.2-2.9-4.8-4.7-5c-2.3-0.2-4.3,1.7-4.5,1.9c-1.2,1.2-1.6,2.7-1.3,4.9c-0.1,0-0.1,0-0.2,0.1
c-0.1,0-1.6,0.7-2.5,2.4c-0.1,0.2-0.2,0.5-0.3,0.7c-0.7-0.1-1.5,0-2.3,0.3c-0.9,0.3-2.2,1.1-3.1,2.8c-0.9,1.8-0.9,4.1-0.1,6.3
c0.1,0.3,0.3,0.6,0.4,0.9c-0.1,0.6-0.1,1.1-0.1,1.7C5.3,99,4,99.8,2.7,100.6c-1.3,0.8-1.7,2.6-0.8,3.9c0.9,1.2,2.6,1.5,3.8,0.7
c0.6-0.4,1.2-0.8,1.8-1.3c1,2.6,2.7,4.4,4.9,5.3c0.2,0.1,0.4,0.1,0.7,0.2c-1.3,1.5-1.9,3.1-1.5,4.5c0.5,1.7,2.1,2.8,4.6,3.3
c0.8,0.1,1.6,0.2,2.5,0.2h0.8c0.4,1.2,0.8,2.3,1.2,3.4c-0.5,0.1-1,0.3-1.4,0.4c-1.7,0.5-3.4,0.8-5,1c-3.2,0.5-5.9,0.9-6.9,3.4
c-0.8,2-0.2,4.8,1.8,7.9c1.7,2.6,4.1,5,6.8,6.7c3.1,2.1,6.4,3.2,9.6,3.2h0.3c4.2,0,7.7-1.9,10.9-4.5c0.5,0.3,1.1,0.6,1.6,0.8
c1.8,0.8,3.3,1.2,4.7,1.2h0.1l1.4,14.1c-0.6-0.1-1.3-0.3-2.1-0.5c-0.9-0.2-1.8-0.5-2.7-0.7c-0.4-0.1-0.8-0.1-1.1,0.1
c-0.5,0.3-0.7,1-0.5,1.6c1,2.1,2.9,5.1,6.2,7.3c0.2,0.2,0.6,0.4,1,0.6l2.3,22.8l0.6,0.1c2.7,0.4,5.6,0.7,8.5,1l0.7,0.1
c0.1,0,0.1,0,0.2,0h0.4l0.9,0.1c2.3,0.2,4.7,0.4,7.1,0.5h0.7c0.1,0,0.1,0,0.2,0s0.1,0,0.2,0h0.9c2.4,0.1,4.7,0.2,7.2,0.2h1.1
c0.1,0,0.2,0,0.2,0h10c2.2,0,4.5-0.1,6.7-0.2h0.9c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0h0.7c2.5-0.1,4.9-0.3,7.3-0.5l0.9-0.1h0.4
l0.7-0.1c3-0.3,6-0.6,8.7-1l0.6-0.1l2.8-27.8c1.5,1.6,3,3.4,4.3,5.3c-0.8,0.8-1.4,1.6-1.9,2.5c-1.1,1.9-1.3,3.6-0.4,4.8
c0.6,0.9,1.8,1.4,3.2,1.4c0.1,0.7,0.2,1.6,0.4,2.5c0.3,1,0.6,2.2,1.1,3.3c0.9,2.2,1.3,4.5,1.2,6.9l-0.2,3.5c-0.3,1.1-1.9,7,1.4,8.9
c0.6,0.4,1.4,0.5,2.2,0.5c1.1,0,2.2-0.3,3-0.9c0.5-0.4,0.9-0.8,1.1-1.3c0.7,0.7,1.6,1.3,2.8,1.3c0.1,0,0.1,0,0.2,0
c1.4-0.1,2.6-0.9,3.3-2.2c0,0,0,0,0.1,0.1c1.4,0.7,2.7,1.1,3.8,1.1c0.7,0,1.4-0.2,2-0.5c0.5-0.3,1.2-0.8,1.8-2.4
c0.7-1.8,1-4.5,1-8.1c0-4.4-0.6-8.8-1.6-13.2c1.5,0,3.4-0.4,5.2-1.5c2-1.3,4.9-4.3,4-6.7c-0.8-2-3.6-2.4-4.1-2.4
c-2.1-0.2-3.6,0.6-4.8,1.4c-1.1,0.7-2.1,1.3-3.6,1.2c-1-0.1-1.5-0.4-2.2-0.9c-0.8-0.5-1.6-1.1-3.1-1.2h-1.5c0-0.7-0.1-1.4-0.5-1.9
c-0.8-1.2-2.5-1.7-4.7-1.3c-0.1,0-0.1,0-0.2,0c-3.7-5.6-8.5-10.1-12-13l0.2-2.1c2.3,1.9,5,3.7,8.2,4.6c0.2,1.7,1.6,3.1,3.5,3.2
c0.9,0,1.7-0.3,2.4-0.8c0.7,0.8,1.6,1.3,2.7,1.3h0.1c1.1,0,2.1-0.5,2.8-1.4c0.5,0.3,1.1,0.4,1.7,0.5c1.1,0,2.1-0.4,2.8-1.2
c0.5,0.3,1.1,0.5,1.7,0.5c1.5,0,2.9-0.9,3.4-2.2c0.2,0,0.4,0.1,0.6,0.1c1.8,0.1,3.4-1.3,3.7-3c1.6-0.3,2.9-1.7,3-3.5v-0.1
c0,0,0,0,0.1,0c1,0,1.9-0.3,2.6-1s1.1-1.6,1.1-2.5C158.6,136.9,158.2,135.9,157.4,135.3z M137.3,193.6c-0.5,1.3-1.2,2-2.3,2h-0.2
c-1,0-1.9-1-2.3-1.5c0.2-1,0.2-2.2,0.3-3.7c0.1-3,0.1-6,0.1-8.9c0.6,0.1,1.3,0.2,2,0.2c1.3,0,2.7-0.2,4-0.8
C139,183.7,138.7,189.7,137.3,193.6z M136.6,163.2c1.1,0.1,1.7,0.5,2.4,1s1.5,1,2.9,1.1c2,0.2,3.3-0.7,4.5-1.4
c1.2-0.7,2.2-1.4,3.8-1.2c0.8,0.1,2.5,0.5,2.8,1.5c0.5,1.3-1.4,3.6-3.4,4.9c-1.6,1-3.4,1.3-4.7,1.3c-0.1-0.4-0.5-0.7-0.9-0.6
c-0.4,0.1-0.7,0.5-0.6,0.9c1.3,4.8,1.9,9.7,1.9,14.4c0,5.1-0.7,8.4-2,9.1c-1.3,0.7-3.1,0-4.3-0.6c-0.1,0-0.1,0-0.2-0.1
c1.4-4.5,1.7-10.9,1.5-13.4c1.1-0.7,2-1.5,2.9-2.6c0.3-0.3,0.2-0.8-0.1-1.1c-0.3-0.3-0.8-0.2-1.1,0.1c-1,1.3-2.2,2.2-3.6,2.8
c-4.3,1.9-8.5-0.3-9.3-0.8c-0.4-0.2-0.8-0.1-1.1,0.3c-0.2,0.4-0.1,0.8,0.3,1.1c0.4,0.2,1.5,0.8,3,1.2c0,3.1,0,6.2-0.1,9.3
c0,1.6-0.1,2.8-0.3,3.7c0,0,0,0,0,0.1c-0.2,0.8-0.5,1.3-1,1.7c-1,0.7-2.6,0.8-3.6,0.3c-1.9-1.1-1.1-5.6-0.6-7.2v-0.1l0.2-3.7
c0.1-2.6-0.3-5.1-1.3-7.6c-0.4-1.1-0.8-2.1-1-3.1c-1.5-6.1,1-8.6,1.8-9.3c1.7-1.4,3.8-1.4,4-1.4c2.4,0,4.4,1.6,5.1,4.1
c0.1,0.4,0.5,0.7,1,0.5c0.4-0.1,0.7-0.5,0.5-1c-0.5-1.6-1.3-2.9-2.5-3.8C134.6,163.3,135.6,163.1,136.6,163.2z M124.7,162.5
c0.8-0.5,1.6-1,2.3-1.3h0.1c0-0.1,0.1-0.1,0.1-0.1c1.6-0.8,3.1-1.1,4.3-1.1c1,0,1.7,0.3,2,0.8c0.2,0.3,0.3,0.8,0.2,1.4
c-0.6,0.2-1.2,0.5-1.8,0.8c-0.7-0.3-1.5-0.5-2.4-0.5c-0.5,0-2.9,0-5,1.7c-1.8,1.4-2.7,3.6-2.8,6.4v0.4c-0.9,0-1.5-0.3-1.9-0.7
c-0.5-0.7-0.3-1.8,0.5-3.2C121.2,165.4,122.8,163.8,124.7,162.5z M78.8,58.3c9.4,0,19.1,3.7,27.5,10.5c3.8,3.1,7.1,6.7,9.7,10.4
c2.6,3.8,4.4,7.7,5.2,11.4c0.6,2.9,0.8,5.6,0.6,8.2c-2.5-2.3-6.1-5.3-10.8-8c-0.1-1-0.3-2-0.6-2.9c-0.8-2.4-2.2-4.6-4.1-6.4
c-1.6-1.4-3.1-2.3-4-2.8c-2.8-1.5-5.9-2.3-9.2-2.3c-3,0-5.4,0.6-6.9,1.1c-2.2,0.8-5.8,2-8.1,5.2c-2.3-0.2-4.7-0.2-7,0
c-1.3,0.1-2.5,0.3-3.7,0.5c-0.2-0.3-0.4-0.6-0.7-0.8c-3-3.5-7.3-4-9.8-4.3c-0.9-0.1-1.8-0.2-2.7-0.2c-3.2,0-7.8,0.7-11.9,3.8
c1.2-2.8,2.8-5.5,5-8C56.4,63.1,71.5,58.3,78.8,58.3z M108.5,101.2c0.7-1.2,1.1-2.2,1.3-2.7c0.3-0.8,0.8-2.2,1.1-4
c0.1-0.6,0.2-1.3,0.2-1.9c4.8,2.9,8.3,6,10.6,8.2c-0.6,2.5-1.1,5.3-1.1,8.2C116.6,105.9,112.6,103.4,108.5,101.2z M116,107.6
c0,5.9,1.2,12.1,5.1,16.5c1.5,1.8,0.4,4.8-1,6.2c0,0-0.1,0.1-0.2,0.1c-1.2,1.2-2.9,0.6-3.7-0.7c-4.7-8-6.6-17.1-6.7-26.3
C111.7,104.7,113.9,106.1,116,107.6z M68.2,146.5c0,0.1,0.1,0.2,0.1,0.4c-0.4,0.3-0.8,0.5-1.2,0.7c-0.4,0.1-0.7,0.1-1.1,0.2
c-1.7,0-3.4-1.5-4.7-4.2c-1.4-2.9-2.3-6.9-2.4-11.1c-0.1-2.9,0.3-5.6,0.9-8c-0.1,0.8-0.2,1.7-0.2,2.5c-0.2,5.8,2,10.5,4.8,10.6
c2.6,0.1,4.8-3.9,5.2-9l-3.8-1c-1.1-0.3-1-1.9,0.1-2l3.7-0.5c-0.3-4-1.7-7.2-3.6-8.2c1.5,0.2,3.1,1.7,4.3,4.2
c1.4,2.9,2.3,6.9,2.4,11.1c0.1,2.7-0.2,5.3-0.8,7.6c-1.1,0.4-2.1,1.2-2.8,2.2C68.3,143.3,67.9,144.9,68.2,146.5z M79,106.3
c1.1,1.2,2.5,1.9,3.8,2.3c0,0.1-0.1,0.1-0.1,0.2c-1,1.8-2.8,2.9-4.8,2.9c-2.2-0.1-4.2-1.6-4.9-3.9c1.8-0.1,3.1-0.9,3.3-1
c0.4-0.2,0.5-0.7,0.2-1.1c-0.2-0.4-0.7-0.5-1.1-0.2c-0.1,0.1-2.3,1.4-4.8,0.4c-1.6-0.7-2.4-2.1-2.7-3c0.3-0.7,0.4-1.5,0.5-2.3
c1.4-0.2,2.7-0.9,3.6-2c0.1,0,0.1,0,0.2,0c0.4,0,0.8,0,1.1-0.1c1.6-0.4,2.9-1.5,3.7-3c0,0,0,0,0-0.1c0.3,0.9,0.6,1.5,0.8,1.9
c0.9,1.9,2.1,3.7,3.5,5.2c1.2,1.2,2.6,2.3,4.2,3.3c0.4,0.2,0.7,0.4,1,0.6c-0.3,0.3-0.7,0.6-1.1,0.7c-1.6,0.6-3.8-0.1-5.4-1.8
c-0.3-0.3-0.8-0.3-1.1,0C78.7,105.5,78.7,106,79,106.3z M65.5,115.3c-0.2,0-0.3,0-0.5,0.1l-0.2-4c0.7-0.3,1.4-0.9,2-1.6
c0.8-1.1,1.3-2.4,1.3-3.8c0.5,0.5,1.1,1,1.9,1.3c0.4,0.2,0.9,0.3,1.3,0.4v0.1c0.4,1.8,1.5,3.3,3,4.3l0.4,27.4h-1.2
c0.5-2.3,0.7-4.7,0.7-7.3C74.1,122.6,70.2,115.2,65.5,115.3z M59.9,108.3c-0.1-0.1-0.1-0.1-0.2-0.2c0.8-0.5,1.9-1.2,3-2.2h0.7
c0.7,0,1.5-0.1,2.3-0.6c0.3-0.2,0.6-0.4,0.9-0.6v0.1c0.2,1.4-0.1,2.8-0.9,3.8c-0.6,0.8-1.4,1.3-2.2,1.4
C62.2,110.3,60.8,109.6,59.9,108.3z M60.6,111c-0.7,0.9-1.7,1.4-2.8,1.4c-0.9,0-1.8-0.3-2.4-0.8c-0.3-0.4-0.6-0.8-0.7-1.4
c1.7-0.4,2.9-1,3.7-1.4c0,0,0.1,0,0.1-0.1c0,0.2,0,0.3,0.1,0.5C59.2,110,59.8,110.6,60.6,111z M64.5,104.3c0.8-0.9,1.6-1.8,2.2-2.8
c-0.3,1.2-0.9,2.2-1.8,2.6C64.8,104.2,64.7,104.2,64.5,104.3z M69.9,96.2c-0.3-0.2-0.5-0.4-0.7-0.6c0,0,0,0,0-0.1
c0-0.2,0.1-0.5,0.2-0.8c2.1-0.2,4.2-0.4,6.4-0.4c0,0.1,0,0.1-0.1,0.2c-0.6,1.1-1.6,2-2.7,2.2C72,97.1,70.8,96.9,69.9,96.2z M76.2,92
c0.1,0.3,0.1,0.6,0.2,0.9c-2.4,0-4.6,0.1-6.8,0.4c0.1-0.9,0.2-1.9,0.1-3.1c-0.1-2.1-0.6-4-1.4-5.6c1-0.1,1.9-0.3,2.9-0.3
c2-0.2,4-0.2,6,0C76.1,86.5,75.8,89.1,76.2,92z M68.7,97.3c0.1,0.1,0.2,0.2,0.3,0.2c0.4,0.2,0.7,0.4,1.1,0.5c-0.6,0.4-1.3,0.7-2,0.8
C68.3,98.4,68.5,97.8,68.7,97.3z M67.7,95.3c-1.8,8.2-9.2,11.8-9.9,12.1c-1.2,0.6-3.7,1.7-6.9,1.7c-1.1,0-2.3-0.1-3.5-0.5
c-4.7-1.4-7-5-7.8-6.3c-0.8-1.3-3-4.7-2.6-9.3c0.6-5.2,4.2-8.4,5.6-9.5c4.1-3.5,8.9-4.2,11.9-4.2c1.1,0,2,0.1,2.5,0.2
c2.5,0.3,6.2,0.8,8.8,3.8C69.4,87.6,68,93.6,67.7,95.3z M54.2,112.7c0.8,0.8,2,1.3,3.3,1.3c0.1,0,0.1,0,0.2,0c1.5-0.1,3-0.8,4-2
c0.1-0.1,0.1-0.3,0.2-0.4c0.4,0.1,0.7,0.1,1.1,0.1l0.2,4.3c-3.5,2.1-5.9,8.6-5.8,16.5c0.1,4.5,1,8.6,2.5,11.8c1,2.1,2.3,3.6,3.7,4.4
c-1.3,0.6-2.7,1.4-4.4,2.3c-1.3,0.7-1.9,1.2-2.4,1.5c-0.2,0.1-0.3,0.2-0.5,0.3L54.1,123l-0.9-12.2C53.4,111.5,53.7,112.1,54.2,112.7
z M70.4,142.9c0.7-1,1.7-1.6,2.9-1.9c1.7-0.3,3.4,0.4,4.4,1.7c0.3,0.3,0.7,0.4,1.1,0.2c0.3-0.3,0.4-0.7,0.2-1.1
c-0.6-0.8-1.4-1.5-2.3-1.9l-0.5-27.1c0.5,0.2,1.1,0.3,1.7,0.3c0.1,0,0.1,0,0.2,0c2.4,0,4.8-1.4,6-3.7c0.1-0.2,0.1-0.5,0-0.7h0.3
c0.4,0,0.8-0.1,1.1-0.1l-0.1,7.4c-3.9,1.5-6.7,8.4-6.5,16.9c0.1,4.5,1,8.6,2.5,11.8c0.6,1.2,1.3,2.2,2,3c-0.7-0.1-1.4-0.2-2.1-0.2
c-0.4,0-1,0-1.7,0.1c-0.1-0.1-0.2-0.3-0.3-0.3c-0.4-0.2-0.9-0.1-1,0.3c-0.6,1.2-1.8,2.1-3.1,2.3c-2.4,0.5-4.7-1.1-5.2-3.6
C69.5,145.1,69.8,143.9,70.4,142.9z M82.7,144c-1.4-2.9-2.3-6.9-2.4-11.1c-0.1-2.9,0.3-5.6,0.9-8c-0.1,0.8-0.2,1.7-0.2,2.5
c-0.2,5.8,2,10.5,4.8,10.6c2.6,0.1,4.8-3.9,5.2-9l-3.8-1c-1.1-0.3-1-1.9,0.1-2l3.7-0.5c-0.3-4-1.7-7.2-3.6-8.2
c1.5,0.2,3.1,1.7,4.3,4.2c1.4,2.9,2.3,6.9,2.4,11.1c0.1,4.2-0.6,8.2-1.9,11.2c-1.2,2.8-2.9,4.4-4.6,4.4
C85.8,148.2,84,146.7,82.7,144z M93.5,144.4c1.4-3.2,2.2-7.4,2.1-11.9c-0.2-9.3-3.8-16.6-8.4-16.9l0.1-7.9c0.1-0.1,0.2-0.2,0.3-0.3
c0.4,2.1,1.9,3.9,3.9,4.4c0.5,0.1,0.9,0.2,1.4,0.2h0.6c0.5,0.7,1.2,1.2,1.9,1.6c0.4,0.2,0.8,0.3,1.2,0.3l-1.3,32.3l-0.4,7.2
c-0.8-0.4-1.2-0.6-1.7-1c-0.5-0.4-1.1-0.8-2.4-1.5c-0.9-0.5-1.7-1-2.4-1.4C90.4,149.2,92.2,147.4,93.5,144.4z M89.1,107.4
c0.9,0.3,1.6,0.5,1.9,0.6c0.9,0.2,2.7,0.6,4.8,0.6h0.6c-1,1.5-2.9,2.2-4.5,1.8C90.5,110,89.5,108.8,89.1,107.4z M96,112.2
c-0.4-0.2-0.6-0.4-0.9-0.6c1-0.4,1.9-1.1,2.5-2.1c0.3-0.3,0.2-0.7,0-1c1.1-0.1,2.1-0.4,3.1-0.7c0.5,0.8,0.7,1.7,0.5,2.4
c-0.2,0.8-0.8,1.4-1.7,1.8C98.4,112.5,97,112.6,96,112.2z M96.8,146.4l1.6-32.4c0.6-0.1,1.2-0.3,1.8-0.5c1.3-0.6,2.2-1.6,2.5-2.8
c0.5,3.3,1,6.4,1.7,9.3c0.8,3.2,1.7,6.1,2.7,8.6l-1.2,17.4l-0.7,9.2c-1,0.2-1.7,0.4-2.4,0.4c-2.4,0.2-4.4-0.5-6.2-1.3L96.8,146.4z
M101.9,105.6c-2.1,1.1-4.3,1.5-6.1,1.5c-1.9,0-3.5-0.4-4.4-0.6c-0.7-0.2-8.7-2.2-12.1-9.9c-0.7-1.6-3.2-7.2-0.4-12.1
c2-3.5,5.5-4.7,7.9-5.5c0.9-0.3,3.4-1.1,6.4-1.1c2.5,0,5.5,0.5,8.4,2.1c1.5,0.8,5.8,3.2,7.4,8.2c1.4,4.4-0.1,8.2-0.7,9.6
C107.8,99.3,106.2,103.3,101.9,105.6z M43.7,75.9c-1.6,2.4-2.8,4.9-3.7,7.5c0,0.1-0.1,0.2-0.1,0.3c-0.6,0.6-1.2,1.3-1.8,2.1
c-1.6,2.2-2.5,4.5-2.8,7.1c-0.2,2.2,0.1,4.4,0.9,6.6c0.7,1.8,1.5,3,1.9,3.7c0.3,0.4,0.7,1,1.3,1.8c-2.3,4.8-4.9,8.3-7.8,10.8
c-0.4,0.3-0.8,0.7-1.2,1c-0.3-0.8-0.6-1.6-0.8-2.4c3-1.9,4.6-4.4,3.9-6.6c-0.3-1.2-1.3-2.1-2.7-2.7c0.5-0.5,1.1-1.1,1.5-1.7
c2.3-3.2,4-9.2,0.7-12.8c-1.1-1.2-2.6-1.9-4.5-2.2C33.7,84.3,38.7,80.1,43.7,75.9z M17.1,79.2c0,0,1.6-1.6,3.2-1.4
c1.4,0.2,2.6,2.3,3.4,4.1c0.7,1.6,1.3,4.5,1.6,6.5c-1.5,0.2-3.1,1.3-5.2,3.1c-1.2-2-3.1-5.5-3.6-7.2C16,82.1,15.9,80.4,17.1,79.2z
M13.4,86.1c0.5-0.9,1.4-1.5,1.7-1.6v0.1c0.5,1.9,2.7,5.5,4,7.8c-0.8,0.7-1.7,1.5-2.6,2.4C13.6,91.4,12.4,88,13.4,86.1z M7.8,89.9
c0.7-1.3,1.6-1.8,2.2-2.1c0.5-0.2,1-0.2,1.5-0.2c0,2.4,1.3,5.3,3.8,8.2c-1.2,1.1-1.6,1.9-1.6,2.8c0,0.3,0,0.7,0.1,1
c-1.1,0.1-2.3-0.4-2.5-0.5c-1.6-0.7-2.9-2.2-3.6-4.1C7.1,93.2,7.1,91.3,7.8,89.9z M16.5,115.7c-1.9-0.3-3.1-1.1-3.4-2.2
c-0.4-1.5,1-3.5,3.6-5.1l-0.8-1.3c-0.6,0.3-1.1,0.7-1.5,1.1c-0.5-0.1-1-0.2-1.5-0.4c-1-0.4-3-1.6-4.1-4.8c1-0.7,1.9-1.4,2.9-2.1
c0.5,0.1,1.2,0.3,1.8,0.3c0.3,0,0.6,0,0.9-0.1c0.1,0.2,0.2,0.3,0.4,0.5c1.2,1.3,3.2,2.2,5,2.3c3,0.1,5.9-2.2,7-5.5l-1.5-0.5
c-0.9,2.7-3.2,4.5-5.5,4.4c-1.4,0-3-0.7-3.9-1.8c-0.4-0.4-0.8-1.1-0.8-1.8c0-0.6,0.4-1.1,2.2-2.8c4.2-3.9,6.4-5.8,8.2-6.1
c0.7-0.1,4.1-0.5,6.1,1.7c2.4,2.6,1.5,7.6-0.8,10.8c-2.1,2.9-5.2,3.9-6.9,4.3l0.3,1.5c1.2-0.3,3-0.8,4.9-2c1.4,0.4,2.4,1.1,2.6,2
c0.3,1-0.3,2.4-1.7,3.7c-1.6,1.4-3.8,2.6-6.4,3.4C21.2,115.9,18.6,116.1,16.5,115.7z M25.7,140.9c-5.9-0.1-11.5-4.7-14.2-8.8
c-1.4-2.2-2.1-4.3-1.6-5.5c0.5-1.1,2.2-1.4,4.9-1.8c1.6-0.2,3.4-0.5,5.3-1.1c0.5-0.1,0.9-0.3,1.4-0.4c0.1,0,0.2-0.1,0.4-0.1
c3.5,6.9,8.5,11.4,11.2,13.3c0.4,0.4,0.9,0.7,1.4,1C31.5,139.8,28.7,140.9,25.7,140.9z M41.8,129.9c-1.5-0.8-3.8-2.4-6.1-4.8
c-1.4-1.5-3-3.5-4.3-6c0.6-0.4,1.2-0.8,1.8-1.3c2.5-2.1,4.8-4.9,6.8-8.5l2.1,20.3C42,129.7,41.9,129.8,41.8,129.9z M41.4,107.1
c1.4,1.2,3.2,2.4,5.4,3.1c1.3,0.4,2.6,0.6,4,0.6h0.7l1,12.4l2.2,30.7c-2,0.9-4.4,2-7.2,1.8c-0.4,0-0.7-0.1-1.1-0.1L41.4,107.1z
M49.4,184.9l-2.1-20.6c0.8,0.4,1.8,0.7,2.9,1c2,0.4,3.7,0.4,5.3,0.2l1.4,20.3C54.3,185.5,51.8,185.2,49.4,184.9z M59.1,185.9
L57.4,165c0.1,0,0.3-0.1,0.4-0.1c0.2,0,0.3-0.1,0.5-0.1c0.9-0.2,1.9-0.4,3.1-0.7c-0.3,0.3-0.6,0.6-0.5,1.2c0.1,0.8,0.8,1.1,1.1,1.2
c0.6,0.3,1.4,0.4,2.4,0.4c0.3,0,0.7,0,1.1-0.1l0.8,19.5C63.8,186.3,61.4,186.2,59.1,185.9z M68.2,186.6l-1-19.8
c0.7-0.2,1.6-0.5,2.5-1c0,0,0,0,0.1,0c0,0,0,0,0,0c0.4-0.2,0.9-0.5,1.3-0.7c0,0,0,0,0,0c0.1,0,0.1-0.1,0.2-0.1
c0.8,1.7,2.2,3,3.8,3.5l0,0l0.3,18.4C73,186.7,70.6,186.7,68.2,186.6z M84,186.8h-6.6l-0.2-18.3c1.4-0.2,2.8-1.2,3.7-2.5
c0.5,0.2,1,0.3,1.4,0.5l0.8,0.2c0,0,0.1,0,0.1,0c0,0,0,0,0.1,0c0.3,0.1,0.7,0.1,1,0.2L84,186.8z M93.3,186.6
c-2.2,0.1-4.5,0.2-6.7,0.2l0.2-19.8c0.5-0.1,1-0.2,1.4-0.4c0.2-0.1,0.9-0.5,1.1-1.2c0.1-0.5-0.2-0.9-0.5-1.2
c1.1,0.3,2.2,0.5,3.1,0.7c0.2,0,0.3,0.1,0.5,0.1c0.7,0.1,1.4,0.3,2.1,0.4L93.3,186.6z M92.5,163.4c-0.2,0-0.3-0.1-0.5-0.1
c-1.3-0.3-3.2-0.6-5-1.4c-0.2-0.1-0.5-0.1-0.7,0c-0.2,0.1-0.4,0.3-0.4,0.6c-0.1,0.7,0.3,1.3,0.6,1.7c0.3,0.4,0.7,0.7,0.9,0.9
c-0.4,0.2-1.5,0.3-2.9,0.2c-0.3,0-0.7-0.1-1-0.1c-0.1,0-0.2,0-0.2-0.1c0,0,0,0,0,0c-1.5-0.3-3.6-1.1-5.7-2.9c-0.7-0.6-1.4-1.4-2-2.2
l-0.6-0.9l-0.6,0.9c-0.6,0.8-1.3,1.5-2,2.2c-1.3,1.1-2.6,1.9-3.8,2.4c-0.6,0.2-1.2,0.4-1.7,0.6c-0.1,0-0.2,0.1-0.3,0.1c0,0,0,0,0,0
c0,0,0,0,0,0c-1.9,0.4-3.3,0.2-3.8-0.1c0.2-0.2,0.5-0.5,0.9-0.9c0.4-0.5,0.8-1.1,0.6-1.7c0-0.2-0.2-0.4-0.4-0.6
c-0.2-0.1-0.5-0.1-0.7,0c-1.9,0.8-3.7,1.2-5,1.4c-0.2,0-0.4,0.1-0.5,0.1c-2.2,0.4-4.4,0.9-7.1,0.3c-2.6-0.6-4.3-1.7-5-2.2
c-2.7-1.8-4.4-4.2-5.3-6.1c0.7,0.2,1.4,0.4,2.1,0.6c2.5,0.6,3.7,1,5.1,1.1h0.9c3,0,5.5-1.1,7.5-2.1c1.1-0.5,1.5-0.8,2.1-1.2
c0.5-0.3,1.1-0.7,2.3-1.5c2.7-1.5,4.5-2.5,6.3-3c0.4,0,0.8-0.1,1.3-0.3c0.4-0.1,0.9-0.1,1.3-0.1h0.3c1.1,1.5,2.9,2.5,4.8,2.5
c0.4,0,0.7,0,1.1-0.1c1.4-0.3,2.7-1,3.6-2.2c1-0.2,1.8-0.2,2.3-0.2c2.8,0,4.9,1.1,8.9,3.4c1.2,0.7,1.8,1.1,2.3,1.5
c0.6,0.4,1,0.7,2.1,1.2c2.2,1,4.9,2.3,8.3,2.1c1.3-0.1,2.6-0.4,5.1-1.1c0.7-0.2,1.4-0.4,2.1-0.6c-1,1.9-2.6,4.2-5.3,6.1
c-0.8,0.4-2.5,1.6-5.1,2.1C96.9,164.3,94.8,163.9,92.5,163.4z M102.6,185.9c-2.4,0.2-4.9,0.4-7.4,0.5l0.8-20.9
c1.2,0.1,2.5,0,3.9-0.3c1.9-0.4,3.4-1.2,4.5-1.8L102.6,185.9z M115.2,156.6l-0.1,0.3l-2.9,27.9c-2.5,0.4-5.1,0.7-7.8,0.9l1.7-23.5
c2.9-2.2,4.6-4.8,5.5-6.8c0.3-0.6,0.1-1.2-0.5-1.6c-0.3-0.2-0.7-0.3-1.1-0.1c-0.9,0.3-1.8,0.5-2.7,0.7c-0.3,0.1-0.5,0.1-0.7,0.2
l0.6-8.7l1.1-14.3c0.8,1.5,1.6,2.8,2.5,3.9c1.8,2.2,3.7,4.4,5.8,6.5L115.2,156.6z M129.9,149.7c-0.8,0-1.5-0.5-1.8-1.2
c1.1,0.2,2.2,0.4,3.5,0.4C131.2,149.4,130.6,149.7,129.9,149.7z M136.9,149c-0.3,0.8-1.1,1.3-1.9,1.2c-0.8,0-1.6-0.5-1.9-1.3
c1.3-0.1,2.7-0.2,4-0.5L136.9,149z M151.1,143.4C151.1,143.4,151,143.4,151.1,143.4h-0.9v0.8c0,0.1,0,0.1,0,0.2c0,1.1-0.9,2-2.1,2
c0,0,0,0-0.1,0c-0.3,0-0.6-0.1-0.8-0.2l-1-0.5l-0.1,1.1c-0.1,1-1,1.8-2.1,1.8c-0.5,0-1-0.2-1.4-0.6l-0.8-0.7l-0.5,0.9
c-0.4,0.7-1.1,1.1-1.9,1.1c-0.5,0-1-0.2-1.4-0.6l-0.4-0.4c2.7-0.6,5.5-1.6,8.2-3c2.6-1.3,5-3,7-4.7c0.1,0.2,0.1,0.5,0.1,0.8
C153.1,142.5,152.2,143.4,151.1,143.4z M132.4,147.3h-0.5c-4-0.1-7.7-1.4-11.1-4c-3.2-2.2-5.7-5.1-8.6-8.7
c-2.4-2.9-4.7-8.3-6.3-15.1c-1-4-1.7-8.5-2.2-13.2c1.8-1.1,3-2.5,4-3.9c0.1,0,0.1,0.1,0.2,0.1c0,9.9,2,19.9,7.1,28.6
c1.2,2.2,3.8,2.8,5.7,1c0.1-0.1,0.2-0.2,0.2-0.2c1.2-1.3,2-3.1,2.4-4.8c0.2-1.5,0.3-3-0.7-4.3c-3.4-3.7-4.6-8.9-4.7-14
c1,0.7,1.9,1.4,2.8,2.1c0.2,3.8,1.1,7.6,3.5,10.7c3.7,4.9,10.1,7.4,19.2,7.5c3.4,0,6.4,0.4,8.7,1c2.3,0.7,3.7,1.6,4.1,2.7
c0.3,0.9-0.2,2.2-1.3,3.7C151.5,141.1,141.8,147.3,132.4,147.3z M156.3,139.2c-0.4,0.4-0.9,0.6-1.5,0.6c-0.3,0-0.5-0.1-0.8-0.2
c0.7-0.7,1.4-1.5,1.9-2.2c0.3-0.2,0.4-0.5,0.6-0.8c0.2,0.4,0.4,0.8,0.4,1.2C156.9,138.3,156.7,138.9,156.3,139.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,45 @@
---
title: Home
---
Orville's goal is to provide a powerful API for applications to access
PostgreSQL databases with minimal use of sophisticated language techniques or
extensions. It strikes a balance between enforcing type-safety in database
interactions where it is reasonable and presenting type signatures that are
minimally complicated.
## Why Orville?
Orville is not meant to replace existing PostgreSQL libraries in the Haskell
ecosystem, but to complement them. It has the power to satisfy most experienced
Haskell developers but strives to remain approachable to newcomers despite
this. Orville's API is rich enough to be used in production on large and
sophisticated applications, but avoids complicated type-level programming. If
your application is too large to reasonably write all your SQL statements by
hand yet doesn't require absolute type-safety between your custom SQL
statements, their result sets and the Haskell types they decode into, Orville
may be the right choice for you.
## Feature Overview
* Rich API for marshalling Haskell types to and from SQL
* High-level APIs for common CRUD operations
* Optional automatic schema migrations
* Optional API for executing complex data loads across multiple tables without ever writing an N+1 query by accident
* Progressive escape hatches to let you dig deeper when you need to
## Tutorials
See the tutorials, in order of increasing complexity:
$for(tutorials)$
* <a href="$url$">$title$</a>$endfor$
Additional documentation is available in the Haddocks.
## Just show me some code!
Ok! Here's a very simple application that inserts some entities of a `Pet`
model and finds one of them based on its name.
$sample("hero/src/Main.hs")$

View File

@ -0,0 +1,21 @@
name: site-builder
version: 0.1.0.0
build-type: Simple
cabal-version: >= 1.10
executable site
main-is: site.hs
build-depends: base == 4.*
, hakyll == 4.16.*
, attoparsec
, bytestring
, containers
, data-default
, dlist
, filepath
, non-empty-text
, pandoc
, skylighting
, text
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010

View File

@ -0,0 +1,450 @@
--------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
import qualified Control.Concurrent.MVar as MVar
import qualified Data.ByteString.Lazy as BSL
import Data.Default (def)
import qualified Data.Foldable as Fold
import qualified Data.List as List
import qualified Data.Set as Set
import Data.Ord (comparing)
import Data.Monoid (mappend)
import Hakyll
import Text.Pandoc.Highlighting (Style, breezeDark, styleToCss)
import Text.Pandoc.Options (ReaderOptions(..), WriterOptions(..))
import qualified Text.Read as Read
import qualified Skylighting
import qualified System.FilePath as FilePath
import qualified Data.Attoparsec.Text as AttoText
import qualified Data.Char as Char
import qualified Data.Map.Strict as Map
import qualified Data.NonEmptyText as NET
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import qualified Data.DList as DList
--------------------------------------------------------------------------------
config :: Configuration
config =
def
{ previewHost = "0.0.0.0"
}
pandocCodeStyle :: Style
pandocCodeStyle =
breezeDark
renderPandocInStyle :: Item String -> Compiler (Item String)
renderPandocInStyle =
renderPandocWith
defaultHakyllReaderOptions
(defaultHakyllWriterOptions
{ writerHighlightStyle = Just pandocCodeStyle
})
main :: IO ()
main = do
hakyllWith config $ do
snippetCache <- preprocess newSnippetCache
match "images/*" $ do
route idRoute
compile copyFileCompiler
match "css/*" $ do
route idRoute
compile compressCssCompiler
create ["css/syntax.css"] $ do
route idRoute
compile (makeItem $ styleToCss pandocCodeStyle)
match "contact.md" $ do
route $ setExtension "html"
compile $ pandocCompiler
>>= applyDefaultLayout snippetCache defaultContext
>>= relativizeUrls
let
tutorialsRoute =
composeRoutes
(gsubRoute "tutorials/" (const ""))
(setExtension "html")
match "tutorials/**" $ do
route tutorialsRoute
compile $
getResourceBody
>>= applyAsTemplate (pageCtx snippetCache)
>>= renderPandocInStyle
>>= loadAndApplyTemplate "templates/post.html" (pageCtx snippetCache)
>>= saveSnapshot navLinksSnapshot
>>= applyDefaultLayout snippetCache (pageCtx snippetCache)
>>= relativizeUrls
match "index.md" $ do
route $ setExtension "html"
compile $ do
navContext <- loadNavContex snippetCache
getResourceBody
>>= applyAsTemplate (mconcat [navContext, pageCtx snippetCache])
>>= renderPandocInStyle
>>= applyDefaultLayout snippetCache defaultContext
>>= relativizeUrls
match "templates/*" $ compile templateBodyCompiler
create ["check-all-snippets-used"] $ do
-- This rule doesn't have a route, which causes no actual file to get
-- create for the site, which is what we want.
compile $ do
-- Depend on index since it gets compiled last. This way the other
-- files will populate the snippet cache before we check if all
-- snippets are used.
_index <- load "index.md" :: Compiler (Item String)
recompilingUnsafeCompiler $ failIfAnySnippetsUnused snippetCache
makeItem ("Never seen" :: String)
--------------------------------------------------------------------------------
applyDefaultLayout ::
SnippetCache ->
Context a ->
Item a ->
Compiler (Item String)
applyDefaultLayout snippetCache itemContext item = do
navContext <- loadNavContex snippetCache
loadAndApplyTemplate
"templates/default.html"
(mappend navContext itemContext)
item
{- |
Nav links are generated from a named snapshot of the content items to
avoid the dependency cycle introduced by an item needing a nav link to
itself.
-}
navLinksSnapshot :: String
navLinksSnapshot =
"navLinks"
loadNavContex :: SnippetCache -> Compiler (Context a)
loadNavContex snippetCache = do
tutorials <- inNavOrder =<< loadAllSnapshots "tutorials/*" navLinksSnapshot
pure $
listField "tutorials" (pageCtx snippetCache) (return tutorials)
inNavOrder :: (MonadMetadata m, MonadFail m) => [Item a] -> m [Item a]
inNavOrder =
let
pairWithNavOrder item = do
navOrder <- getNavOrder (itemIdentifier item)
pure (item, navOrder)
in
\items ->
fmap
(map fst . List.sortBy (comparing snd))
(traverse pairWithNavOrder items)
getNavOrder :: (MonadMetadata m, MonadFail m) => Identifier -> m Int
getNavOrder identifier = do
metadata <- getMetadata identifier
case lookupString "navOrder" metadata of
Nothing -> fail $ "navOrder not specified for " <> show identifier
Just navOrder -> either fail pure (Read.readEither navOrder)
pageCtx :: SnippetCache -> Context String
pageCtx snippetCache =
mconcat
[ dateField "date" "%B %e, %Y"
, sampleField snippetCache
, defaultContext
]
sampleField :: SnippetCache -> Context a
sampleField snippetCache =
functionField "sample" $ \args item -> do
case args of
[path] ->
mkMarkdownCodeBlock path =<<
recompilingUnsafeCompiler (TIO.readFile ("../samples/" <> path))
[path, snippetName] -> do
case NET.fromText (T.pack snippetName) of
Nothing ->
fail $ "Snippet name may not be empty"
Just nonEmptySnippetName -> do
errOrSnippet <-
recompilingUnsafeCompiler $
lookupSnippet
snippetCache
("../samples/" <> path)
nonEmptySnippetName
case errOrSnippet of
Left err -> fail $ "Error loading snippet from " <> path <> ": " <> err
Right snippet -> mkMarkdownCodeBlock path snippet
_ -> fail "Wrong number of arguments passed to function sample()"
mkMarkdownCodeBlock :: FilePath -> T.Text -> Compiler String
mkMarkdownCodeBlock path body = do
lang <- either fail pure (guessLang path)
pure $
unlines
[ "<div class=\"codeblock-label\">" <> lang <> "</div>"
, "```" <> lang
, T.unpack body
, "```"
]
guessLang :: FilePath -> Either String String
guessLang path =
case FilePath.takeExtensions path of
".hs" -> Right "haskell"
".sh" -> Right "sh"
".patch" -> Right "diff"
".txt" -> Right "txt"
ext -> Left $ "Unable to determine language for " <> path
type SnippetMap =
Map.Map NET.NonEmptyText T.Text
type SnippetCache =
MVar.MVar (Map.Map FilePath SnippetCacheEntry)
newSnippetCache :: IO SnippetCache
newSnippetCache =
MVar.newMVar Map.empty
failIfAnySnippetsUnused :: SnippetCache -> IO ()
failIfAnySnippetsUnused snippetCache =
MVar.withMVar snippetCache (Fold.traverse_ failIfAnySnippetsUnusedForEntry)
failIfAnySnippetsUnusedForEntry :: MonadFail m => SnippetCacheEntry -> m ()
failIfAnySnippetsUnusedForEntry cacheEntry =
let
allKeys =
Map.keysSet (snippetCacheEntrySnippets cacheEntry)
unusedKeys =
Set.difference allKeys (snippetCacheEntryUsedSnippets cacheEntry)
in
if Set.null unusedKeys
then pure ()
else
fail
$ "Unused snippets found in "
<> snippetCacheEntryPath cacheEntry
<> ": "
<> show unusedKeys
lookupSnippet ::
SnippetCache ->
FilePath ->
NET.NonEmptyText ->
IO (Either String T.Text)
lookupSnippet cacheVar path snippetName =
if snippetName == hiddenSnippetName
then
pure . Left $
"Snippets with the name "
<> show hiddenSnippetName
<> " cannot be referenced in templates."
else
MVar.modifyMVar cacheVar $ \cacheMap -> do
errOrMapAndEntry <-
case Map.lookup path cacheMap of
Just cacheEntry ->
pure . Right $ (cacheMap, cacheEntry)
Nothing -> do
errOrSnippets <- loadSnippetsFile path
case errOrSnippets of
Left err -> pure . Left $ err
Right snippets ->
let
cacheEntry =
SnippetCacheEntry
{ snippetCacheEntryPath = path
, snippetCacheEntrySnippets = snippets
, snippetCacheEntryUsedSnippets = Set.empty
}
in
pure . Right $
( Map.insert path cacheEntry cacheMap
, cacheEntry
)
pure $
case errOrMapAndEntry of
Left err -> (cacheMap, Left err)
Right (newMap, cacheEntry) ->
let
snippet =
case Map.lookup snippetName (snippetCacheEntrySnippets cacheEntry) of
Nothing -> Left $ "Snippet " <> show snippetName <> " not found in " <> path
Just snippet -> Right snippet
newMapWithSnippetMarkedUsed =
Map.adjust
(markSnippetUsed snippetName)
path
newMap
in
( newMapWithSnippetMarkedUsed
, snippet
)
data SnippetCacheEntry =
SnippetCacheEntry
{ snippetCacheEntryPath :: FilePath
, snippetCacheEntrySnippets :: SnippetMap
, snippetCacheEntryUsedSnippets :: Set.Set NET.NonEmptyText
}
loadSnippetsFile :: FilePath -> IO (Either String SnippetMap)
loadSnippetsFile =
fmap (AttoText.parseOnly snippets) . TIO.readFile
markSnippetUsed :: NET.NonEmptyText -> SnippetCacheEntry -> SnippetCacheEntry
markSnippetUsed snippetName cacheEntry =
cacheEntry
{ snippetCacheEntryUsedSnippets =
Set.insert
snippetName
(snippetCacheEntryUsedSnippets cacheEntry)
}
hiddenSnippetName :: NET.NonEmptyText
hiddenSnippetName =
NET.new 'h' "idden"
snippets :: AttoText.Parser SnippetMap
snippets =
let
insertChunks snippetMarker chunks snippets =
let
name =
snippetMarkerName snippetMarker
in
if name == hiddenSnippetName
then pure snippets
else
if Map.member name snippets
then
fail $
"Snippet names must be unique within their file. "
<> show name
<> " appears more than once."
else
pure $
Map.insert
name
(T.concat . DList.toList $ chunks)
snippets
go snippets chunks snippetMarker = do
let
snippetLeadingChar =
NET.head
. snippetMarkerPrefix
$ snippetMarker
nextChunk <- AttoText.takeTill (== snippetLeadingChar)
let
newChunks =
DList.snoc chunks nextChunk
atEnd <- AttoText.atEnd
if atEnd
then insertChunks snippetMarker newChunks snippets
else do
nextNameOrBrace <-
AttoText.eitherP
(snippetMarkerWithMatchingPrefix snippetMarker)
(AttoText.string (T.singleton snippetLeadingChar))
case nextNameOrBrace of
Left nextName -> do
newSnippets <- insertChunks snippetMarker newChunks snippets
go
newSnippets
DList.empty
nextName
Right followingBrace -> do
go
snippets
(DList.snoc newChunks followingBrace)
snippetMarker
in
go Map.empty DList.empty =<< snippetMarkerWithAnyPrefix
{- |
Parses a magic haskell comment marking the beginning of a snippet. The
snippet name may consist of any non-space characters. E.G.
> {- SNIPPET: header -}
or
> -- SNIPPET: header
or
> # SNIPPET: header
-}
snippetMarkerWithAnyPrefix :: AttoText.Parser SnippetMarker
snippetMarkerWithAnyPrefix = do
SnippetMarker
<$> nonEmptyWhile (not . Char.isSpace)
<*> snippetMarkerBody
snippetMarkerWithMatchingPrefix :: SnippetMarker -> AttoText.Parser SnippetMarker
snippetMarkerWithMatchingPrefix marker = do
SnippetMarker
<$> nonEmptyString (snippetMarkerPrefix marker)
<*> snippetMarkerBody
snippetMarkerBody :: AttoText.Parser NET.NonEmptyText
snippetMarkerBody = do
AttoText.skipWhile AttoText.isHorizontalSpace
AttoText.string "SNIPPET:"
AttoText.skipWhile AttoText.isHorizontalSpace
name <- nonEmptyWhile (not . Char.isSpace)
AttoText.skipWhile AttoText.isHorizontalSpace
AttoText.skipWhile (not . isEOLChar)
AttoText.endOfLine
pure name
nonEmptyWhile :: (Char -> Bool) -> AttoText.Parser NET.NonEmptyText
nonEmptyWhile predicate = do
text <- AttoText.takeWhile1 predicate
case NET.fromText text of
Nothing -> fail "nonEmptyWhile: takeWhile1 returned empty text"
Just nonEmptyText -> pure nonEmptyText
nonEmptyString :: NET.NonEmptyText -> AttoText.Parser NET.NonEmptyText
nonEmptyString targetText =
AttoText.string (NET.toText targetText)
*> pure targetText
data SnippetMarker =
SnippetMarker
{ snippetMarkerPrefix :: NET.NonEmptyText
, snippetMarkerName :: NET.NonEmptyText
}
isEOLChar :: Char -> Bool
isEOLChar c =
c == '\n' || c == '\r'

View File

@ -0,0 +1,2 @@
Here you can find all my previous posts:
$partial("templates/post-list.html")$

View File

@ -0,0 +1,44 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Orville - $title$</title>
<link rel="stylesheet" href="/css/syntax.css" />
<link rel="stylesheet" href="/css/default.css" />
</head>
<body>
<section class="leftbar">
<header>
<h1 class="logo">
<a href="/">
<img alt="Orville Logo" src="images/orville-waving-pennant.svg"/>
</a>
</h1>
</header>
<nav>
<h3><a href="/">Home</a></h3>
<h3>Tutorials</h3>
$for(tutorials)$
<a href="$url$">$title$</a>
$endfor$
<h3>Other Links</h3>
<a href="/contact.html">Contact</a>
</nav>
<footer>
Site proudly generated by
<a href="http://jaspervdj.be/hakyll">Hakyll</a>
</footer>
</section>
<main role="main">
<h1>$title$</h1>
$body$
</main>
</body>
</html>

View File

@ -0,0 +1,5 @@
<article>
<section>
$body$
</section>
</article>

View File

@ -0,0 +1,44 @@
---
title: Getting Started
navOrder: 0
---
Orville is a PostgreSQL client library, so it needs a working PostgreSQL server
to work. This tutorial assumes that PostgreSQL in running on `localhost`,
listening on port `5432` and that the user `postgres` exists with password
`postgres`.
Orville itself depends on the native LibPQ library being installed to
communicate with the server, so we need to install it before building
everything. If you're on Debian-like distribution that uses `apt`, this command
will do that.
$sample("install-packages.sh", "installLibPqClient")$
With that setup out of the way, let's make a new project for this demo:
$sample("getting-started/run.sh", "initProject")$
Now we need to edit `stack.yaml` and add `orville-postgresql` as an extra-dep.
$sample("getting-started/add-orville-extra-dep-to-stack-yaml.patch")$
Next, edit the `orville-getting-started.cabal` file to make it depend on
Orville.
$sample("getting-started/add-orville-to-cabal-file.patch")$
Here is a minimal program that simply computes 1+1 on the database. Replace
the `src/Main.hs` with it.
$sample("getting-started/Main.hs")$
All that's left is to build the executable and run it. When it runs it will
connect to the PostgreSQL server, run the SQL to calculate `1 + 1` and then
print the result out.
$sample("getting-started/run.sh", "buildAndExecute")$
This is the output you will see in the console if everything went as planned:
$sample("getting-started/expected-output.txt")$

View File

@ -0,0 +1,86 @@
---
title: Using JSON
navOrder: 4
---
You'll need a Haskell project named `using-json` for this tutorial.
The setup is identical to the setup in [Getting Started](getting-started.html)
aside from the package name, so we'll avoid explaining it again here.
SQL has a rigid schema. Using JSON inside SQL allows for pockets of schemaless
data, that is still queryable using PostgreSQL's built-in functionality.
This document explains how to use Orville with the JSONB data type that
PostgreSQL natively supports.
Project initialization is similar to previous tutorials, but additional
dependencies like Aeson have been added. Aeson is a JSON library for Haskell.
Here's the beginning of our `src/Main.hs` file.
$sample("using-json/src/Main.hs", "moduleHeader")$
Let's suppose we have an example entity with an ID, and some arbitrary JSON
data in a column called 'tags'.
Note how `fooTagsField` below uses the `Value` type from the Aeson library.
Remember that the `Value` contains its own `Null` constructor, which is
distinct from SQL's `NULL`. So we can have JSON nulls in this field, but no SQL
nulls.
We could also use a custom type with `FromJSON`/`ToJSON` instances, since
`jsonb` allows for that too. Aeson is not the focus of this document though.
$sample("using-json/src/Main.hs", "dataTypes")$
Before we can define the corresponding `SqlMarshaller`, we'll need to define the
`aesonValueField` helper function. This is done `tryConvertSqlType` along with
`jsonb` field to apply Aeson encoding and decode.
$sample("using-json/src/Main.hs", "aesonValueField")$
Let's define the `SqlMarshaller` and the table. This is standard stuff, no
surprises here.
$sample("using-json/src/Main.hs", "tableDefinition")$
With all definitions done, we can write `main`. Orville will also use the parts
of the `SqlType` during migration.
$sample("using-json/src/Main.hs", "mainFunction")$
We'll construct a JSON value using the Aeson library, which makes this look
fairly verbose. But imagine that the `Array` value below was read from a file,
or received over HTTP from a web browser.
$sample("using-json/src/Main.hs", "insertEntity")$
Using raw SQL, we can use PostgreSQL's built-in JSONB functions. Let's suppose
we want a row returned for each of the values in the `Array` above.
| ID | Tag |
| -- | --- |
| 0 | 1 |
| 0 | 2 |
| 0 | 3 |
We can use an `SqlMarshaller` to produce a result like this, even though there
is no table for the returned schema. The programmer must ensure correspondence
of the SQL and the `SqlMarshaller`. If they don't match, an exception will be
thrown.
We'll have the `SqlMarshaller` work with tuples and `marshallReadOnlyField`s.
These allow for succintly defining a quick one-off `SqlMarshaller`.
$sample("using-json/src/Main.hs", "selectJSONArray")$
# Program output and test
This concludes this tutorial. You can build an execute this as usual:
$sample("using-json/run.sh","buildAndExecute")$
And you should see the following output:
$sample("using-json/expected-output.txt")$

View File

@ -0,0 +1,58 @@
---
title: Using Migrations
navOrder: 2
---
## Adding a new non-nullable column
We'll show how, to add a new non-nullable column:
1. first, we create the initial version of the table without the 'new' column
1. we then add the column, but only as *nullable*
1. we make sure all values are present on the nullable column
1. we then migrate the column to be non-nullable
You'll need a Haskell project named `using-migrations` for this tutorial.
The setup is identical to the setup in [Getting Started](getting-started.html)
aside from the package name, so we'll avoid explaining it again here. Instead
we'll get straight on creating our `src/Main.hs` file.
$sample("using-migrations/src/Main.hs", "moduleHeaderAndTypes")$
Note how the following tables have the same SQL table names. Imagine that
`table1` is the initial version of the table, which then is changed to
`table2`, and so on. In practice, they can keep their Haskell names, since they
won't need to co-exist, like they do in this document.
Orville's AutoMigration tool sees that the difference between the tables is,
that the second table has an additional column, and it will generate and
execute the DDL to add the column. It needs to be nullable, because the database won't
have any values for it when it is added.
$sample("using-migrations/src/Main.hs", "tableDefinitions")$
Now let's add a `main` function invokes Orville's auto-migration tool to
demonstrate making changes to the table.
$sample("using-migrations/src/Main.hs", "mainFunction")$
# Dropping a column
Orville won't automatically drop a column in the SQL database that isn't in the SqlMarshaller.
The column will just be ignored.
We have to tell Orville explicitly about the columns that are safe to drop.
This is done using the `dropColumns` combinator. Add this to the bottom of the
`main` function:
$sample("using-migrations/src/Main.hs", "droppingColumns")$
# Conclusion
This concludes this tutorial. You can build an execute this as usual:
$sample("using-migrations/run.sh","buildAndExecute")$
And you should see the following output:
$sample("using-migrations/expected-output.txt")$

View File

@ -0,0 +1,124 @@
---
title: Using Plans
navOrder: 3
---
You'll need a Haskell project named `using-plans` for this tutorial.
The setup is identical to the setup in [Getting Started](getting-started.html)
aside from the package name, so we'll avoid explaining it again here.
This example shows Plans. A Plan contains one or more SQL select statements,
and when the first is run, its result is passed into the next.
The goal of plans is to prevent [n+1
queries](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/),
while still allowing a plan for a single item to be modified to execute against
many items.
The code contains a detailed description, this document will just focus on
examples.
This example has a table with students, and a table with classes they can take.
Because multiple students can be enrolled in multiple classes, it is a
many-to-many relationship, which can be modelled with a separate table with two
foreign keys on it.
These tables are defined in a manner similar to previous tutorials. Note the
foreign keys on the `student_class` table. Begin your `src/Main.hs` like this:
$sample("using-plans/src/Main.hs", "moduleHeader")$
The three tables are declared, we'll proceed to the `main` function, which
ensures some sample data is available, and then queries it in different ways.
Since we have foreign key constraints, we have to create and delete the data in
an order that doesn't violate these constraints. Orville will throw a Haskell
runtime exception upon execution of an SQL statement that violates a
constraint.
$sample("using-plans/src/Main.hs", "mainFunction")$
Now that the data is available, let's first show off a simple plan which is
already more powerful than `findEntity`. `findMaybeOne` takes the table, and
the field to filter on, where as `findEntity` only works using the primary key.
The plan returned by `findMaybeOne` is like a parameterized query, it doesn't
yet contain the actual value to filter for.
But upon execution, that value has to be provided, and it has to match the type
of the Plan. `execute` is in MonadOrville just like `findEntity`, so from here
on out, it is familiar territory.
$sample("using-plans/src/Main.hs", "findByStudentId")$
Just to demonstrate that you can filter on other fields too, let's search for a
specific student using their name. Note that Orville doesn't have any
type-level checks for whether there is an index on the field.
$sample("using-plans/src/Main.hs", "findByStudentName")$
A plan that takes a single argument and returns a single argument can be passed
into `planList` to make it work on multiple values. Note how `execute` now
takes a list instead of just a single value.
$sample("using-plans/src/Main.hs", "findByStudentNameList")$
Remember how a plan is just a list of SQL statements. This can used in a way
similar to how `JOIN` is used in SQL.
The function `chain` is used to chain these statements together. After the
first statement is executed and its result has been sent to the client, Orville
allows for manipulating the value with `focusParam` before using it in a step.
For simplicity, we'll use `findOne` here which is like `findMaybeOne`, but
throws exceptions when it fails to find something. In practice, make sure to
only use `findOne` when there are constraints or there is otherwise certainty
that a row exists.
The following plan will:
1. find a student, given a name. Since this is the first step of the plan, the
name is the input of the plan.
1. using the ID of the student, find a row in `student_class` that matches on
the `studentClassStudentIdField`. Note that Orville doesn't check that the
fields are actually comparable, or that it makes sense to compare them!
1. using the ID of the `StudentClass`, find a row in `class` that matches on the `class_id`.
$sample("using-plans/src/Main.hs", "findStudentAndClass")$
Expanding on the previous example, let's find all the names of the classes they
attend, instead of just one. This also lets us avoid unsafe uses of `findOne`.
This new version doesn't throw an exception if a student doesn't attend any
classes, which would happen when the middle plan would fail. Because of the
constraint, the final plan can't fail, so that `findOne` kept.
Let's extract the `Student -> [Class]` part to its own Plan, which we'll then
use for the final expression. Note how the following definition is similar to
the last two lines of the plan above.
$sample("using-plans/src/Main.hs", "studentsToClassesPlan")$
Remember how plans solve the n+1 problem by scaling easily from a single item
to multiple items. This means that while `studentToClassesPlan` executes as two
SQL statements, `planList studentToClassesPlan`, a version that works on
multiple elements, *also* executes as two SQL statements.
You can verify this using `explain`, which shows the generated SQL. Note how
both of these lists have two SQL statements in them:
$sample("using-plans/src/Main.hs", "explainStudentsToClassesPlan")$
With that in mind, let's use `studentToClassesPlan` with `findAll` and
`planList` to get a list of classes for each matching student.
(we sort the inner lists below, such that the result is deterministic.)
$sample("using-plans/src/Main.hs", "executeStudentsToClassesPlan")$
You can build an execute this as usual:
$sample("using-plans/run.sh","buildAndExecute")$
And you should see the following output:
$sample("using-plans/expected-output.txt")$

View File

@ -0,0 +1,67 @@
---
title: Using SqlMarshaller
navOrder: 1
---
The SQL Marshaller helps with converting from a Haskell record to SQL and back.
This document also shows how the SQL marshaller in table definitions, which can
then be used to generate Data Definition Language (DDL) queries to create
tables in the database.
You'll need a Haskell project named `using-sql-marshaller` for this tutorial.
The setup is identical to the setup in [Getting Started](getting-started.html)
aside from the package name, so we'll avoid explaining it again here. Instead
we'll get straight on creating our `src/Main.hs` file.
First, let's import the necessary modules. We use less 'internal' imports here
than in the [Getting Started](getting-started.html) guide, because we are using
a higher abstraction level.
$sample("using-sql-marshaller/src/Main.hs","moduleHeader")$
Next, let's declare some type aliases and the Haskell record itself. We'll
enable storing values of this record in the SQL database.
$sample("using-sql-marshaller/src/Main.hs","dataTypes")$
To store the record in SQL, we need to define Orville FieldDefinitions for each
of the fields of the record. A FieldDefinition maps to a column in SQL. Also
note how the type is parameterized on whether it is nullable or not.
The strings passed in here are the actual SQL column names. FieldDefinitions
help avoiding typos, since the Haskell compiler will fail compilation if the
name of a FieldDefinition is misspelt.
$sample("using-sql-marshaller/src/Main.hs","fieldDefinitions")$
Now that the fields are defined, we can use them, togehter with the record
field selector functions, to define the `SqlMarshaller`.
$sample("using-sql-marshaller/src/Main.hs","sqlMarshaller")$
We can use the marshaller to define the Orville table definition. This binding
represents a table, but note that it doesn't necessarily exist in the SQL
database until we start using it.
$sample("using-sql-marshaller/src/Main.hs","tableDefinition")$
Now let's write the main function, which does the following:
1. auto migrates using the table defintion. It will match the Haskell record at
the time of execution of the statement. The details of migration are out of
scope for this article.
1. deletes the Foo with ID 0, if it exists. Necessary to allow the program to
be repeatedly executed, as primary keys can't be duplicated.
1. inserts an example Foo object with ID 0.
1. reads it back out using its ID 0. If an entity with the given ID doesn't
exist, we'd get a Nothing here.
1. prints the retrieved entity
$sample("using-sql-marshaller/src/Main.hs","mainFunction")$
The program is now complete, let's compile and run!
$sample("using-sql-marshaller/run.sh","buildAndExecute")$
Once it builds and runs successfully you should see the following output:
$sample("using-sql-marshaller/expected-output.txt")$

View File

@ -0,0 +1,7 @@
templates:
params:
author-email: maintainers@flipstone.com
author-name: Flipstone Technology Partners, Inc
category: sample
copyright: ""
github-username: flipstone

View File

@ -0,0 +1,12 @@
resolver:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
system-ghc: true
install-ghc: false
packages:
- site-builder
extra-deps:
- hakyll-4.16.2.0
- non-empty-text-0.2.0

View File

@ -0,0 +1,27 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages:
- completed:
hackage: hakyll-4.16.2.0@sha256:d98c0e2ed14ca2483ea52406f9c924e8fe383fd06c4c3b80ca5daf312f36c270,9997
pantry-tree:
sha256: 7e353fb6d50611d437c3c355ee5b50cc7b0e2ec805ee6a2deb89068d0840266f
size: 9412
original:
hackage: hakyll-4.16.2.0
- completed:
hackage: non-empty-text-0.2.0@sha256:7d1c1f9a11c78c00c656269f940d2fcccd3c2eaf6b619f66bb83a9ea72decc1f,2438
pantry-tree:
sha256: 303f637d7ca4c4573c8d861282b07b172959c8d3f3aa531b0462f3d08b9669d1
size: 400
original:
hackage: non-empty-text-0.2.0
snapshots:
- completed:
sha256: fb482b8e2d5d061cdda4ba1da2957c012740c893a5ee1c1b99001adae7b1fbe7
size: 640046
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml
original:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/19.yaml