snap-server 0.3.1.1 → 1.1.2.1
raw patch · 103 files changed
Files
- CONTRIBUTORS +2/−0
- LICENSE +2/−2
- README.SNAP.md +9/−10
- README.md +13/−32
- Setup.hs +0/−3
- benchmark/Benchmark.hs +7/−0
- benchmark/Snap/Internal/Http/Parser/Benchmark.hs +27/−0
- benchmark/Snap/Internal/Http/Parser/Data.hs +26/−0
- extra/fonts/DroidSerif-Bold.eot binary
- extra/fonts/DroidSerif-Bold.svg +0/−223
- extra/fonts/DroidSerif-Bold.ttf binary
- extra/fonts/DroidSerif-Bold.woff binary
- extra/fonts/DroidSerif-BoldItalic.eot binary
- extra/fonts/DroidSerif-BoldItalic.svg +0/−223
- extra/fonts/DroidSerif-BoldItalic.ttf binary
- extra/fonts/DroidSerif-BoldItalic.woff binary
- extra/fonts/DroidSerif-Italic.eot binary
- extra/fonts/DroidSerif-Italic.svg +0/−223
- extra/fonts/DroidSerif-Italic.ttf binary
- extra/fonts/DroidSerif-Italic.woff binary
- extra/fonts/DroidSerif-Regular.eot binary
- extra/fonts/DroidSerif-Regular.svg +0/−223
- extra/fonts/DroidSerif-Regular.ttf binary
- extra/fonts/DroidSerif-Regular.woff binary
- extra/haddock.css +0/−478
- extra/hscolour.css +0/−15
- extra/logo.gif binary
- haddock.sh +0/−11
- pong/Main.hs +80/−0
- snap-server.cabal +488/−120
- src/Control/Concurrent/Extended.hs +106/−0
- src/Data/Concurrent/HashMap.hs +0/−237
- src/Data/Concurrent/HashMap/Internal.hs +0/−16
- src/Snap/Http/Server.hs +264/−67
- src/Snap/Http/Server/Config.hs +66/−491
- src/Snap/Http/Server/Types.hs +319/−0
- src/Snap/Internal/Http/Parser.hs +0/−496
- src/Snap/Internal/Http/Server.hs +0/−853
- src/Snap/Internal/Http/Server/Address.hs +111/−0
- src/Snap/Internal/Http/Server/Backend.hs +0/−93
- src/Snap/Internal/Http/Server/Clock.hs +44/−0
- src/Snap/Internal/Http/Server/Common.hs +40/−0
- src/Snap/Internal/Http/Server/Config.hs +856/−0
- src/Snap/Internal/Http/Server/Date.hs +37/−87
- src/Snap/Internal/Http/Server/GnuTLS.hs +0/−357
- src/Snap/Internal/Http/Server/HttpPort.hs +0/−117
- src/Snap/Internal/Http/Server/LibevBackend.hs +0/−727
- src/Snap/Internal/Http/Server/ListenHelpers.hs +0/−84
- src/Snap/Internal/Http/Server/Parser.hs +460/−0
- src/Snap/Internal/Http/Server/Session.hs +832/−0
- src/Snap/Internal/Http/Server/SimpleBackend.hs +0/−355
- src/Snap/Internal/Http/Server/Socket.hs +208/−0
- src/Snap/Internal/Http/Server/TLS.hs +165/−0
- src/Snap/Internal/Http/Server/Thread.hs +107/−0
- src/Snap/Internal/Http/Server/TimeoutManager.hs +229/−0
- src/Snap/Internal/Http/Server/TimeoutTable.hs +0/−139
- src/Snap/Internal/Http/Server/Types.hs +185/−0
- src/Snap/Internal/Http/Server/gnutls_helpers.c +0/−17
- src/System/FastLogger.hs +172/−101
- src/System/SendFile.hs +0/−26
- src/System/SendFile.hsc +105/−0
- src/System/SendFile/Darwin.hsc +0/−41
- src/System/SendFile/FreeBSD.hsc +64/−24
- src/System/SendFile/Linux.hsc +64/−29
- test/Snap/Internal/Http/Server/Address/Tests.hs +73/−0
- test/Snap/Internal/Http/Server/Parser/Tests.hs +249/−0
- test/Snap/Internal/Http/Server/Session/Tests.hs +1018/−0
- test/Snap/Internal/Http/Server/Socket/Tests.hs +171/−0
- test/Snap/Internal/Http/Server/TimeoutManager/Tests.hs +136/−0
- test/Snap/Test/Common.hs +174/−0
- test/System/SendFile/Tests.hs +262/−0
- test/Test/Blackbox.hs +697/−0
- test/Test/Common/Rot13.hs +24/−0
- test/Test/Common/TestHandler.hs +193/−0
- test/TestSuite.hs +83/−0
- test/bad_key.pem +15/−0
- test/benchmark/Benchmark.hs +0/−7
- test/benchmark/Snap/Internal/Http/Parser/Benchmark.hs +0/−51
- test/benchmark/Snap/Internal/Http/Parser/Data.hs +0/−24
- test/cbits/errno_util.c +5/−0
- test/cert.pem +14/−0
- test/common/Paths_snap_server.hs +0/−9
- test/common/Snap/Test/Common.hs +0/−88
- test/common/Test/Common/Rot13.hs +0/−19
- test/common/Test/Common/TestHandler.hs +0/−75
- test/data/fileServe/foo.bin +0/−1
- test/data/fileServe/foo.bin.bin.bin +0/−1
- test/data/fileServe/foo.html +0/−1
- test/data/fileServe/foo.txt +0/−1
- test/dummy.txt +1/−0
- test/key.pem +15/−0
- test/pongserver/Main.hs +0/−32
- test/runTestsAndCoverage.sh +0/−58
- test/snap-server-testsuite.cabal +0/−223
- test/suite/Data/Concurrent/HashMap/Tests.hs +0/−121
- test/suite/Snap/Internal/Http/Parser/Tests.hs +0/−280
- test/suite/Snap/Internal/Http/Server/Tests.hs +0/−897
- test/suite/Test/Blackbox.hs +0/−280
- test/suite/TestSuite.hs +0/−62
- test/testserver/Main.hs +0/−36
- test/testserver/static/hello.txt +0/−1
- testserver/Main.hs +36/−0
- testserver/static/hello.txt +1/−0
CONTRIBUTORS view
@@ -3,5 +3,7 @@ Shu-yu Guo <shu@rfrn.org> Carl Howells <chowells79@gmail.com> John Lenz <jlenz2@math.uiuc.edu>+Herbert Valerio Riedel <hvriedel@gmail.com> James Sanders <jimmyjazz14@gmail.com> Jacob Stanley <jacob@stanley.io>+Jurriën Stutterheim <j.stutterheim@me.com>
LICENSE view
@@ -1,5 +1,5 @@-Copyright (c) 2009, Snap Framework authors (see CONTRIBUTORS)-Copyright (c) 2010, Google, Inc.+Copyright (c) 2009-present, Snap Framework authors (see CONTRIBUTORS)+Copyright (c) 2010-2016, Google, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without
README.SNAP.md view
@@ -9,21 +9,20 @@ Snap Status and Features ------------------------ -This developer prerelease contains only the Snap core system, namely:-- * a high-speed HTTP server, with an optional high-concurrency backend using- the [libev](http://software.schmorp.de/pkg/libev.html) library+The Snap core system consists of: * a sensible and clean monad for web programming - * an xml-based templating system for generating HTML based on- [expat](http://expat.sourceforge.net/) (via- [hexpat](http://hackage.haskell.org/package/hexpat)) that allows you to- bind Haskell functionality to XML tags without getting PHP-style tag soup- all over your pants+ * a high-speed HTTP server called "snap-server" + * an xml-based templating system called "heist" for generating HTML that+ allows you to bind Haskell functionality to XML tags without getting+ PHP-style tag soup all over your pants++ * a "snaplet" system for building web sites from composable pieces.+ Snap is currently only officially supported on Unix platforms; it has been-tested on Linux and Mac OSX Snow Leopard, and is reported to work on Windows.+tested on Linux and Mac OSX, and is reported to work on Windows. Snap Philosophy
README.md view
@@ -1,25 +1,16 @@ Snap Framework HTTP Server Library ---------------------------------- +[](https://github.com/snapframework/snap-server/actions/workflows/ci.yml)+ This is the Snap Framework HTTP Server library. For more information about Snap, read the `README.SNAP.md` or visit the Snap project website at http://www.snapframework.com/. -The Snap HTTP server is a high performance, epoll-enabled, iteratee-based web-server library written in Haskell. Together with the `snap-core` library upon-which it depends, it provides a clean and efficient Haskell programming-interface to the HTTP protocol. Higher-level facilities for building web-applications (like user/session management, component interfaces, data-modeling, etc.) are not yet implemented, so this release will mostly be of-interest for those who:-- * need a fast and minimal HTTP API at roughly the same level of abstraction- as Java servlets,--or-- * are interested in contributing to the Snap Framework project.-+The Snap HTTP server is a high performance web server library written in+Haskell. Together with the `snap-core` library upon which it depends, it+provides a clean and efficient Haskell programming interface to the HTTP+protocol. Building snap-server --------------------@@ -31,12 +22,8 @@ ### Optional dependencies -The `snap-server` library can optionally use the-[libev](http://software.schmorp.de/pkg/libev.html) for high-speed, O(1)-scalable socket event processing.- If you would like SSL support, `snap-server` requires the-[gnutls](http://www.gnu.org/software/gnutls/) library.+[openssl](http://www.openssl.org/) library. ## Building snap-server@@ -46,17 +33,11 @@ cabal install -to get the "stock" version of Snap. If you would like to try the optional-`libev` backend, pass the `libev` flag to `cabal install`:-- cabal install -flibev--And if you would like SSL support, pass the `gnutls` flag to `cabal install`:+to install snap-server. - cabal install -fgnutls+If you would like SSL support, pass the `openssl` flag to `cabal install`: -Note that the "`-flibev`" and "`-fgnutls`" flags are not mutually-exclusive,-and if you would like you can use them together.+ cabal install -fopenssl ## Building the Haddock Documentation@@ -75,12 +56,12 @@ `cd` into the `test/` directory and run $ cabal configure # for the stock backend, or..- $ cabal configure -flibev # for the libev backend, and/or..- $ cabal configure -fgnutls # for the SSL backend+ $ cabal configure -fopenssl # for the SSL backend+ $ cabal build From here you can invoke the testsuite by running: - $ ./runTestsAndCoverage.sh + $ ./runTestsAndCoverage.sh The testsuite generates an `hpc` test coverage report in `test/dist/hpc`.
− Setup.hs
@@ -1,3 +0,0 @@-import Distribution.Simple--main = defaultMain
+ benchmark/Benchmark.hs view
@@ -0,0 +1,7 @@+module Main where++import Criterion.Main+import qualified Snap.Internal.Http.Parser.Benchmark as PB++main :: IO ()+main = defaultMain [ PB.benchmarks ]
+ benchmark/Snap/Internal/Http/Parser/Benchmark.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Internal.Http.Parser.Benchmark+ ( benchmarks )+ where++import Control.Monad+import qualified Criterion.Main as C+import qualified Data.ByteString as S+import Snap.Internal.Http.Parser.Data+import Snap.Internal.Http.Server.Parser+import qualified System.IO.Streams as Streams++parseGet :: S.ByteString -> IO ()+parseGet s = do+ !_ <- Streams.fromList [s] >>= parseRequest+ return $! ()+++benchmarks :: C.Benchmark+benchmarks = C.bgroup "parser"+ [ C.bench "firefoxget" $ C.whnfIO $! replicateM_ 1000+ $! parseGet parseGetData+ ]
+ benchmark/Snap/Internal/Http/Parser/Data.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE OverloadedStrings #-}++module Snap.Internal.Http.Parser.Data+ ( parseGetData+ , parseChunkedData+ )+ where++import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L++parseGetData :: S.ByteString+parseGetData = S.concat+ [ "GET /favicon.ico HTTP/1.1\r\n"+ , "Host: 0.0.0.0=5000\r\n"+ , "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"+ , "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"+ , "Accept-Language: en-us,en;q=0.5\r\n"+ , "Accept-Encoding: gzip,deflate\r\n"+ , "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"+ , "Keep-Alive: 300\r\n"+ , "Connection: keep-alive\r\n"+ , "\r\n" ]++parseChunkedData :: L.ByteString+parseChunkedData = L.fromChunks ["In the beginning, everything was void, and J.H.W.H. Conway began to create numbers.", "Conway said, \"Let there be two rules which bring forth all numbers larege and small.", "This shall be the first rule: Every number corresponds to two sets of previously created numbers, such that no member of the left set is greater than or equal to any member of the right set.", "And the second rule shall be this: One number is less than or equal to another number if and only if no member of the first number \'s left set is greater than or equal to the second number, and no member of the second number\'s right set is less than or equal to the first number.\" And Conway examined these two rules he had made, and behold! They were very good.", "And the first number was created from the void left set and the void right set. Conway called this number \"zero,\" and said that it shall be a sign to separate positive numbers from negative numbers.", "Conway proved that zero was less than or equal to zero, end he saw that it was good.", "And the evening and the morning were the day of zero.", "On the next day, two more numbers were created, one with zero as its left set and one with zero as its right set. And Conway called the former number \"one,\" and the latter he called \"minus one.\" And he proved that minus one is less than but not equal to zero and zero is less than but not equal to one.", "And the evening day.", "And Conway said, \"Let the numbers be added to each other in this wise: The left set of the sum of two numbers shall be the sums of all left parts of each number with the other; and in like manner the right set shall be from the right parts, each according to its kind.\" Conway proved that every number plus zero is unchanged, and he saw that addition was good.", "And the evening and the morning were the third day."]
− extra/fonts/DroidSerif-Bold.eot
binary file changed (47454 → absent bytes)
− extra/fonts/DroidSerif-Bold.svg
@@ -1,223 +0,0 @@-<?xml version="1.0" standalone="no"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >-<svg xmlns="http://www.w3.org/2000/svg">-<defs>-<font id="DroidSerif-Bold" horiz-adv-x="1145" >-<font-face font-family="Droid Serif" font-weight="700" font-stretch="normal" units-per-em="2048" panose-1="2 2 8 0 6 5 0 2 2 0" ascent="1638" descent="-410" x-height="1098" cap-height="1462" bbox="-80 -492 2185 1907" underline-thickness="102" underline-position="-103" unicode-range="U+0020-U+2122"/>-<missing-glyph horiz-adv-x="532" />-<glyph glyph-name=".notdef" horiz-adv-x="532" />-<glyph glyph-name=".null" horiz-adv-x="0" />-<glyph glyph-name="nonmarkingreturn" horiz-adv-x="682" />-<glyph glyph-name="space" unicode=" " horiz-adv-x="532" />-<glyph glyph-bame="tab" unicode="	" horiz-adv-x="532" />-<glyph glyph-bame="uni00A0" unicode=" " horiz-adv-x="532" />-<glyph glyph-name="exclam" unicode="!" horiz-adv-x="782" d="M213 1462h356l-120 -995h-115zM225 147q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77t-36.5 -50t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50t-13 77z" />-<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="1040" d="M584 1462h319l-72 -563h-135zM137 1462h320l-92 -563h-136z" />-<glyph glyph-name="numbersign" unicode="#" d="M1022 551v-141h-256l-76 -410h-145l76 410h-213l-78 -410h-146l78 410h-205v141h232l71 371h-237v143h264l72 397h147l-74 -397h213l76 397h146l-76 -397h196v-143h-223l-69 -371h227zM434 551h215l72 371h-215z" />-<glyph glyph-name="dollar" unicode="$" d="M639 1556v-155q91 -3 157 -20t109 -44.5t63.5 -63.5t20.5 -77q0 -65 -56 -107t-169 -42q0 30 -7 65t-22 67.5t-38.5 59t-57.5 41.5v-399q6 -3 23 -9.5t28 -11.5q94 -37 161 -76t109.5 -85t62 -99.5t19.5 -118.5q0 -78 -27.5 -144.5t-79 -117.5t-126.5 -83.5t-170 -43.5 v-254h-115v250q-117 3 -198 30t-131.5 68t-72.5 91t-22 98q0 45 16.5 76t43.5 50.5t61.5 28.5t71.5 9q0 -77 16.5 -137t47 -102.5t73 -68.5t94.5 -34v442l-35 14q-98 40 -163.5 81t-106 87.5t-57.5 100.5t-17 120q0 74 28 135.5t78 107.5t119.5 75.5t153.5 38.5v157h115z M799 389q0 65 -40 111t-120 88v-387q77 17 118.5 68t41.5 120zM385 1128q0 -27 6 -52t22 -48.5t43 -46t68 -45.5v354q-60 -11 -99.5 -51.5t-39.5 -110.5z" />-<glyph glyph-name="percent" unicode="%" horiz-adv-x="1855" d="M807 1030q0 -103 -23 -187t-68.5 -144t-115 -93t-162.5 -33q-97 0 -167 33t-114.5 93t-65.5 144t-21 187t21 186.5t66 143t115 91.5t168 32q92 0 161 -32t115 -91.5t68.5 -143t22.5 -186.5zM301 1030q0 -84 7.5 -149.5t23.5 -111t42.5 -69.5t63.5 -24q39 0 64.5 24 t41.5 69.5t22.5 111t6.5 149.5q0 82 -6.5 146.5t-22 109.5t-41 68.5t-63.5 23.5t-64.5 -23.5t-43 -68.5t-24 -109.5t-7.5 -146.5zM651 0h-159l706 1462h158zM1786 436q0 -103 -23 -187t-68.5 -144t-115 -92.5t-162.5 -32.5q-97 0 -167 32.5t-114.5 92.5t-65.5 144t-21 187 t21 186.5t66 143t115 91.5t168 32q92 0 161 -32t115 -91.5t68.5 -143t22.5 -186.5zM1280 436q0 -84 7.5 -149.5t23.5 -111t42.5 -69.5t63.5 -24q39 0 64.5 24t41.5 69.5t22.5 111t6.5 149.5q0 82 -6.5 146.5t-22 109.5t-41 68.5t-63.5 23.5t-64.5 -23.5t-43 -68.5 t-24 -109.5t-7.5 -146.5z" />-<glyph glyph-name="ampersand" unicode="&" horiz-adv-x="1640" d="M1208 0l-141 150q-38 -38 -84.5 -69t-102.5 -53.5t-121.5 -35t-142.5 -12.5q-126 0 -223 29.5t-163 85.5t-100 137t-34 184q0 90 28.5 153.5t76.5 110t111.5 79t133.5 60.5q-40 48 -69.5 91.5t-48.5 86.5t-28 88t-9 97q0 68 26 123t77.5 95t128.5 61.5t179 21.5 q99 0 172.5 -23t122 -63t73 -93t24.5 -112q0 -62 -19 -112t-57.5 -92.5t-97 -79.5t-138.5 -74q5 -8 15 -15l290 -305q13 71 17 140.5t4 127.5v90h448v-108h-32q-34 0 -66.5 -4t-60.5 -18.5t-49.5 -42t-34.5 -74.5q-16 -57 -37.5 -121.5t-52.5 -130.5l204 -213q29 -31 71 -41 t97 -10h19v-109h-406zM397 406q0 -61 19.5 -113.5t54.5 -91.5t85.5 -61.5t111.5 -22.5q109 0 184 35.5t125 95.5l-438 467q-43 -31 -70.5 -65.5t-43.5 -73t-22 -81t-6 -89.5zM846 1190q0 36 -6.5 67t-22.5 54t-44 36t-71 13q-34 0 -59.5 -13t-41.5 -36t-24 -54.5t-8 -68.5 q0 -35 8 -67t23.5 -63.5t39.5 -63.5t56 -68q43 24 72 51t46 58.5t24.5 69.5t7.5 85z" />-<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="594" d="M137 1462h320l-92 -563h-136z" />-<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="819" d="M446 651q0 -122 12.5 -239.5t46.5 -222t94 -192.5t155 -151v-131q-171 69 -292 161.5t-197.5 209.5t-112 258t-35.5 307q0 165 35.5 305.5t112 256.5t197.5 208t292 160v-129q-95 -63 -155 -150.5t-94 -191.5t-46.5 -220.5t-12.5 -238.5z" />-<glyph glyph-name="parenright" unicode=")" horiz-adv-x="819" d="M373 651q0 122 -12.5 238.5t-46 220.5t-93.5 191.5t-155 150.5v129q171 -68 292 -160t197.5 -208t111.5 -256.5t35 -305.5q0 -166 -35 -307t-111.5 -258t-197.5 -209.5t-292 -161.5v131q95 63 155 151t93.5 192.5t46 222t12.5 239.5z" />-<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="1028" d="M72 1237l92 207l305 -221l-68 333h230l-74 -329l307 213l92 -205l-319 -80l319 -82l-92 -203l-307 213l72 -331h-228l66 333l-303 -217l-92 203l319 84z" />-<glyph glyph-name="plus" unicode="+" d="M645 659v-366h-147v366h-365v146h365v366h147v-366h367v-146h-367z" />-<glyph glyph-name="comma" unicode="," horiz-adv-x="602" d="M459 86q0 -65 -20 -126t-64 -113t-113.5 -93.5t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 19 -11 31.5t-27.5 23.5t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165z" />-<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="635" d="M51 451v215h533v-215h-533z" />-<glyph glyph-name="period" unicode="." horiz-adv-x="623" d="M143 147q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77t-36.5 -50t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50t-13 77z" />-<glyph glyph-name="slash" unicode="/" horiz-adv-x="590" d="M147 -250l-147 2l446 1804h144z" />-<glyph glyph-name="zero" unicode="0" d="M1075 733q0 -169 -28 -308t-89 -238t-156 -153t-229 -54q-140 0 -236 54t-155.5 153t-85.5 238.5t-26 309.5t26 308t85.5 236t156 151t237.5 53q133 0 228 -53t155.5 -151t88.5 -236.5t28 -309.5zM387 733q0 -147 8 -262t28.5 -194.5t56.5 -121.5t93 -42t93 42 t56.5 121.5t28 194.5t7.5 262t-7.5 261.5t-27.5 193.5t-56 120.5t-92 41.5q-57 0 -93.5 -41.5t-57.5 -120.5t-29 -193.5t-8 -261.5z" />-<glyph glyph-name="one" unicode="1" d="M199 0v109h168q26 0 45 6.5t32 21.5t19 40.5t6 64.5v1026l-73.5 -87t-66.5 -67t-62.5 -43.5t-61.5 -15.5q-25 0 -46.5 10.5t-37.5 30.5t-25.5 48t-9.5 62q31 8 65 19.5t72.5 30t82.5 45t95 63.5l144 106h229v-1228q0 -32 4.5 -57t16 -42t32 -25.5t52.5 -8.5h165v-109 h-845z" />-<glyph glyph-name="two" unicode="2" d="M999 1143q0 -48 -10.5 -93t-35 -93t-64.5 -101.5t-99 -118t-137.5 -142.5l-181.5 -175l-205 -195h477q63 0 107.5 36.5t62.5 105.5l17 63h121l-11 -430h-968v211l303 309q95 97 156 175t96 149t49 140.5t14 148.5q0 117 -42.5 171t-117.5 54q-104 0 -146 -89.5 t-42 -264.5q-58 0 -106.5 11t-83 35t-53.5 62.5t-19 93.5q0 56 28.5 106t84.5 88t140.5 60.5t196.5 22.5q115 0 202.5 -23.5t147 -67.5t89.5 -107t30 -142z" />-<glyph glyph-name="three" unicode="3" d="M498 -20q-116 0 -199.5 20t-137 54t-79 78.5t-25.5 92.5q0 39 14 69t38 50.5t55.5 30.5t66.5 10q0 -65 18.5 -114t51.5 -82t79.5 -49.5t102.5 -16.5q50 0 95.5 14t80.5 48t55.5 92.5t20.5 146.5q0 59 -20.5 108t-61 84.5t-99.5 55.5t-136 20h-127v127h135q66 0 115 21.5 t81 61.5t48 95.5t16 122.5q0 112 -43 175t-127 63q-55 0 -89.5 -27t-53.5 -72t-26 -102t-7 -117q-128 0 -197 44.5t-69 138.5q0 54 28.5 101.5t85.5 83t141.5 55.5t196.5 20q109 0 196.5 -22t149 -65t94.5 -105t33 -142q0 -69 -24 -127t-66 -104t-99 -80.5t-124 -57.5 q62 -11 126.5 -35.5t117.5 -66.5t87 -105t34 -151q0 -125 -46.5 -210t-124 -136.5t-177 -73.5t-205.5 -22z" />-<glyph glyph-name="four" unicode="4" d="M893 381v-125q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h26v-109h-718v109h57q35 0 65.5 5t53 20.5t36 44.5t13.5 77v125h-567v125l581 956h285v-946h213v-135h-213zM594 874q0 90 3 194t11 200q-10 -24 -32 -66l-47 -86.5l-48 -84t-35 -58.5l-276 -457h424v358z" />-<glyph glyph-name="five" unicode="5" d="M471 123q51 0 96.5 16t80 53.5t55 101t20.5 157.5q0 153 -73 228t-206 75q-39 0 -70.5 -3t-58.5 -8.5t-51 -12t-47 -13.5l-94 37l65 708h775l10 -372h-117l-16 69q-5 18 -11 32.5t-16.5 24.5t-26.5 15.5t-41 5.5h-426q0 -1 -1.5 -17.5t-3.5 -43.5t-5 -61l-6 -69l-16 -188 q16 6 41.5 11.5t55.5 10t63.5 7t64.5 2.5q119 0 215.5 -27.5t165 -82t106 -136.5t37.5 -192q0 -133 -48.5 -223.5t-125.5 -145.5t-172 -78.5t-188 -23.5q-115 0 -195 20.5t-130 55t-72.5 79t-22.5 92.5q0 72 44.5 107t119.5 35q0 -44 11.5 -88t38 -79t69.5 -57t106 -22z" />-<glyph glyph-name="six" unicode="6" d="M657 1362q-60 0 -108.5 -36t-84 -105t-56.5 -169.5t-27 -230.5q21 14 48 27.5t61.5 24.5t78 17.5t95.5 6.5q93 0 168.5 -29t129 -83.5t82.5 -133t29 -178.5q0 -110 -30 -200.5t-89.5 -155.5t-148 -101t-205.5 -36q-114 0 -207.5 41.5t-160 127.5t-103.5 217t-37 310 q0 169 35.5 316t108 256t182.5 172t258 63q99 0 168 -19t112 -50.5t62.5 -72t19.5 -84.5q0 -31 -13 -60t-42 -51t-75.5 -35t-114.5 -13q0 46 -6 93t-21 85t-41.5 62t-67.5 24zM588 772q-28 0 -59 -8.5t-59.5 -22.5t-52 -31.5t-36.5 -35.5q1 -147 18.5 -253t48 -174t71 -100 t87.5 -32q79 0 124.5 80.5t45.5 257.5q0 166 -50 242.5t-138 76.5z" />-<glyph glyph-name="seven" unicode="7" d="M338 0l545 1239h-539q-56 0 -84.5 -26.5t-34.5 -77.5l-12 -103h-123l10 430h977v-100l-565 -1362h-174z" />-<glyph glyph-name="eight" unicode="8" d="M61 373q0 66 21.5 119t61.5 96.5t95.5 80t122.5 70.5q-122 71 -187.5 161t-65.5 210q0 71 24.5 138.5t80.5 119.5t147 83.5t223 31.5q108 0 189.5 -27t136.5 -75t82.5 -113.5t27.5 -143.5q0 -61 -19.5 -108t-55.5 -85.5t-87 -71.5t-115 -66q92 -45 157 -90.5t105.5 -95 t59 -104t18.5 -116.5q0 -97 -35.5 -172.5t-103 -127.5t-164.5 -79.5t-221 -27.5q-128 0 -222 31t-155.5 84t-91 125t-29.5 153zM569 96q53 0 95.5 19t72.5 53t46 81t16 103q0 50 -17 90.5t-53.5 76t-93 69t-135.5 69.5q-34 -22 -64 -50.5t-51.5 -64t-34 -79.5t-12.5 -98 q0 -60 16.5 -109.5t47 -85t73 -55t94.5 -19.5zM762 1128q0 44 -12.5 86.5t-36.5 75.5t-59.5 53.5t-82.5 20.5q-42 0 -74.5 -17.5t-54.5 -48t-33.5 -72.5t-11.5 -91q0 -53 14.5 -93t42.5 -72t69 -57.5t95 -50.5q38 22 65 47t44.5 57t26 71.5t8.5 90.5z" />-<glyph glyph-name="nine" unicode="9" d="M465 -20q-93 0 -157 19.5t-104 52t-57.5 74t-17.5 85.5q0 45 24 75.5t76 41.5q15 -46 36 -86t50.5 -69.5t69 -46.5t90.5 -17q138 0 212.5 149t84.5 444q-24 -30 -53.5 -55t-66.5 -44t-81.5 -29.5t-97.5 -10.5q-88 0 -161.5 27.5t-127 81t-83 133t-29.5 182.5 q0 111 32 202t92.5 156.5t147.5 101.5t197 36q111 0 205 -40t162.5 -124t106.5 -214t38 -310q0 -169 -33 -317.5t-103.5 -259t-182 -174.5t-269.5 -64zM561 711q74 0 127 37.5t84 99.5q-1 131 -17.5 225t-45 154.5t-68.5 89.5t-88 29q-88 0 -136 -86.5t-48 -260.5 q0 -142 48 -215t144 -73z" />-<glyph glyph-name="colon" unicode=":" horiz-adv-x="623" d="M143 147q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77t-36.5 -50t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50t-13 77zM143 952q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27 t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77.5t-36.5 -50.5t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50.5t-13 77.5z" />-<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="602" d="M459 86q0 -65 -20 -126t-64 -113t-113.5 -93.5t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 19 -11 31.5t-27.5 23.5t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165zM143 952q0 47 13 78.5t35.5 50.5t53.5 27t66 8 q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77.5t-36.5 -50.5t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50.5t-13 77.5z" />-<glyph glyph-name="less" unicode="<" d="M133 690v84l879 479v-161l-660 -361l660 -356v-162z" />-<glyph glyph-name="equal" unicode="=" d="M1016 604v-143h-887v143h887zM1016 1001v-143h-887v143h887z" />-<glyph glyph-name="greater" unicode=">" d="M133 213v162l660 356l-660 361v161l879 -479v-84z" />-<glyph glyph-name="question" unicode="?" horiz-adv-x="1126" d="M1014 1106q0 -82 -25.5 -147t-76.5 -119t-127.5 -99.5t-178.5 -87.5l-41 -186h-125l-41 252q88 35 144 82.5t88.5 102t44.5 114.5t12 121q0 49 -9 89.5t-28.5 70t-50 45.5t-72.5 16q-46 0 -77 -21t-50 -56t-27.5 -82t-8.5 -99q-63 0 -116 9t-91.5 26.5t-60 44.5t-21.5 63 q0 50 26 93.5t79.5 75.5t135.5 50.5t195 18.5q108 0 200 -25.5t159 -74t105 -118.5t38 -159zM332 147q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77t-36.5 -50t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5 t-35.5 50t-13 77z" />-<glyph glyph-name="at" unicode="@" horiz-adv-x="1886" d="M1806 803q0 -153 -37 -273t-97 -202.5t-135.5 -126t-152.5 -43.5q-91 0 -154 44.5t-97 147.5h-13q-21 -40 -48 -75t-61 -61t-76.5 -41t-96.5 -15q-64 0 -122.5 21t-103 64t-70.5 109t-26 156q0 55 13 119t41.5 127.5t72 123t105 105t141 73t178.5 27.5q71 0 122 -18 t83 -43l86 43h49l-86 -512q-2 -12 -4.5 -31t-4.5 -39t-3.5 -38.5t-1.5 -30.5q0 -42 9 -69t23 -42.5t31.5 -21t34.5 -5.5q41 0 82.5 34t75.5 99.5t55.5 162.5t21.5 223q0 140 -42.5 245.5t-118 176t-180 106t-228.5 35.5q-97 0 -191.5 -27t-180 -79t-157.5 -127.5t-125 -172 t-82.5 -213.5t-29.5 -252q0 -181 54 -309t146.5 -209t216 -118t261.5 -37q83 0 162 15t150 39t132 55t109 63l49 -78q-54 -41 -122.5 -77t-149 -63t-171 -43t-188.5 -16q-117 0 -225 21.5t-202.5 65.5t-172.5 109.5t-133.5 153.5t-86 198t-30.5 243q0 137 33.5 262t95 231.5 t149.5 193t197 148t236.5 94.5t269.5 33q178 0 313 -51t225.5 -139.5t136.5 -209t46 -259.5zM768 487q0 -102 36 -156.5t95 -54.5q44 0 75.5 21t53 55.5t35.5 77.5t22 88l82 418q-6 14 -17.5 24.5t-26.5 18t-31.5 11t-32.5 3.5q-52 0 -93.5 -26t-74 -68.5t-55.5 -97 t-38.5 -110.5t-22.5 -109.5t-7 -94.5z" />-<glyph glyph-name="A" unicode="A" horiz-adv-x="1542" d="M446 481l-59 -176q-8 -25 -16.5 -58.5t-8.5 -58.5q0 -20 8 -35t21 -24.5t29.5 -14.5t34.5 -5h86v-109h-533v109h25q27 0 49.5 6t42 22.5t37 45.5t35.5 75l444 1204h281l428 -1206q15 -43 31.5 -71.5t36 -45t41.5 -23.5t46 -7h37v-109h-676v109h80q15 0 31 4.5t28.5 14 t20.5 24.5t8 36q0 25 -6 48t-12 40l-72 205h-498zM795 942l-22.5 73.5l-23 78.5l-22 79.5t-18.5 75.5q-9 -31 -21 -68l-25.5 -76l-27 -78l-25.5 -75l-121 -346h414z" />-<glyph glyph-name="B" unicode="B" horiz-adv-x="1376" d="M1241 1090q0 -68 -18.5 -118.5t-52.5 -87t-81.5 -62.5t-105.5 -44v-10q71 -18 129.5 -49.5t101 -77t66 -105.5t23.5 -135q0 -202 -147 -301.5t-439 -99.5h-660v109h84q23 0 42.5 4.5t33.5 18.5t22.5 40t8.5 70v981q0 41 -8.5 66.5t-23 39.5t-34 19.5t-41.5 5.5h-84v108 h598q292 0 439 -90t147 -282zM571 125h136q68 0 116 15t78 48.5t43.5 87.5t13.5 132q0 75 -12 130.5t-41 91.5t-76 54t-118 18h-140v-577zM571 827h78q72 0 119.5 15t76 46.5t40.5 81.5t12 120t-13.5 117t-43.5 76t-78 41.5t-117 12.5h-74v-510z" />-<glyph glyph-name="C" unicode="C" horiz-adv-x="1368" d="M870 143q75 0 133.5 17.5t104.5 45.5t80.5 63t60.5 69q16 -12 25.5 -37t9.5 -51q0 -43 -23 -90.5t-77 -87.5t-143 -66t-220 -26q-178 0 -311 54t-221 153t-132 238t-44 308q0 166 45 304t133.5 237t221 154t306.5 55q118 0 205.5 -18.5t145.5 -50.5t87 -75.5t29 -93.5 q0 -38 -16.5 -70.5t-49 -56.5t-80.5 -37.5t-110 -13.5q0 51 -11 101.5t-37.5 91.5t-69.5 66.5t-107 25.5q-97 0 -164 -41t-107.5 -120t-58.5 -194.5t-18 -263.5t22 -259t71 -184.5t127.5 -110t192.5 -36.5z" />-<glyph glyph-name="D" unicode="D" horiz-adv-x="1571" d="M1458 758q0 -168 -46 -307.5t-137.5 -239.5t-227 -155.5t-314.5 -55.5h-676v109h86q23 0 42 4.5t33 18.5t22 40t8 70v987q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-41 4.5h-86v108h676q170 0 304.5 -44.5t228 -133t143 -220.5t49.5 -306zM1112 758q0 293 -107.5 436 t-316.5 143h-117v-1210h115q105 0 185 43.5t133.5 125.5t80.5 198.5t27 263.5z" />-<glyph glyph-name="E" unicode="E" horiz-adv-x="1337" d="M573 125h410q31 0 53 11.5t38 32.5t25.5 49.5t14.5 62.5l16 96h142l-15 -377h-1200v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v990q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v108h1137l8 -377h-143l-10 97q-8 75 -38 115t-93 40h-345v-512h486v-123h-486v-577z" />-<glyph glyph-name="F" unicode="F" horiz-adv-x="1272" d="M1059 1085l-10 99q-10 81 -49.5 117t-102.5 36h-326v-559h486v-121h-486v-415q0 -44 8.5 -70t22.5 -40t34 -18.5t42 -4.5h127v-109h-748v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v998q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-41 4.5h-86v108h1135l10 -377h-143z" />-<glyph glyph-name="G" unicode="G" horiz-adv-x="1575" d="M866 -20q-190 0 -331.5 54t-235.5 153t-140 238t-46 308q0 166 49 304t145 237t239 154t331 55q128 0 223.5 -18.5t160 -50.5t96.5 -75.5t32 -93.5q0 -36 -17 -67.5t-51 -55.5t-83 -37.5t-114 -13.5q0 62 -15 114t-46.5 89t-79.5 57.5t-113 20.5q-112 0 -190.5 -41 t-128 -120t-72 -194.5t-22.5 -263.5t23.5 -262.5t76 -192.5t136 -118.5t204.5 -40.5q38 0 76 3t74 11v301q0 82 -37 114t-109 32h-27v108h644v-108h-27q-31 0 -54 -7.5t-38 -25.5t-22 -47.5t-7 -73.5v-336q-120 -55 -242 -82.5t-262 -27.5z" />-<glyph glyph-name="H" unicode="H" horiz-adv-x="1677" d="M913 0v109h88q22 0 41 4.5t33.5 18.5t22.5 40t8 70v458h-535v-458q0 -44 8.5 -70t22.5 -40t33 -18.5t41 -4.5h88v-109h-707v109h86q22 0 41 4.5t33.5 18.5t22.5 40t8 70v986q0 41 -8.5 65.5t-23 37.5t-33.5 17.5t-40 4.5h-86v109h707v-109h-88q-22 0 -41 -4.5t-33 -18.5 t-22.5 -40t-8.5 -70v-395h535v395q0 44 -8 70t-22.5 40t-33.5 18.5t-41 4.5h-88v109h707v-109h-86q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-989q0 -40 8.5 -64.5t23 -37t33 -16.5t39.5 -4h86v-109h-707z" />-<glyph glyph-name="I" unicode="I" horiz-adv-x="821" d="M57 0v109h86q23 0 42 4.5t33 18.5t22 40t8 70v978q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v109h707v-109h-86q-22 0 -41.5 -4.5t-33.5 -18.5t-22 -40t-8 -70v-978q0 -44 8 -70t22 -40t33.5 -18.5t41.5 -4.5h86v-109h-707z" />-<glyph glyph-name="J" unicode="J" horiz-adv-x="754" d="M731 1354h-86q-22 0 -41.5 -4.5t-33.5 -18.5t-22.5 -40t-8.5 -70v-1225q0 -93 -21 -165t-58 -126.5t-88.5 -92t-112 -60.5t-128 -33.5t-137.5 -10.5h-74v119h37q49 0 95.5 18.5t82.5 61.5t58 113.5t22 173.5v1235q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-40 4.5h-86v108 h706v-108z" />-<glyph glyph-name="K" unicode="K" horiz-adv-x="1503" d="M889 1090q33 35 55.5 63.5t36 53t19.5 46.5t6 43q0 34 -26 47t-89 13v106h555v-106q-42 0 -79.5 -13t-73.5 -37t-71 -57t-71 -73l-270 -297l381 -605q30 -48 57.5 -79.5t55.5 -50.5t57 -27t63 -8h8v-109h-110q-78 0 -137 5t-103.5 15t-76.5 25.5t-56 36.5t-43.5 47.5 t-38.5 58.5l-276 471l-91 -71v-346q0 -44 8.5 -70t22.5 -40t34 -18.5t42 -4.5h86v-109h-707v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v998q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-41 4.5h-86v108h707v-108h-86q-22 0 -42 -4.5t-34 -18.5t-22.5 -40t-8.5 -70v-478z" />-<glyph glyph-name="L" unicode="L" horiz-adv-x="1339" d="M57 0v109h86q23 0 42 4.5t33 18.5t22 40t8 70v979q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v108h707v-108h-86q-21 0 -40.5 -4.5t-33.5 -17.5t-22.5 -37.5t-8.5 -65.5v-1104h381q72 0 112 45.5t58 132.5l33 154h115l-15 -457h-1200z" />-<glyph glyph-name="M" unicode="M" horiz-adv-x="1950" d="M1237 0v109h20q32 0 56.5 4t40.5 16t24 34.5t8 59.5v1037l-413 -1260h-139l-433 1260v-1018q0 -44 10.5 -70t30 -40t47.5 -18.5t64 -4.5h12v-109h-508v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v998q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-41 4.5h-86v108h590l340 -989 l326 989h579v-108h-86q-22 0 -41 -4.5t-33 -18.5t-22 -40t-8 -70v-979q0 -44 8 -70t22 -40t33 -18.5t41 -4.5h86v-109h-655z" />-<glyph glyph-name="N" unicode="N" horiz-adv-x="1614" d="M1200 0l-799 1128v-886q0 -44 8.5 -70t22.5 -40t33.5 -18.5t40.5 -4.5h86v-109h-535v109h86q22 0 41 4.5t33.5 18.5t22.5 40t8 70v987q0 41 -8.5 65.5t-23 37.5t-33.5 17.5t-40 4.5h-86v108h455l723 -1022v789q0 41 -8.5 65.5t-23 37.5t-33.5 17.5t-40 4.5h-86v108h535 v-108h-86q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-1221h-189z" />-<glyph glyph-name="O" unicode="O" horiz-adv-x="1612" d="M1499 733q0 -169 -45.5 -308t-134 -238t-217 -153t-295.5 -54q-175 0 -305.5 54t-216.5 153t-129 238.5t-43 309.5t43 308.5t129.5 236.5t217 151.5t306.5 53.5q166 0 294.5 -53.5t216.5 -152t133.5 -237t45.5 -309.5zM457 733q0 -147 19 -262t61 -194.5t108.5 -121.5 t161.5 -42q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262t-18.5 262t-59.5 194.5t-107 121t-161 41.5q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262z" />-<glyph glyph-name="P" unicode="P" horiz-adv-x="1307" d="M1245 1028q0 -92 -32 -177t-104 -150t-187 -103.5t-281 -38.5h-70v-328q0 -40 9 -64.5t24 -37t35 -16.5t41 -4h125v-109h-748v109h86q23 0 42 4.5t33 18.5t22 40t8 70v987q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-41 4.5h-86v108h629q142 0 247 -30t174.5 -86.5 t103.5 -136.5t34 -181zM571 678h50q76 0 129 19t86.5 60t49 106t15.5 157q0 82 -13.5 142.5t-43 100t-77 59t-116.5 19.5h-80v-663z" />-<glyph glyph-name="Q" unicode="Q" horiz-adv-x="1612" d="M1499 733q0 -144 -32.5 -265.5t-95.5 -215.5t-156 -158.5t-214 -93.5q9 -113 37 -185.5t68.5 -114t89.5 -57.5t100 -16h33v-119h-147q-92 0 -181.5 27t-162 85.5t-121 150t-58.5 221.5q-138 21 -240.5 83.5t-170.5 158.5t-101.5 223t-33.5 278q0 170 43 308.5 t129.5 236.5t217 151.5t306.5 53.5q166 0 294.5 -53.5t216.5 -152t133.5 -237t45.5 -309.5zM457 733q0 -147 19 -262t61 -194.5t108.5 -121.5t161.5 -42q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262t-18.5 262t-59.5 194.5t-107 121t-161 41.5q-96 0 -163 -41.5 t-109 -121t-61 -194.5t-19 -262z" />-<glyph glyph-name="R" unicode="R" horiz-adv-x="1448" d="M57 109h86q21 0 40 4t33.5 16.5t23 37t8.5 64.5v998q0 41 -8.5 65.5t-23 37.5t-33.5 17.5t-40 4.5h-86v108h660q290 0 425.5 -97t135.5 -282q0 -81 -24 -144t-63.5 -110t-89.5 -79.5t-102 -53.5l244 -420q26 -44 50.5 -75.5t49 -52t50.5 -30t55 -9.5h8v-109h-67 q-92 0 -160.5 7t-120 27.5t-89 56.5t-69.5 93l-243 451h-136v-404q0 -40 8.5 -64.5t23 -37t33.5 -16.5t40 -4h88v-109h-707v109zM571 754h115q71 0 118.5 19t76 56.5t41 94t12.5 131.5q0 78 -14 132t-44 88.5t-78 50t-116 15.5h-111v-587z" />-<glyph glyph-name="S" unicode="S" horiz-adv-x="1200" d="M541 -20q-138 0 -230 26t-147.5 67t-79 92t-23.5 101q0 53 19.5 89t52 59t74 33t86.5 10q0 -88 21 -154.5t58 -111t88.5 -67t112.5 -22.5q60 0 107 17t80 47t50 70.5t17 87.5q0 52 -21 92.5t-63.5 75t-107 66t-150.5 67.5q-107 44 -180.5 90.5t-118.5 100.5t-64.5 117 t-19.5 138q0 94 38 170t105 130t159 83t200 29q113 0 195 -18.5t135.5 -50.5t79.5 -75.5t26 -93.5q0 -36 -15.5 -67t-47 -54t-79 -36t-110.5 -13q0 43 -11.5 92.5t-37.5 92t-67.5 70.5t-100.5 28q-41 0 -78 -12t-64.5 -36t-43.5 -59.5t-16 -81.5q0 -43 14 -81t51.5 -74.5 t103 -73t169.5 -78.5q105 -43 179 -88t121.5 -96.5t69 -113t21.5 -136.5q0 -99 -39 -181.5t-112 -141.5t-175.5 -92t-230.5 -33z" />-<glyph glyph-name="T" unicode="T" horiz-adv-x="1337" d="M831 242q0 -44 8 -70t22.5 -40t33.5 -18.5t41 -4.5h86v-109h-707v109h86q23 0 42 4.5t33 18.5t22 40t8 70v1095h-164q-46 0 -77 -10t-50.5 -28.5t-29 -45.5t-13.5 -61l-14 -127h-138l11 397h1276l10 -397h-137l-15 127q-4 34 -13.5 61t-29 45.5t-50.5 28.5t-77 10h-164 v-1095z" />-<glyph glyph-name="U" unicode="U" horiz-adv-x="1530" d="M1497 1354h-88q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-799q0 -103 -29.5 -185t-92 -139t-159.5 -87.5t-231 -30.5t-239.5 25.5t-178.5 81.5t-111.5 144.5t-38.5 214.5v783q0 41 -8.5 65.5t-23 37.5t-33 17.5t-39.5 4.5h-88v108h706v-108h-86q-21 0 -40 -4.5 t-33.5 -18.5t-22.5 -40t-8 -70v-791q0 -86 21.5 -144.5t61.5 -94t96 -51t126 -15.5q68 0 123 17.5t93.5 54.5t59.5 94t21 135v803q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-40 4.5h-86v108h536v-108z" />-<glyph glyph-name="V" unicode="V" horiz-adv-x="1430" d="M1430 1354h-99q-14 0 -25 -6t-22 -22.5t-23 -45.5t-28 -76l-418 -1204h-205l-436 1255q-10 29 -25.5 48.5t-33 30.5t-35.5 15.5t-33 4.5h-47v108h676v-108h-94q-15 0 -29 -3.5t-25.5 -11.5t-18.5 -21t-7 -32q0 -20 6 -45.5t12 -42.5l209 -631q8 -23 16.5 -54t16.5 -65 t14.5 -67.5t9.5 -61.5q3 17 10.5 46.5t17.5 64l20.5 69l19.5 62.5l211 623l8.5 24.5t8 27.5t6 27t2.5 21q0 34 -22.5 52t-59.5 18h-107v108h529v-108z" />-<glyph glyph-name="W" unicode="W" horiz-adv-x="2185" d="M1237 1448l283 -782q18 -48 33.5 -97.5l28.5 -94.5t23 -83t15 -65l17 82l19.5 94.5l22 101.5t23.5 101l108 442q3 12 6.5 28t6.5 31.5t4.5 29t1.5 21.5q0 53 -31.5 75t-99.5 22h-47v108h534v-108h-39q-30 0 -53 -6t-41 -23.5t-32.5 -48.5t-28.5 -82l-318 -1194h-233 l-344 961l-295 -961h-254l-375 1245q-9 32 -22 53t-30.5 33.5t-40 17.5t-52.5 5h-27v108h684v-108h-47q-62 0 -92.5 -24t-30.5 -75q0 -17 6.5 -49.5t14.5 -60.5l137 -473l23.5 -84.5t23.5 -92t20 -89.5t13 -76q14 66 30.5 123.5l34.5 117.5l270 877h150z" />-<glyph glyph-name="X" unicode="X" horiz-adv-x="1499" d="M1071 1294q0 18 -9 30t-24.5 18.5t-36.5 9t-45 2.5h-6v108h480v-108h-19q-30 0 -54 -7.5t-47.5 -25t-47.5 -45.5t-54 -70l-297 -405l377 -584q40 -63 83 -85.5t81 -22.5h27v-109h-676v109h10q123 0 123 67q0 12 -2 23t-9.5 26t-20.5 37t-36 55l-188 285l-221 -299 q-19 -26 -36 -59.5t-17 -65.5q0 -34 28 -51.5t96 -17.5h7v-109h-517v109h13q37 0 65 10t52.5 28.5t47.5 45t48 59.5l358 467l-338 526q-17 27 -33.5 47.5t-37 34t-45.5 20.5t-60 7h-27v108h678v-108h-6q-35 0 -58.5 -4.5t-37.5 -13t-19.5 -19.5t-5.5 -23q0 -21 15.5 -53 t38.5 -67l170 -254l178 249q18 28 36.5 62.5t18.5 62.5z" />-<glyph glyph-name="Y" unicode="Y" horiz-adv-x="1419" d="M336 0v109h96q25 0 46.5 3t37.5 15.5t25.5 37.5t9.5 68v285l-379 727q-15 30 -28.5 51t-29.5 33.5t-36.5 18.5t-50.5 6h-27v108h686v-108h-35q-62 0 -92.5 -25t-30.5 -67q0 -26 9.5 -56.5t21.5 -56.5l152 -301q32 -65 52.5 -115t37.5 -98q21 54 48.5 117.5t61.5 132.5 l119 245q22 45 28.5 75.5t6.5 47.5q0 53 -33.5 77t-101.5 24h-47v108h536v-108h-39q-26 0 -44.5 -7t-35 -25t-34 -49t-41.5 -79l-348 -678v-280q0 -45 9 -70t24.5 -38t36 -16t44.5 -3h101v-109h-756z" />-<glyph glyph-name="Z" unicode="Z" horiz-adv-x="1364" d="M1229 1358l-770 -1233h442q63 0 103 17.5t63.5 46.5t34 65.5t14.5 75.5l10 92h148l-10 -422h-1178v102l768 1235h-403q-48 0 -79 -13t-49.5 -37.5t-27 -59t-12.5 -76.5l-11 -111h-147l10 422h1094v-104z" />-<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="848" d="M205 -262v1818h567v-108h-88q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -78v-1306q0 -48 13.5 -77.5t36 -45t53.5 -20.5t65 -5h88v-108h-567z" />-<glyph glyph-name="backslash" unicode="\" horiz-adv-x="590" d="M0 1556h145l445 -1804h-148z" />-<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="848" d="M643 1556v-1818h-567v108h88q35 0 65.5 5t53 20.5t36 45t13.5 77.5v1306q0 49 -13.5 78t-36 44.5t-53 20.5t-65.5 5h-88v108h567z" />-<glyph glyph-name="asciicircum" unicode="^" d="M526 1462h88l435 -925h-160l-320 702l-315 -702h-160z" />-<glyph glyph-name="underscore" unicode="_" horiz-adv-x="940" d="M950 -291h-960v121h960v-121z" />-<glyph glyph-name="grave" unicode="`" horiz-adv-x="1182" d="M713 1241q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="a" unicode="a" horiz-adv-x="1227" d="M410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM592 999q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5 q108 0 188.5 -18.5t134 -59.5t80.5 -107.5t27 -162.5v-522q0 -42 6.5 -70t20.5 -44.5t38 -23.5t58 -7h8v-109h-381l-43 141h-18q-34 -41 -64 -71.5t-64 -50.5t-76.5 -29.5t-100.5 -9.5q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113 q0 51 -4 94t-17 74t-38.5 48t-67.5 17z" />-<glyph glyph-name="b" unicode="b" horiz-adv-x="1329" d="M1233 553q0 -149 -27.5 -257t-80.5 -178.5t-131.5 -104t-180.5 -33.5q-59 0 -107 13t-86.5 37t-68 57t-51.5 73h-19l-57 -160h-389v109h14q29 0 57 5t50 20t35.5 43t13.5 75v1059q0 44 -13 70.5t-35 41.5t-51.5 20t-62.5 5h-8v108h481v-350q0 -32 -2.5 -75t-5.5 -81 l-8 -92h14q44 76 117.5 120t189.5 44q100 0 176.5 -33.5t129 -103t79.5 -177t27 -255.5zM725 971q-61 0 -101 -25.5t-64 -77.5t-34 -130.5t-10 -184.5q0 -101 10 -179.5t34 -132t65 -81t102 -27.5q101 0 146 109t45 313q0 209 -45 312.5t-148 103.5z" />-<glyph glyph-name="c" unicode="c" horiz-adv-x="1079" d="M604 -20q-113 0 -206.5 29t-160.5 96t-104 175t-37 265q0 166 38.5 277t106 178t159.5 95.5t198 28.5q99 0 175 -16.5t127 -45.5t77.5 -68.5t26.5 -84.5q0 -33 -11.5 -64.5t-41 -55.5t-81 -39t-131.5 -15q0 53 -6.5 101t-21.5 84t-40.5 57.5t-64.5 21.5 q-45 0 -80.5 -21.5t-61 -73.5t-39 -139t-13.5 -218q0 -208 57 -311t186 -103q53 0 99.5 12.5t84.5 35t66.5 53t46.5 65.5q25 -15 37 -40.5t12 -53.5q0 -39 -23 -79t-71.5 -72.5t-123.5 -53t-179 -20.5z" />-<glyph glyph-name="d" unicode="d" horiz-adv-x="1329" d="M1122 252q0 -47 14 -75t37.5 -43t54 -20t64.5 -5h8v-109h-397l-57 160h-19q-23 -42 -52.5 -75t-68 -56.5t-86.5 -36t-108 -12.5q-100 0 -178 33.5t-131.5 103t-81 176.5t-27.5 254q0 148 27.5 256.5t80.5 179t130 105t176 34.5q58 0 104.5 -12.5t84 -34t66.5 -51.5 t50 -66h14q-4 57 -8 107q-1 21 -2.5 43t-3 41.5t-2 34.5t-0.5 24v113q0 42 -13.5 67.5t-36 38.5t-52.5 17t-64 4h-16v108h493v-1304zM600 133q61 0 101.5 25.5t65 77.5t34.5 130.5t10 184.5q0 101 -10 179.5t-34.5 132t-65 81t-101.5 27.5q-51 0 -87.5 -27.5t-59 -81.5 t-33 -132.5t-10.5 -180.5q0 -209 43.5 -312.5t146.5 -103.5z" />-<glyph glyph-name="e" unicode="e" horiz-adv-x="1169" d="M608 991q-86 0 -136.5 -85t-55.5 -249h354q0 78 -9 140t-28.5 105t-50 66t-74.5 23zM627 -20q-130 0 -229.5 38t-166.5 110t-101 176.5t-34 238.5q0 144 34 253t99 182t159.5 109.5t215.5 36.5q111 0 200 -31.5t151 -93.5t95 -154t33 -214v-105h-671q3 -103 22.5 -177 t54 -122t84 -71t113.5 -23q53 0 98 12.5t81.5 35t64 53t45.5 65.5q55 -30 55 -100q0 -44 -24 -83.5t-74 -69.5t-125.5 -48t-179.5 -18z" />-<glyph glyph-name="f" unicode="f" horiz-adv-x="834" d="M39 0v109h45q22 0 47.5 4.5t47 18.5t36 40t14.5 70v716h-182v140h182v76q0 95 24.5 169.5t76 126t130.5 78.5t187 27q99 0 165 -11.5t105 -32t55.5 -47.5t16.5 -59q0 -69 -62.5 -101t-189.5 -32q0 25 -5 54t-17 54t-31.5 41.5t-48.5 16.5q-25 0 -43 -13.5t-29.5 -43 t-16.5 -76.5t-5 -115v-112h282v-140h-282v-716q0 -44 14.5 -70t36 -40t47 -18.5t47.5 -4.5h96v-109h-743z" />-<glyph glyph-name="g" unicode="g" horiz-adv-x="1147" d="M1137 1059q0 -23 -7 -44.5t-23.5 -37.5t-45 -25.5t-70.5 -9.5q0 21 -6.5 37t-17.5 27t-25 16.5t-29 5.5q-17 0 -36.5 -7t-30.5 -15q21 -23 39 -52.5t31.5 -63.5t21.5 -70.5t8 -74.5q0 -77 -24.5 -142.5t-75.5 -113.5t-129 -75t-185 -27q-11 0 -28 0.5l-34 1t-32.5 2 t-23.5 2.5q-13 -7 -26.5 -17.5t-24 -23.5t-17 -29t-6.5 -34q0 -34 26.5 -50t69.5 -16h248q102 0 176 -21.5t122.5 -61.5t71.5 -98.5t23 -131.5q0 -95 -36 -169.5t-109.5 -126t-185 -79t-263.5 -27.5q-242 0 -360.5 72.5t-118.5 212.5q0 110 71 168.5t206 69.5q-28 11 -55 27 t-48 38.5t-34 51.5t-13 65q0 34 13.5 63t37.5 55.5t57.5 50t73.5 46.5q-45 16 -83.5 44.5t-66 68.5t-43.5 91t-16 113q0 180 104.5 279.5t323.5 99.5q73 0 135.5 -18.5t108.5 -44.5l37.5 38.5t46.5 37.5t58 28t71 11q37 0 64.5 -9.5t46 -25.5t28 -37t9.5 -45zM246 -203 q0 -85 61.5 -125.5t179.5 -40.5q180 0 262 52t82 153q0 65 -41 91t-124 26h-238q-31 0 -63 -5.5t-58.5 -22.5t-43.5 -47.5t-17 -80.5zM383 745q0 -54 7.5 -97.5t24.5 -74.5t44 -48t67 -17q41 0 68 16.5t43 48t22.5 76t6.5 99.5q0 57 -7 103.5t-23.5 79.5t-43.5 51.5 t-68 18.5q-40 0 -67 -19t-43.5 -53t-23.5 -81t-7 -103z" />-<glyph glyph-name="h" unicode="h" horiz-adv-x="1366" d="M858 0v674q0 66 -8.5 117.5t-28 86.5t-51 53.5t-76.5 18.5q-51 0 -85 -26t-54.5 -69.5t-29.5 -101t-9 -120.5v-391q0 -43 10.5 -69t29.5 -40.5t46.5 -19t61.5 -4.5h6v-109h-629v109h4q35 0 64 4.5t50.5 19.5t33.5 43t12 74v1073q0 41 -14.5 65.5t-36.5 38t-47.5 17.5 t-47.5 4h-24v108h481v-337q0 -40 -2.5 -86t-5.5 -85l-8 -90h18q31 58 65.5 91t73.5 49.5t82.5 21t91.5 4.5q79 0 142 -23t106.5 -71t66.5 -122.5t23 -178.5v-475q0 -48 8.5 -76.5t25.5 -43.5t43 -20t61 -5h6v-109h-455z" />-<glyph glyph-name="i" unicode="i" horiz-adv-x="721" d="M176 1430q0 39 13.5 67t37 45.5t55 26t68.5 8.5q35 0 67 -8.5t56 -26t38.5 -45.5t14.5 -67q0 -38 -14.5 -66t-38.5 -46t-56 -27t-67 -9q-37 0 -68.5 9t-55 27t-37 46t-13.5 66zM59 109q23 0 48.5 4.5t47 18.5t36 40t14.5 70v622q0 41 -14.5 65.5t-36.5 38t-47.5 17.5 t-47.5 4h-24v109h481v-856q0 -44 14.5 -70t36 -40t47.5 -18.5t48 -4.5h24v-109h-651v109h24z" />-<glyph glyph-name="j" unicode="j" horiz-adv-x="707" d="M516 1098v-1114q0 -138 -38.5 -229.5t-107 -146t-163 -77.5t-207.5 -23h-41v127h14q56 0 99.5 18t73 60t44.5 112t15 175v854q0 44 -13 70.5t-35.5 41t-52.5 19t-63 4.5h-6v109h481zM178 1430q0 39 13.5 67t37 45.5t55 26t68.5 8.5q35 0 67 -8.5t56 -26t38.5 -45.5 t14.5 -67q0 -38 -14.5 -66t-38.5 -46t-56 -27t-67 -9q-37 0 -68.5 9t-55 27t-37 46t-13.5 66z" />-<glyph glyph-name="k" unicode="k" horiz-adv-x="1303" d="M1303 0h-29q-112 0 -188 5t-131 23t-95 54.5t-80 99.5l-182 287l-82 -61v-166q0 -44 14.5 -70t36 -40t47.5 -18.5t48 -4.5h24v-109h-651v109h24q23 0 48.5 4.5t47 18.5t36 40t14.5 70v1081q0 41 -14.5 65.5t-36.5 38t-47.5 17.5t-47.5 4h-24v108h481v-790 q0 -28 -1.5 -64.5t-3.5 -69.5q-3 -39 -5 -79l258 289q34 38 44.5 60.5t10.5 37.5q0 26 -27.5 40.5t-78.5 14.5v103h516v-103q-71 0 -139.5 -41.5t-149.5 -132.5l-129 -147l272 -406q54 -81 109 -120t104 -39h7v-109z" />-<glyph glyph-name="l" unicode="l" horiz-adv-x="721" d="M59 109q23 0 48.5 4.5t47 18.5t36 40t14.5 70v1081q0 41 -14.5 65.5t-36.5 38t-47.5 17.5t-47.5 4h-24v108h481v-1314q0 -44 14.5 -70t36 -40t47.5 -18.5t48 -4.5h24v-109h-651v109h24z" />-<glyph glyph-name="m" unicode="m" horiz-adv-x="2019" d="M858 0v674q0 66 -8.5 117.5t-28 86.5t-51 53.5t-76.5 18.5q-51 0 -85 -26t-54.5 -69.5t-29.5 -101t-9 -120.5v-391q0 -43 10.5 -69t29.5 -40.5t46.5 -19t61.5 -4.5h6v-109h-629v109h4q35 0 64 4.5t50.5 19.5t33.5 43t12 74v612q0 43 -10.5 69t-30 40.5t-46.5 19t-61 4.5 h-6v103h430l27 -146h10q31 58 65.5 92t73.5 52t82.5 23t91.5 5q113 0 193 -40.5t117 -131.5h18q31 58 67.5 92t78 52t87 23t93.5 5q79 0 142 -23t106.5 -71t66.5 -122.5t23 -178.5v-475q0 -48 8.5 -76.5t25.5 -43.5t43 -20t60 -5h6v-109h-455v674q0 132 -36.5 204t-126.5 72 q-48 0 -82 -23.5t-55.5 -63.5t-31.5 -93.5t-10 -112.5v-403q0 -48 8.5 -76.5t25.5 -43.5t43 -20t61 -5h6v-109h-455z" />-<glyph glyph-name="n" unicode="n" horiz-adv-x="1366" d="M858 0v674q0 66 -8.5 117.5t-28 86.5t-51 53.5t-76.5 18.5q-51 0 -85 -26t-54.5 -69.5t-29.5 -101t-9 -120.5v-391q0 -43 10.5 -69t29.5 -40.5t46.5 -19t61.5 -4.5h6v-109h-629v109h4q35 0 64 4.5t50.5 19.5t33.5 43t12 74v606q0 43 -10.5 69t-30 40.5t-46.5 19t-61 4.5 h-6v109h430l27 -146h10q31 58 65.5 92t73.5 52t82.5 23t91.5 5q79 0 142 -23t106.5 -71t66.5 -122.5t23 -178.5v-475q0 -48 8.5 -76.5t25.5 -43.5t43 -20t61 -5h6v-109h-455z" />-<glyph glyph-name="o" unicode="o" horiz-adv-x="1255" d="M1159 553q0 -289 -135.5 -431t-398.5 -142q-123 0 -221 35.5t-166.5 106.5t-105 179t-36.5 252q0 289 135.5 430t399.5 141q123 0 220.5 -35t166 -106t105 -178.5t36.5 -251.5zM414 553q0 -109 11.5 -192t37 -139t66.5 -84.5t100 -28.5t99.5 28.5t66 84.5t36.5 139 t11 192q0 110 -11.5 192.5t-37 137.5t-66.5 82.5t-100 27.5t-100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5z" />-<glyph glyph-name="p" unicode="p" horiz-adv-x="1321" d="M51 -383q23 0 48.5 4.5t47 18.5t36 40t14.5 70v1096q0 47 -10.5 75t-29 43t-44 20t-54.5 5h-14v109h401l37 -160h9q22 40 51.5 73t68 57t86.5 37t107 13q102 0 180.5 -33.5t131.5 -104t80.5 -178.5t27.5 -257q0 -148 -27 -255.5t-79.5 -177.5t-129 -103.5t-176.5 -33.5 q-117 0 -190 44.5t-117 119.5h-14l8 -92q3 -38 5.5 -81t2.5 -75v-141q0 -44 14.5 -70t36 -40t47 -18.5t47.5 -4.5h45v-109h-671v109h24zM717 127q103 0 147.5 103.5t44.5 312.5q0 204 -44.5 313t-145.5 109q-61 0 -102 -27.5t-65 -81t-34 -132t-10 -179.5q0 -106 10 -184.5 t34 -130.5t64 -77.5t101 -25.5z" />-<glyph glyph-name="q" unicode="q" horiz-adv-x="1327" d="M608 -492v109h37q34 0 64 4t52.5 17t36 38.5t13.5 67.5v150q0 9 0.5 24t2 34.5l3 41t2.5 42.5q4 49 8 107h-14q-21 -35 -50 -65t-66.5 -51.5t-84 -34t-104.5 -12.5q-99 0 -176 33.5t-130 103.5t-80.5 178t-27.5 256q0 147 27.5 254t81 176.5t131.5 103t178 33.5 q60 0 108 -12.5t86.5 -36t68 -56.5t52.5 -75h19l41 160h413v-109h-8q-34 0 -64.5 -5t-54 -20t-37.5 -43t-14 -75v-1102q0 -42 13.5 -67.5t36 -38.5t52.5 -17t64 -4h37v-109h-717zM600 965q-103 0 -146.5 -103.5t-43.5 -312.5q0 -205 43.5 -311.5t146.5 -106.5q61 0 101.5 27 t65 79.5t34.5 130t10 179.5q0 106 -10 184.5t-34.5 130.5t-65 77.5t-101.5 25.5z" />-<glyph glyph-name="r" unicode="r" horiz-adv-x="1071" d="M725 0h-684v109h6q35 0 64 5t50 20.5t32.5 44.5t11.5 77v594q0 45 -10.5 72.5t-30 42.5t-46.5 19.5t-61 4.5h-6v109h414l41 -160h10q20 46 44 80.5t57.5 57.5t79 34.5t108.5 11.5q121 0 178 -42.5t57 -123.5q0 -94 -68 -146t-192 -52q0 42 -4.5 74t-16 53t-31 32 t-48.5 11q-36 0 -62 -18t-44 -46.5t-29.5 -64.5t-18 -72.5t-8.5 -69.5t-2 -57v-354q0 -45 11 -72.5t30 -41.5t45.5 -18.5t56.5 -4.5h66v-109z" />-<glyph glyph-name="s" unicode="s" horiz-adv-x="999" d="M473 -20q-111 0 -189.5 18t-128 50t-72 76t-22.5 95q0 50 19.5 80.5t49 47.5t62.5 22.5t60 5.5q0 -64 16 -115t45 -86.5t69.5 -54.5t90.5 -19q53 0 91.5 11t63 30.5t36.5 45t12 53.5q0 34 -12.5 60.5t-41.5 50t-77.5 46t-120.5 47.5q-83 29 -146.5 61.5t-107 74t-66 95 t-22.5 122.5q0 82 31.5 143t89.5 101.5t139 60.5t180 20q97 0 165 -16.5t111 -43.5t63 -61t20 -69q0 -69 -48.5 -105t-160.5 -36q0 102 -45.5 158.5t-134.5 56.5q-33 0 -63.5 -8t-53 -24t-36 -39.5t-13.5 -55.5q0 -33 12.5 -59t44 -49.5t85.5 -47.5t138 -53 q68 -24 125.5 -54.5t99 -70t64.5 -90t23 -115.5q0 -85 -29.5 -152t-86.5 -113t-140 -70.5t-189 -24.5z" />-<glyph glyph-name="t" unicode="t" horiz-adv-x="829" d="M643 145q40 0 76.5 5.5t68.5 13.5v-133q-16 -8 -43.5 -17t-64 -16.5t-82.5 -12.5t-100 -5q-69 0 -125 16.5t-95 55t-60 100t-21 151.5v655h-154v105q66 0 118 26t83 60q63 66 94 203h170v-254h262v-140h-262v-634q0 -93 31.5 -136t103.5 -43z" />-<glyph glyph-name="u" unicode="u" horiz-adv-x="1366" d="M907 0l-45 145h-10q-31 -53 -67 -85.5t-77 -50t-86.5 -23.5t-93.5 -6q-160 0 -245.5 99t-85.5 306v459q0 45 -8 73t-25 44t-43.5 22t-63.5 6h-4v109h455v-656q0 -66 7.5 -119t25.5 -90.5t48 -58t75 -20.5q49 0 84.5 21.5t58 62t33 98t10.5 129.5v393q0 45 -12 71 t-32 39.5t-47 17t-57 3.5h-6v109h465v-860q0 -45 10.5 -70.5t28.5 -38.5t43 -16.5t55 -3.5h17v-109h-408z" />-<glyph glyph-name="v" unicode="v" horiz-adv-x="1241" d="M1241 989h-41q-21 0 -37.5 -5t-32 -20.5t-30.5 -45t-33 -78.5l-297 -840h-270l-336 891q-11 29 -25.5 48t-34 30t-45 15.5t-59.5 4.5v109h635v-109h-86q-31 0 -49.5 -16.5t-18.5 -48.5q0 -25 6.5 -49t12.5 -41l137 -388q25 -65 43.5 -131t28.5 -118q5 24 14 56l18 62.5 l16.5 55.5l10.5 35l139 411q10 28 16.5 56.5t6.5 56.5q0 34 -22.5 46.5t-57.5 12.5h-59v109h450v-109z" />-<glyph glyph-name="w" unicode="w" horiz-adv-x="1753" d="M1012 1087l200 -604q25 -74 36 -125.5t18 -89.5h6l9.5 49t11 48l14.5 54.5t20 67.5l90 299q8 26 13.5 56t5.5 47q0 52 -33.5 76t-102.5 24h-14v109h469v-109h-26q-30 0 -52 -6t-39 -23.5t-32 -49t-31 -81.5l-264 -829h-221l-224 680l-235 -680h-223l-263 881 q-11 32 -24 53t-30 33t-39 17t-52 5h-6v109h600v-109h-27q-62 0 -92.5 -17.5t-30.5 -68.5q0 -17 5.5 -41t11.5 -47l76 -266q10 -37 19 -76l17 -76t14.5 -70t10.5 -59h6q9 51 24.5 105.5t41.5 130.5l209 583h133z" />-<glyph glyph-name="x" unicode="x" horiz-adv-x="1323" d="M891 928q0 37 -28.5 49t-76.5 12h-6v109h473v-109h-18q-30 0 -53.5 -5.5t-47 -20t-48.5 -40t-58 -65.5l-211 -258l301 -383q47 -59 86.5 -83.5t77.5 -24.5h27v-109h-652v109h11q123 0 123 67q0 12 -3 24t-11 28t-23.5 37.5t-40.5 51.5l-117 142l-143 -178 q-19 -25 -31 -51t-12 -52q0 -34 29 -51.5t98 -17.5h6v-109h-520v109h18q37 0 65 6.5t52.5 21.5t49.5 40t56 63l258 311l-258 330q-43 54 -86 81t-90 27h-27v109h644v-109h-7q-35 0 -57.5 -4.5t-35.5 -12.5t-18 -19t-5 -23q0 -22 11 -42.5t36 -51.5l114 -140l97 117 q24 31 37.5 59t13.5 56z" />-<glyph glyph-name="y" unicode="y" horiz-adv-x="1186" d="M1186 1098v-109q-31 0 -54.5 -7t-42.5 -24.5t-35 -46t-32 -71.5l-75 -208l-78.5 -212.5l-79 -212l-76.5 -207.5q-36 -99 -68 -174t-67.5 -130t-78.5 -91t-100 -57.5t-132.5 -30.5t-176.5 -9h-35v119q107 0 182 26t127 74t85.5 115t58.5 148l-369 901q-12 29 -27 46 t-32 26t-37 11.5t-43 2.5v121h584v-109q-60 0 -94.5 -15.5t-34.5 -60.5q0 -17 7 -40.5t13 -38.5l37.5 -93.5l38 -101l35.5 -97.5l30 -83q15 -39 25 -70.5t16.5 -57t10.5 -47t6 -42.5q2 21 8 46.5t13 49t14 42l10 26.5l135 401q4 10 7.5 23.5t6.5 27.5t4.5 27t1.5 22 q0 47 -39 64.5t-110 17.5v109h461z" />-<glyph glyph-name="z" unicode="z" horiz-adv-x="1083" d="M754 139q31 0 52.5 9t37 29t26 51.5t19.5 76.5l12 66h121l-10 -371h-975v84l604 874h-299q-23 0 -40 -6.5t-30.5 -23t-24.5 -44t-22 -69.5l-12 -49h-123l25 332h884v-88l-606 -871h361z" />-<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="905" d="M649 -256q-86 0 -151.5 21t-109.5 60.5t-66.5 95.5t-22.5 126v350q0 59 -18.5 95.5t-50.5 57.5t-75.5 29.5t-93.5 10.5v125q50 2 93.5 10t75.5 29t50.5 57.5t18.5 93.5v352q0 144 88.5 221.5t261.5 77.5h195v-108h-80q-44 0 -72 -13t-44.5 -38t-23 -62.5t-6.5 -85.5v-348 q0 -93 -53 -152.5t-172 -86.5v-17q118 -29 171.5 -89t53.5 -153v-350q0 -48 6.5 -85.5t23 -63t44.5 -38.5t72 -13h80v-109h-195z" />-<glyph glyph-name="bar" unicode="|" d="M645 -492h-147v2048h147v-2048z" />-<glyph glyph-name="braceright" unicode="}" horiz-adv-x="905" d="M61 -256v109h80q44 0 72 13t44.5 38.5t23 63t6.5 85.5v350q0 93 53.5 153t171.5 89v17q-119 27 -172 86.5t-53 152.5v348q0 48 -6.5 85.5t-23 62.5t-44.5 38t-72 13h-80v108h195q173 0 261.5 -77.5t88.5 -221.5v-352q0 -57 18.5 -93.5t50.5 -57.5t75.5 -29t93.5 -10v-125 q-50 -2 -93.5 -10.5t-75.5 -29.5t-50.5 -57.5t-18.5 -95.5v-350q0 -70 -22.5 -126t-66.5 -95.5t-109.5 -60.5t-151.5 -21h-195z" />-<glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="1149" d="M541 664q-37 16 -65 26.5t-50.5 17t-43 9t-42.5 2.5q-28 0 -58 -9.5t-59.5 -25.5t-57.5 -38t-52 -48v158q99 108 247 108q29 0 54 -2.5t52.5 -9t61 -19t80.5 -32.5q37 -16 65 -27t51 -17.5t43.5 -9t41.5 -2.5q29 0 58.5 9.5t59 26t57.5 38.5t52 47v-157 q-98 -109 -248 -109q-29 0 -53.5 2.5t-52 9.5t-61 19.5t-80.5 32.5z" />-<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="782" d="M569 -369h-356l121 996h115zM557 946q0 -47 -13 -78.5t-35.5 -50.5t-53.5 -27t-66 -8q-34 0 -64.5 8t-53.5 27t-36.5 50.5t-13.5 78.5q0 46 13.5 77.5t36.5 50.5t53.5 27.5t64.5 8.5q35 0 66 -8.5t53.5 -27.5t35.5 -50.5t13 -77.5z" />-<glyph glyph-name="cent" unicode="¢" d="M571 170q-103 7 -186.5 41.5t-143 101.5t-92 170.5t-32.5 249.5q0 153 34 259.5t94.5 174.5t144 102t181.5 42v151h127v-151q88 -5 156 -23.5t114 -47t69.5 -65t23.5 -77.5q0 -33 -11.5 -64.5t-41 -55.5t-80.5 -39t-131 -15q0 43 -5 84t-16.5 75t-30.5 58.5t-47 36.5 v-856q52 1 97.5 14.5t83 35t66 51t46.5 64.5q26 -15 38.5 -40.5t12.5 -53.5q0 -35 -20.5 -72t-62.5 -68.5t-107 -54t-154 -28.5v-170h-127v170zM430 735q0 -158 33.5 -255t107.5 -134v828q-33 -15 -59 -46.5t-44.5 -84t-28 -128.5t-9.5 -180z" />-<glyph glyph-name="sterling" unicode="£" d="M553 711l12.5 -42.5t9.5 -39t6.5 -40t2.5 -46.5q0 -161 -185 -281l7 -10q6 2 18.5 5t29 6t35.5 5t37 2q21 0 40 -2.5t39.5 -8t45 -13l56.5 -17.5q45 -14 81.5 -22t81.5 -8q70 0 122.5 41.5t92.5 109.5v-229q-40 -71 -98 -106t-139 -35q-31 0 -64.5 4t-65.5 10t-61.5 14 t-52.5 17q-50 17 -105.5 31t-97.5 14q-35 0 -65.5 -4.5t-58.5 -12.5t-54.5 -19.5t-54.5 -25.5l-90 -47v184l65 41q32 20 65 48t60 66.5t44.5 88t17.5 111.5q0 59 -12.5 107.5t-32.5 101.5h-236v125h191q-11 25 -22.5 57t-21.5 68t-16 75t-6 78q0 180 117 275.5t338 95.5 q110 0 187 -18.5t125.5 -50.5t70.5 -75.5t22 -93.5q0 -72 -65 -119t-191 -47q0 47 -7 96.5t-25 90t-50 66.5t-82 26q-77 0 -122.5 -58.5t-45.5 -179.5q0 -42 6.5 -82.5t16 -77.5t21.5 -69t24 -57h363v-125z" />-<glyph glyph-name="currency" unicode="¤" d="M195 729q0 59 16.5 113.5t48.5 99.5l-123 123l103 102l122 -123q45 29 97 45.5t110 16.5q57 0 109.5 -16.5t97.5 -47.5l127 127l103 -104l-125 -127q31 -45 48 -97.5t17 -111.5t-16 -110.5t-45 -96.5l121 -121l-103 -102l-121 121q-46 -31 -100 -48.5t-113 -17.5 q-58 0 -112 16.5t-99 47.5l-118 -119l-105 104l119 119q-59 91 -59 207zM334 729q0 -49 18.5 -92t50 -75.5t74.5 -51t92 -18.5q51 0 94.5 18.5t75 51t49 75.5t17.5 92q0 51 -17.5 94.5t-49 76t-75 51t-94.5 18.5q-49 0 -92 -18.5t-74.5 -51t-50 -76t-18.5 -94.5z" />-<glyph glyph-name="yen" unicode="¥" horiz-adv-x="1104" d="M195 0v109h47q34 0 64 1t52.5 11.5t36.5 34.5t15 69v113h-287v121h287v119h-287v120h252l-242 547q-14 31 -26.5 52t-27.5 33.5t-34 18t-45 5.5h-6v108h586v-108h-15q-62 0 -89 -19t-27 -61q0 -25 8.5 -54.5t23.5 -66.5l78 -195q26 -65 45 -125t27 -102q6 28 21 67l32 83 l86 225q13 35 21 60t12.5 44.5t6 34t1.5 27.5q0 42 -28.5 62t-96.5 20h-6v108h426v-108h-6q-26 0 -46 -7t-37.5 -25t-34.5 -49t-38 -79l-211 -496h268v-120h-286v-119h286v-121h-286v-102q0 -49 13.5 -75t36 -37.5t53.5 -13t65 -1.5h47v-109h-735z" />-<glyph glyph-name="brokenbar" unicode="¦" d="M645 737h-147v819h147v-819zM645 -492h-147v820h147v-820z" />-<glyph glyph-name="section" unicode="§" horiz-adv-x="1114" d="M565 -231q-115 0 -191.5 23.5t-122 61t-64.5 84t-19 93.5q0 40 13.5 70t37.5 50.5t57.5 31t73.5 10.5q0 -68 15.5 -125.5t45.5 -99.5t75.5 -65.5t105.5 -23.5q99 0 154 54t55 145q0 42 -12.5 74.5t-50 66t-106.5 73t-183 95.5q-85 42 -145.5 85t-98 89.5t-55 98 t-17.5 112.5q0 69 37 124.5t96 86.5q-35 37 -61.5 98.5t-26.5 145.5q0 78 30 139.5t84 103.5t128 64t162 22q90 0 158.5 -17.5t114.5 -48.5t69.5 -73.5t23.5 -93.5q0 -63 -50 -105t-144 -42q0 45 -8 92.5t-28.5 86.5t-55.5 64t-89 25q-86 0 -138 -50t-52 -143 q0 -49 16.5 -82.5t48 -59.5t76.5 -49t103 -50q108 -52 185.5 -98t127 -94t73 -101t23.5 -119q0 -37 -10.5 -73t-28 -68t-41.5 -58t-51 -43q34 -43 53 -101t19 -118q0 -81 -26 -149t-77.5 -116.5t-129 -75.5t-179.5 -27zM836 526q0 35 -11 66t-39 62.5t-76.5 64t-123.5 69.5 l-128 62.5t-110 64.5q-15 -17 -24 -40.5t-9 -49.5q0 -42 14.5 -75t48 -63.5t89 -62t137.5 -71.5l115.5 -60.5t89.5 -54.5q11 16 19 38t8 50z" />-<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1182" d="M258 1409q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM678 1409q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5 t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="copyright" unicode="©" horiz-adv-x="1731" d="M113 731q0 104 27 200.5t75.5 180t117 152.5t152 118t179.5 76t200 27t200.5 -27t180 -76t152.5 -118t118 -152.5t76 -180t27 -200.5t-27 -200t-76 -179.5t-118 -152t-152.5 -117.5t-180 -75.5t-200.5 -26.5t-200 26.5t-179.5 75.5t-152 117.5t-117 152t-75.5 179.5 t-27 200zM225 731q0 -88 23 -169.5t64.5 -152.5t100 -129.5t129.5 -100t152.5 -64.5t169.5 -23q89 0 171 23t153 64.5t129.5 100t100 129.5t64.5 152.5t23 169.5t-23 170t-64.5 153.5t-100 130t-129.5 100t-153 64.5t-171 23q-88 0 -169.5 -23t-152.5 -64.5t-129.5 -100 t-100 -130t-64.5 -153t-23 -170.5zM901 365q47 0 87 12t72 32t55.5 45t37.5 50q12 -9 20.5 -25.5t8.5 -38.5q0 -28 -19.5 -57t-58 -53t-96 -39t-134.5 -15q-102 0 -178.5 33t-128 93t-77 144t-25.5 187q0 100 28 183t83.5 143t137 93.5t189.5 33.5q71 0 123.5 -11.5 t87.5 -31t52.5 -46t17.5 -57.5q0 -22 -11 -40t-30 -30.5t-44.5 -19t-54.5 -6.5q0 29 -7.5 56.5t-24.5 50t-44.5 36t-68.5 13.5q-72 0 -122.5 -24t-82.5 -71t-46.5 -115t-14.5 -157q0 -177 69 -272.5t199 -95.5z" />-<glyph glyph-name="ordfeminine" unicode="ª" horiz-adv-x="860" d="M295 991q0 -54 23 -76t55 -22q63 0 94 39.5t31 101.5v84l-47 -2q-85 -3 -120.5 -34.5t-35.5 -90.5zM416 1384q-25 0 -40 -9.5t-23.5 -27t-11.5 -40.5t-3 -50q-106 0 -164.5 20.5t-58.5 68.5q0 35 24 59t65.5 39t97 22t118.5 7q155 0 232 -48.5t77 -164.5v-302 q0 -45 19.5 -61t68.5 -16v-90h-239l-50 100h-14q-18 -22 -41 -42.5t-51.5 -36.5t-63 -25t-75.5 -9q-104 0 -164 53t-60 156q0 102 86 150.5t261 56.5l92 4v55q0 29 -3 53.5t-11.5 41.5t-24.5 26.5t-43 9.5z" />-<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="1135" d="M133 606l313 357h144l-207 -410l207 -410h-144l-313 357v106zM545 606l313 357h143l-206 -410l206 -410h-143l-313 357v106z" />-<glyph glyph-name="logicalnot" unicode="¬" d="M1012 805v-512h-148v366h-731v146h879z" />-<glyph glyph-name="uni00AD" unicode="­" horiz-adv-x="635" d="M51 451v215h533v-215h-533z" />-<glyph glyph-name="registered" unicode="®" horiz-adv-x="1731" d="M477 358h27q20 0 38 2.5t32 10t22 21.5t8 38v600q0 24 -8 38.5t-22 22t-32 9.5t-38 2h-27v72h369q352 0 352 -244q0 -49 -16 -86t-42 -64t-59.5 -45.5t-68.5 -29.5l182 -293q10 -17 19.5 -27.5t22.5 -16.5t30.5 -8t42.5 -2v-69h-217l-226 381h-108v-240q2 -24 10 -38 t21.5 -21.5t31 -10t37.5 -2.5h29v-69h-410v69zM758 748h86q55 0 92 11t59 33t31.5 56t9.5 80q0 45 -11 77t-34.5 51.5t-61 28.5t-91.5 9h-80v-346zM113 731q0 104 27 200.5t75.5 180t117 152.5t152 118t179.5 76t200 27t200.5 -27t180 -76t152.5 -118t118 -152.5t76 -180 t27 -200.5t-27 -200t-76 -179.5t-118 -152t-152.5 -117.5t-180 -75.5t-200.5 -26.5t-200 26.5t-179.5 75.5t-152 117.5t-117 152t-75.5 179.5t-27 200zM225 731q0 -88 23 -169.5t64.5 -152.5t100 -129.5t129.5 -100t152.5 -64.5t169.5 -23q89 0 171 23t153 64.5t129.5 100 t100 129.5t64.5 152.5t23 169.5t-23 170t-64.5 153.5t-100 130t-129.5 100t-153 64.5t-171 23q-88 0 -169.5 -23t-152.5 -64.5t-129.5 -100t-100 -130t-64.5 -153t-23 -170.5z" />-<glyph glyph-name="macron" unicode="¯" horiz-adv-x="940" d="M950 1556h-960v121h960v-121z" />-<glyph glyph-name="degree" unicode="°" horiz-adv-x="819" d="M98 1151q0 65 24.5 121.5t66.5 98.5t98.5 66.5t120.5 24.5q65 0 121.5 -24.5t98.5 -66.5t66.5 -98.5t24.5 -121.5q0 -64 -24.5 -120.5t-66.5 -98.5t-98.5 -66t-121.5 -24q-64 0 -120.5 24t-98.5 66t-66.5 98.5t-24.5 120.5zM240 1151q0 -34 13 -65t36 -54.5t53.5 -37 t65.5 -13.5q36 0 67 13.5t54 37t36 54.5t13 65q0 36 -13 67.5t-36 54.5t-54 36.5t-67 13.5q-35 0 -65.5 -13.5t-53.5 -36.5t-36 -54.5t-13 -67.5z" />-<glyph glyph-name="plusminus" unicode="±" d="M1012 0h-879v145h879v-145zM645 659v-366h-147v366h-365v146h365v366h147v-366h367v-146h-367z" />-<glyph glyph-name="uni00B2" unicode="²" horiz-adv-x="819" d="M698 1264q0 -45 -12.5 -85t-45.5 -84t-90.5 -96t-146.5 -122l-167 -132h327q44 0 62 19.5t24 48.5l10 55h76l-8 -282h-651v147l225 189q53 44 87.5 85.5t54.5 81.5t28 80t8 82q0 66 -21.5 103t-74.5 37q-35 0 -56 -18.5t-32.5 -47.5t-15 -65.5t-3.5 -71.5q-34 0 -67 7 t-59 21.5t-42 38t-16 56.5q0 37 19 68.5t56 54.5t91.5 36t124.5 13q83 0 142.5 -15.5t98 -44t56.5 -69t18 -90.5z" />-<glyph glyph-name="uni00B3" unicode="³" horiz-adv-x="819" d="M479 1260q0 63 -21.5 97t-74.5 34q-32 0 -53.5 -14.5t-34 -39.5t-18 -57t-5.5 -68q-41 0 -74 4t-56 13.5t-35.5 26.5t-12.5 44q0 38 19 71.5t56 58t92 39t126 14.5t128 -14t98 -40t63 -63.5t22 -85.5q0 -90 -56 -146.5t-153 -80.5v-11q46 -7 90 -18t78 -33t55 -57.5 t21 -91.5q0 -75 -38 -126.5t-96.5 -83t-128 -45.5t-132.5 -14q-84 0 -151 15t-107 35v106q22 -9 50 -18t58.5 -16.5t62.5 -12t62 -4.5q98 0 152.5 39.5t54.5 128.5q0 69 -55.5 106t-167.5 37h-68v96h68q38 0 71.5 12.5t58 35.5t38.5 55.5t14 71.5z" />-<glyph glyph-name="acute" unicode="´" horiz-adv-x="1182" d="M330 1268l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="uni00B5" unicode="µ" horiz-adv-x="1362" d="M573 -20q-85 0 -145 31.5t-100 88.5q0 -85 7 -157t30 -126t66.5 -87.5t115.5 -42.5q0 -39 -13 -71.5t-37.5 -56.5t-59.5 -37.5t-79 -13.5q-38 0 -73 14t-61.5 45.5t-42 83t-15.5 126.5q0 61 3 127.5t7.5 147.5t8.5 181t5 228v637h312v-676q0 -55 7.5 -104t25 -85.5 t47.5 -57.5t75 -21q43 0 77.5 23t59 64.5t37.5 100t13 129.5v627h311v-815q0 -94 34 -134t105 -40h15v-109h-179q-105 0 -172.5 49t-93.5 129h-10q-24 -45 -50.5 -82t-59.5 -62.5t-75 -39.5t-96 -14z" />-<glyph glyph-name="paragraph" unicode="¶" horiz-adv-x="1284" d="M860 1430h-172v-1657h-342v108h27q35 0 65.5 4.5t53 20t36 44.5t13.5 77v764h-146q-90 0 -150 32.5t-96 88t-51.5 128t-15.5 152.5q0 82 17 149t55 115t98 74t147 26h803v-108h-26q-35 0 -65.5 -5t-53.5 -20.5t-36 -44.5t-13 -78v-1273q0 -48 13 -77t36 -44.5t53.5 -20 t65.5 -4.5h26v-108h-342v1657z" />-<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="623" d="M143 727q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77.5t-36.5 -50.5t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50.5t-13 77.5z" />-<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="682" d="M571 -258q0 -54 -21 -97.5t-59 -74t-91.5 -46.5t-118.5 -16q-16 0 -39 1.5t-48 4.5t-49 7.5t-43 9.5v125q38 -8 75 -12t65 -4q58 0 91.5 20.5t33.5 73.5q0 30 -11.5 49t-32.5 30.5t-49 17t-61 7.5l43 180h117l-21 -88q50 -4 90.5 -18.5t69 -38.5t44 -57.5t15.5 -73.5z " />-<glyph glyph-name="uni00B9" unicode="¹" horiz-adv-x="819" d="M528 1473v-717q0 -26 7.5 -41.5t20.5 -23.5t30.5 -10.5t36.5 -2.5h84v-90h-578v90h104q20 0 36.5 2.5t29.5 10.5t20 23.5t7 41.5v581q-48 -57 -85.5 -92t-74.5 -35q-29 0 -49.5 29.5t-20.5 71.5q37 9 82.5 29.5t106.5 64.5l92 68h151z" />-<glyph glyph-name="ordmasculine" unicode="º" horiz-adv-x="895" d="M311 1126q0 -121 30.5 -183t107.5 -62q75 0 106 62t31 183t-32 180.5t-108 59.5q-75 0 -105 -59.5t-30 -180.5zM823 1126q0 -176 -95.5 -262t-281.5 -86q-178 0 -276 86.5t-98 261.5q0 176 96 261.5t283 85.5q86 0 155 -21.5t117 -64.5t74 -108t26 -153z" />-<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="1135" d="M1001 500l-313 -357h-143l207 410l-207 410h143l313 -357v-106zM590 500l-314 -357h-143l207 410l-207 410h143l314 -357v-106z" />-<glyph glyph-name="onequarter" unicode="¼" horiz-adv-x="1720" d="M1319 595q0 32 2.5 63.5t7.5 69.5q-8 -17 -17 -33.5t-14 -24.5l-233 -321h254v246zM1522 240v-71q0 -26 7 -41.5t19 -23.5t27.5 -10.5t32.5 -2.5h41v-90h-471v90h57q17 0 32 2.5t26.5 10.5t18.5 23.5t7 41.5v71h-389v82l407 564h185v-537h159v-109h-159zM578 0h-160 l731 1462h158zM443 1473v-717q0 -26 7.5 -41.5t20.5 -23.5t30.5 -10.5t36.5 -2.5h84v-90h-578v90h104q20 0 36.5 2.5t29.5 10.5t20 23.5t7 41.5v581q-48 -57 -85.5 -92t-74.5 -35q-29 0 -49.5 29.5t-20.5 71.5q37 9 82.5 29.5t106.5 64.5l92 68h151z" />-<glyph glyph-name="onehalf" unicode="½" horiz-adv-x="1720" d="M537 0h-160l731 1462h158zM443 1473v-717q0 -26 7.5 -41.5t20.5 -23.5t30.5 -10.5t36.5 -2.5h84v-90h-578v90h104q20 0 36.5 2.5t29.5 10.5t20 23.5t7 41.5v581q-48 -57 -85.5 -92t-74.5 -35q-29 0 -49.5 29.5t-20.5 71.5q37 9 82.5 29.5t106.5 64.5l92 68h151zM1628 679 q0 -45 -12.5 -85t-45.5 -84t-90.5 -96t-146.5 -122l-167 -132h327q44 0 62 19.5t24 48.5l10 55h76l-8 -282h-651v147l225 189q53 44 87.5 85.5t54.5 81.5t28 80t8 82q0 66 -21.5 103t-74.5 37q-35 0 -56 -18.5t-32.5 -47.5t-15 -65.5t-3.5 -71.5q-34 0 -67 7t-59 21.5 t-42 38t-16 56.5q0 37 19 68.5t56 54.5t91.5 36t124.5 13q83 0 142.5 -15.5t98 -44t56.5 -69t18 -90.5z" />-<glyph glyph-name="threequarters" unicode="¾" horiz-adv-x="1720" d="M1319 595q0 32 2.5 63.5t7.5 69.5q-8 -17 -17 -33.5t-14 -24.5l-233 -321h254v246zM1522 240v-71q0 -26 7 -41.5t19 -23.5t27.5 -10.5t32.5 -2.5h41v-90h-471v90h57q17 0 32 2.5t26.5 10.5t18.5 23.5t7 41.5v71h-389v82l407 564h185v-537h159v-109h-159zM619 0h-160 l731 1462h158zM479 1260q0 63 -21.5 97t-74.5 34q-32 0 -53.5 -14.5t-34 -39.5t-18 -57t-5.5 -68q-41 0 -74 4t-56 13.5t-35.5 26.5t-12.5 44q0 38 19 71.5t56 58t92 39t126 14.5t128 -14t98 -40t63 -63.5t22 -85.5q0 -90 -56 -146.5t-153 -80.5v-11q46 -7 90 -18t78 -33 t55 -57.5t21 -91.5q0 -75 -38 -126.5t-96.5 -83t-128 -45.5t-132.5 -14q-84 0 -151 15t-107 35v106q22 -9 50 -18t58.5 -16.5t62.5 -12t62 -4.5q98 0 152.5 39.5t54.5 128.5q0 69 -55.5 106t-167.5 37h-68v96h68q38 0 71.5 12.5t58 35.5t38.5 55.5t14 71.5z" />-<glyph glyph-name="questiondown" unicode="¿" horiz-adv-x="1126" d="M113 -14q0 82 25.5 147t76 119t127 99t178.5 87l41 187h125l41 -252q-87 -35 -143.5 -82.5t-88.5 -102t-44.5 -114.5t-12.5 -121q0 -49 9 -89.5t28.5 -70t50 -45.5t72.5 -16q46 0 77.5 20.5t50.5 56t27.5 82t8.5 99.5q63 0 116 -9t91.5 -27t60 -45t21.5 -63 q0 -50 -26 -93t-79.5 -75t-136 -50.5t-195.5 -18.5q-108 0 -200 25.5t-158.5 74t-104.5 118.5t-38 159zM795 944q0 -47 -13 -78.5t-35.5 -50.5t-53.5 -27t-66 -8q-34 0 -64.5 8t-53.5 27t-36.5 50.5t-13.5 78.5q0 46 13.5 77.5t36.5 50.5t53.5 27.5t64.5 8.5q35 0 66 -8.5 t53.5 -27.5t35.5 -50.5t13 -77.5z" />-<glyph glyph-name="Agrave" unicode="À" horiz-adv-x="1542" d="M446 481l-59 -176q-8 -25 -16.5 -58.5t-8.5 -58.5q0 -20 8 -35t21 -24.5t29.5 -14.5t34.5 -5h86v-109h-533v109h25q27 0 49.5 6t42 22.5t37 45.5t35.5 75l444 1204h281l428 -1206q15 -43 31.5 -71.5t36 -45t41.5 -23.5t46 -7h37v-109h-676v109h80q15 0 31 4.5t28.5 14 t20.5 24.5t8 36q0 25 -6 48t-12 40l-72 205h-498zM795 942l-22.5 73.5l-23 78.5l-22 79.5t-18.5 75.5q-9 -31 -21 -68l-25.5 -76l-27 -78l-25.5 -75l-121 -346h414zM758 1579q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5 l50 -67v-27h-139z" />-<glyph glyph-name="Aacute" unicode="Á" horiz-adv-x="1542" d="M446 481l-59 -176q-8 -25 -16.5 -58.5t-8.5 -58.5q0 -20 8 -35t21 -24.5t29.5 -14.5t34.5 -5h86v-109h-533v109h25q27 0 49.5 6t42 22.5t37 45.5t35.5 75l444 1204h281l428 -1206q15 -43 31.5 -71.5t36 -45t41.5 -23.5t46 -7h37v-109h-676v109h80q15 0 31 4.5t28.5 14 t20.5 24.5t8 36q0 25 -6 48t-12 40l-72 205h-498zM795 942l-22.5 73.5l-23 78.5l-22 79.5t-18.5 75.5q-9 -31 -21 -68l-25.5 -76l-27 -78l-25.5 -75l-121 -346h414zM641 1606l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5 t-106.5 -69.5h-139v27z" />-<glyph glyph-name="Acircumflex" unicode="Â" horiz-adv-x="1542" d="M446 481l-59 -176q-8 -25 -16.5 -58.5t-8.5 -58.5q0 -20 8 -35t21 -24.5t29.5 -14.5t34.5 -5h86v-109h-533v109h25q27 0 49.5 6t42 22.5t37 45.5t35.5 75l444 1204h281l428 -1206q15 -43 31.5 -71.5t36 -45t41.5 -23.5t46 -7h37v-109h-676v109h80q15 0 31 4.5t28.5 14 t20.5 24.5t8 36q0 25 -6 48t-12 40l-72 205h-498zM795 942l-22.5 73.5l-23 78.5l-22 79.5t-18.5 75.5q-9 -31 -21 -68l-25.5 -76l-27 -78l-25.5 -75l-121 -346h414zM415 1606l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141 l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="Atilde" unicode="Ã" horiz-adv-x="1542" d="M446 481l-59 -176q-8 -25 -16.5 -58.5t-8.5 -58.5q0 -20 8 -35t21 -24.5t29.5 -14.5t34.5 -5h86v-109h-533v109h25q27 0 49.5 6t42 22.5t37 45.5t35.5 75l444 1204h281l428 -1206q15 -43 31.5 -71.5t36 -45t41.5 -23.5t46 -7h37v-109h-676v109h80q15 0 31 4.5t28.5 14 t20.5 24.5t8 36q0 25 -6 48t-12 40l-72 205h-498zM795 942l-22.5 73.5l-23 78.5l-22 79.5t-18.5 75.5q-9 -31 -21 -68l-25.5 -76l-27 -78l-25.5 -75l-121 -346h414zM942 1774q22 0 39.5 9t30 24t20 34.5t10.5 40.5h133q-3 -62 -23 -117t-53.5 -96.5t-79 -65.5t-100.5 -24 t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-23 0 -40.5 -9t-30 -24t-20 -34.5t-10.5 -40.5h-133q3 62 23.5 117t54 96.5t79.5 65.5t101 24t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="Adieresis" unicode="Ä" horiz-adv-x="1542" d="M446 481l-59 -176q-8 -25 -16.5 -58.5t-8.5 -58.5q0 -20 8 -35t21 -24.5t29.5 -14.5t34.5 -5h86v-109h-533v109h25q27 0 49.5 6t42 22.5t37 45.5t35.5 75l444 1204h281l428 -1206q15 -43 31.5 -71.5t36 -45t41.5 -23.5t46 -7h37v-109h-676v109h80q15 0 31 4.5t28.5 14 t20.5 24.5t8 36q0 25 -6 48t-12 40l-72 205h-498zM795 942l-22.5 73.5l-23 78.5l-22 79.5t-18.5 75.5q-9 -31 -21 -68l-25.5 -76l-27 -78l-25.5 -75l-121 -346h414zM436 1747q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5 q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM856 1747q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5 t-10 58.5z" />-<glyph glyph-name="Aring" unicode="Å" horiz-adv-x="1542" d="M899 1573q0 30 -9.5 51t-26 34t-38.5 19t-47 6t-47 -6t-38.5 -19t-26 -34t-9.5 -51t9.5 -51t26 -34.5t38.5 -19.5t47 -6t47 6t38.5 19.5t26 34.5t9.5 51zM1024 1573q0 -55 -19 -96.5t-52.5 -69.5t-78.5 -42.5t-96 -14.5t-96 14.5t-78.5 42.5t-52.5 69.5t-19 96.5 q0 54 19 96t52.5 70t78.5 42.5t96 14.5t96 -14.5t78.5 -42.5t52.5 -70t19 -96zM446 481l-59 -176q-8 -25 -16.5 -58.5t-8.5 -58.5q0 -20 8 -35t21 -24.5t29.5 -14.5t34.5 -5h86v-109h-533v109h25q27 0 49.5 6t42 22.5t37 45.5t35.5 75l444 1204h281l428 -1206 q15 -43 31.5 -71.5t36 -45t41.5 -23.5t46 -7h37v-109h-676v109h80q15 0 31 4.5t28.5 14t20.5 24.5t8 36q0 25 -6 48t-12 40l-72 205h-498zM795 942l-22.5 73.5l-23 78.5l-22 79.5t-18.5 75.5q-9 -31 -21 -68l-25.5 -76l-27 -78l-25.5 -75l-121 -346h414z" />-<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="2034" d="M1270 125h409q31 0 53 11.5t38 32.5t25.5 49.5t14.5 62.5l17 96h141l-14 -377h-1200v109h86q56 0 80 34.5t24 87.5v238h-471l-86 -172q-17 -32 -25 -61t-8 -48q0 -42 31.5 -60.5t91.5 -18.5h35v-109h-512v109h25q53 0 95 38.5t87 120.5l575 1075l-135 11v108h1243l8 -377 h-143l-10 97q-8 75 -38 115t-93 40h-344v-512h485v-123h-485v-577zM924 1337l-385 -745h405v745h-20z" />-<glyph glyph-name="Ccedilla" unicode="Ç" horiz-adv-x="1368" d="M870 143q75 0 133.5 17.5t104.5 45.5t80.5 63t60.5 69q16 -12 25.5 -37t9.5 -51q0 -43 -23 -90.5t-77 -87.5t-143 -66t-220 -26q-178 0 -311 54t-221 153t-132 238t-44 308q0 166 45 304t133.5 237t221 154t306.5 55q118 0 205.5 -18.5t145.5 -50.5t87 -75.5t29 -93.5 q0 -38 -16.5 -70.5t-49 -56.5t-80.5 -37.5t-110 -13.5q0 51 -11 101.5t-37.5 91.5t-69.5 66.5t-107 25.5q-97 0 -164 -41t-107.5 -120t-58.5 -194.5t-18 -263.5t22 -259t71 -184.5t127.5 -110t192.5 -36.5zM962 -258q0 -54 -21 -97.5t-59 -74t-91.5 -46.5t-118.5 -16 q-16 0 -39 1.5t-48 4.5t-49 7.5t-43 9.5v125q38 -8 75 -12t65 -4q58 0 91.5 20.5t33.5 73.5q0 30 -11.5 49t-32.5 30.5t-49 17t-61 7.5l43 180h117l-21 -88q50 -4 90.5 -18.5t69 -38.5t44 -57.5t15.5 -73.5z" />-<glyph glyph-name="Egrave" unicode="È" horiz-adv-x="1337" d="M573 125h410q31 0 53 11.5t38 32.5t25.5 49.5t14.5 62.5l16 96h142l-15 -377h-1200v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v990q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v108h1137l8 -377h-143l-10 97q-8 75 -38 115t-93 40h-345v-512h486v-123h-486v-577zM689 1579 q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="Eacute" unicode="É" horiz-adv-x="1337" d="M573 125h410q31 0 53 11.5t38 32.5t25.5 49.5t14.5 62.5l16 96h142l-15 -377h-1200v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v990q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v108h1137l8 -377h-143l-10 97q-8 75 -38 115t-93 40h-345v-512h486v-123h-486v-577zM523 1606 l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="Ecircumflex" unicode="Ê" horiz-adv-x="1337" d="M573 125h410q31 0 53 11.5t38 32.5t25.5 49.5t14.5 62.5l16 96h142l-15 -377h-1200v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v990q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v108h1137l8 -377h-143l-10 97q-8 75 -38 115t-93 40h-345v-512h486v-123h-486v-577zM288 1606 l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="Edieresis" unicode="Ë" horiz-adv-x="1337" d="M573 125h410q31 0 53 11.5t38 32.5t25.5 49.5t14.5 62.5l16 96h142l-15 -377h-1200v109h86q22 0 41 4t33.5 16.5t22.5 37t8 64.5v990q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v108h1137l8 -377h-143l-10 97q-8 75 -38 115t-93 40h-345v-512h486v-123h-486v-577zM356 1747 q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM776 1747q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5 q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="Igrave" unicode="Ì" horiz-adv-x="821" d="M57 0v109h86q23 0 42 4.5t33 18.5t22 40t8 70v978q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v109h707v-109h-86q-22 0 -41.5 -4.5t-33.5 -18.5t-22 -40t-8 -70v-978q0 -44 8 -70t22 -40t33.5 -18.5t41.5 -4.5h86v-109h-707zM429 1579q-48 28 -106.5 69.5t-113 85.5 t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="821" d="M57 0v109h86q23 0 42 4.5t33 18.5t22 40t8 70v978q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v109h707v-109h-86q-22 0 -41.5 -4.5t-33.5 -18.5t-22 -40t-8 -70v-978q0 -44 8 -70t22 -40t33.5 -18.5t41.5 -4.5h86v-109h-707zM253 1606l49.5 67l55.5 78.5t52.5 81t40.5 74.5 h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="821" d="M57 0v109h86q23 0 42 4.5t33 18.5t22 40t8 70v978q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v109h707v-109h-86q-22 0 -41.5 -4.5t-33.5 -18.5t-22 -40t-8 -70v-978q0 -44 8 -70t22 -40t33.5 -18.5t41.5 -4.5h86v-109h-707zM48 1606l56.5 67l64.5 78.5t60.5 81t44.5 74.5 h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="821" d="M57 0v109h86q23 0 42 4.5t33 18.5t22 40t8 70v978q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v109h707v-109h-86q-22 0 -41.5 -4.5t-33.5 -18.5t-22 -40t-8 -70v-978q0 -44 8 -70t22 -40t33.5 -18.5t41.5 -4.5h86v-109h-707zM79 1747q0 35 10 59.5t26.5 39.5t38.5 21.5 t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM499 1747q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5 t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="1571" d="M1458 758q0 -168 -46 -307.5t-137.5 -239.5t-227 -155.5t-314.5 -55.5h-676v109h86q23 0 42 4.5t33 18.5t22 40t8 70v460h-170v125h170v402q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-41 4.5h-86v108h676q170 0 304.5 -44.5t228 -133t143 -220.5t49.5 -306zM1112 758 q0 293 -107.5 436t-316.5 143h-117v-510h256v-125h-256v-575h115q105 0 185 43.5t133.5 125.5t80.5 198.5t27 263.5z" />-<glyph glyph-name="Ntilde" unicode="Ñ" horiz-adv-x="1614" d="M1200 0l-799 1128v-886q0 -44 8.5 -70t22.5 -40t33.5 -18.5t40.5 -4.5h86v-109h-535v109h86q22 0 41 4.5t33.5 18.5t22.5 40t8 70v987q0 41 -8.5 65.5t-23 37.5t-33.5 17.5t-40 4.5h-86v108h455l723 -1022v789q0 41 -8.5 65.5t-23 37.5t-33.5 17.5t-40 4.5h-86v108h535 v-108h-86q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-1221h-189zM998 1774q22 0 39.5 9t30 24t20 34.5t10.5 40.5h133q-3 -62 -23 -117t-53.5 -96.5t-79 -65.5t-100.5 -24t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-23 0 -40.5 -9t-30 -24t-20 -34.5t-10.5 -40.5h-133 q3 62 23.5 117t54 96.5t79.5 65.5t101 24t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="Ograve" unicode="Ò" horiz-adv-x="1612" d="M1499 733q0 -169 -45.5 -308t-134 -238t-217 -153t-295.5 -54q-175 0 -305.5 54t-216.5 153t-129 238.5t-43 309.5t43 308.5t129.5 236.5t217 151.5t306.5 53.5q166 0 294.5 -53.5t216.5 -152t133.5 -237t45.5 -309.5zM457 733q0 -147 19 -262t61 -194.5t108.5 -121.5 t161.5 -42q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262t-18.5 262t-59.5 194.5t-107 121t-161 41.5q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262zM813 1579q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67 v-27h-139z" />-<glyph glyph-name="Oacute" unicode="Ó" horiz-adv-x="1612" d="M1499 733q0 -169 -45.5 -308t-134 -238t-217 -153t-295.5 -54q-175 0 -305.5 54t-216.5 153t-129 238.5t-43 309.5t43 308.5t129.5 236.5t217 151.5t306.5 53.5q166 0 294.5 -53.5t216.5 -152t133.5 -237t45.5 -309.5zM457 733q0 -147 19 -262t61 -194.5t108.5 -121.5 t161.5 -42q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262t-18.5 262t-59.5 194.5t-107 121t-161 41.5q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262zM666 1606l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5 h-139v27z" />-<glyph glyph-name="Ocircumflex" unicode="Ô" horiz-adv-x="1612" d="M1499 733q0 -169 -45.5 -308t-134 -238t-217 -153t-295.5 -54q-175 0 -305.5 54t-216.5 153t-129 238.5t-43 309.5t43 308.5t129.5 236.5t217 151.5t306.5 53.5q166 0 294.5 -53.5t216.5 -152t133.5 -237t45.5 -309.5zM457 733q0 -147 19 -262t61 -194.5t108.5 -121.5 t161.5 -42q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262t-18.5 262t-59.5 194.5t-107 121t-161 41.5q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262zM440 1606l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40 l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="Otilde" unicode="Õ" horiz-adv-x="1612" d="M1499 733q0 -169 -45.5 -308t-134 -238t-217 -153t-295.5 -54q-175 0 -305.5 54t-216.5 153t-129 238.5t-43 309.5t43 308.5t129.5 236.5t217 151.5t306.5 53.5q166 0 294.5 -53.5t216.5 -152t133.5 -237t45.5 -309.5zM457 733q0 -147 19 -262t61 -194.5t108.5 -121.5 t161.5 -42q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262t-18.5 262t-59.5 194.5t-107 121t-161 41.5q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262zM975 1774q22 0 39.5 9t30 24t20 34.5t10.5 40.5h133q-3 -62 -23 -117t-53.5 -96.5t-79 -65.5t-100.5 -24t-99.5 20 t-83 44.5l-72 44.5t-66.5 20q-23 0 -40.5 -9t-30 -24t-20 -34.5t-10.5 -40.5h-133q3 62 23.5 117t54 96.5t79.5 65.5t101 24t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="Odieresis" unicode="Ö" horiz-adv-x="1612" d="M1499 733q0 -169 -45.5 -308t-134 -238t-217 -153t-295.5 -54q-175 0 -305.5 54t-216.5 153t-129 238.5t-43 309.5t43 308.5t129.5 236.5t217 151.5t306.5 53.5q166 0 294.5 -53.5t216.5 -152t133.5 -237t45.5 -309.5zM457 733q0 -147 19 -262t61 -194.5t108.5 -121.5 t161.5 -42q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262t-18.5 262t-59.5 194.5t-107 121t-161 41.5q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262zM463 1747q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5 t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM883 1747q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="multiply" unicode="×" d="M571 631l-301 -303l-104 104l301 303l-301 301l104 103l301 -301l301 303l105 -105l-303 -303l303 -303l-103 -102z" />-<glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1612" d="M1499 733q0 -169 -45.5 -308t-134 -238t-217 -153t-295.5 -54q-173 0 -303 53l-62 -115h-145l94 174q-140 96 -209 260.5t-69 382.5q0 170 43 308.5t129.5 236.5t217 151.5t306.5 53.5q85 0 160 -15t141 -43l64 119h143l-96 -178q136 -96 207 -258t71 -377zM457 733 q0 -128 14 -230t45 -179l506 942q-38 42 -91.5 64t-121.5 22q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262zM1155 733q0 127 -14 228.5t-43 179.5l-506 -944q40 -42 93 -63t122 -21q96 0 162.5 42t107.5 121.5t59.5 194.5t18.5 262z" />-<glyph glyph-name="Ugrave" unicode="Ù" horiz-adv-x="1530" d="M1497 1354h-88q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-799q0 -103 -29.5 -185t-92 -139t-159.5 -87.5t-231 -30.5t-239.5 25.5t-178.5 81.5t-111.5 144.5t-38.5 214.5v783q0 41 -8.5 65.5t-23 37.5t-33 17.5t-39.5 4.5h-88v108h706v-108h-86q-21 0 -40 -4.5 t-33.5 -18.5t-22.5 -40t-8 -70v-791q0 -86 21.5 -144.5t61.5 -94t96 -51t126 -15.5q68 0 123 17.5t93.5 54.5t59.5 94t21 135v803q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-40 4.5h-86v108h536v-108zM813 1579q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321 q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="Uacute" unicode="Ú" horiz-adv-x="1530" d="M1497 1354h-88q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-799q0 -103 -29.5 -185t-92 -139t-159.5 -87.5t-231 -30.5t-239.5 25.5t-178.5 81.5t-111.5 144.5t-38.5 214.5v783q0 41 -8.5 65.5t-23 37.5t-33 17.5t-39.5 4.5h-88v108h706v-108h-86q-21 0 -40 -4.5 t-33.5 -18.5t-22.5 -40t-8 -70v-791q0 -86 21.5 -144.5t61.5 -94t96 -51t126 -15.5q68 0 123 17.5t93.5 54.5t59.5 94t21 135v803q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-40 4.5h-86v108h536v-108zM643 1606l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5 t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="Ucircumflex" unicode="Û" horiz-adv-x="1530" d="M1497 1354h-88q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-799q0 -103 -29.5 -185t-92 -139t-159.5 -87.5t-231 -30.5t-239.5 25.5t-178.5 81.5t-111.5 144.5t-38.5 214.5v783q0 41 -8.5 65.5t-23 37.5t-33 17.5t-39.5 4.5h-88v108h706v-108h-86q-21 0 -40 -4.5 t-33.5 -18.5t-22.5 -40t-8 -70v-791q0 -86 21.5 -144.5t61.5 -94t96 -51t126 -15.5q68 0 123 17.5t93.5 54.5t59.5 94t21 135v803q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-40 4.5h-86v108h536v-108zM454 1606l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5 t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="Udieresis" unicode="Ü" horiz-adv-x="1530" d="M1497 1354h-88q-21 0 -40 -4.5t-33.5 -18.5t-22.5 -40t-8 -70v-799q0 -103 -29.5 -185t-92 -139t-159.5 -87.5t-231 -30.5t-239.5 25.5t-178.5 81.5t-111.5 144.5t-38.5 214.5v783q0 41 -8.5 65.5t-23 37.5t-33 17.5t-39.5 4.5h-88v108h706v-108h-86q-21 0 -40 -4.5 t-33.5 -18.5t-22.5 -40t-8 -70v-791q0 -86 21.5 -144.5t61.5 -94t96 -51t126 -15.5q68 0 123 17.5t93.5 54.5t59.5 94t21 135v803q0 41 -8 65.5t-22.5 37.5t-33.5 17.5t-40 4.5h-86v108h536v-108zM494 1747q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5 t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM914 1747q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7 q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="Yacute" unicode="Ý" horiz-adv-x="1419" d="M336 0v109h96q25 0 46.5 3t37.5 15.5t25.5 37.5t9.5 68v285l-379 727q-15 30 -28.5 51t-29.5 33.5t-36.5 18.5t-50.5 6h-27v108h686v-108h-35q-62 0 -92.5 -25t-30.5 -67q0 -26 9.5 -56.5t21.5 -56.5l152 -301q32 -65 52.5 -115t37.5 -98q21 54 48.5 117.5t61.5 132.5 l119 245q22 45 28.5 75.5t6.5 47.5q0 53 -33.5 77t-101.5 24h-47v108h536v-108h-39q-26 0 -44.5 -7t-35 -25t-34 -49t-41.5 -79l-348 -678v-280q0 -45 9 -70t24.5 -38t36 -16t44.5 -3h101v-109h-756zM602 1606l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21 q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="Thorn" unicode="Þ" horiz-adv-x="1307" d="M571 410h50q76 0 129 19t86.5 60t49 106t15.5 157q0 82 -13.5 142.5t-43 100t-77 59t-116.5 19.5h-80v-663zM1245 760q0 -92 -32 -177t-104 -150t-187 -103.5t-281 -38.5h-70v-60q2 -40 11 -64.5t23.5 -37t34 -16.5t40.5 -4h84v-109h-707v109h86q23 0 42 4.5t33 18.5 t22 40t8 70v979q0 44 -8 70t-22 40t-33 18.5t-42 4.5h-86v108h707v-108h-84q-21 0 -41 -4t-35 -17t-24 -37t-9 -65v-37h115q142 -2 247 -32.5t174.5 -86t103.5 -135t34 -180.5z" />-<glyph glyph-name="germandbls" unicode="ß" horiz-adv-x="1446" d="M205 1118q0 128 41 216t112.5 142t168.5 77.5t210 23.5q142 0 241 -37t161.5 -109.5t91 -179t29.5 -245.5h-115q-50 0 -93.5 -6t-76 -22t-51.5 -42.5t-19 -67.5q0 -36 12.5 -63t39.5 -50.5t70.5 -47t105.5 -52.5q64 -30 108 -67.5t71.5 -80.5t39.5 -89t12 -94 q0 -87 -27.5 -151.5t-79 -107.5t-126.5 -64t-170 -21q-93 0 -176.5 18.5t-149.5 56.5v248h110q7 -41 24.5 -78t44 -64.5t61.5 -44t77 -16.5q69 0 109.5 36t40.5 102q0 36 -9.5 66.5t-33 58.5t-63.5 55t-101 55q-75 35 -124.5 75.5t-79 86.5t-42 96t-12.5 103 q0 71 24.5 122.5t69 86t105.5 53t133 22.5q-1 94 -16.5 159.5t-44.5 106.5t-70.5 59.5t-94.5 18.5q-52 0 -94.5 -17t-72.5 -52.5t-46 -90t-16 -128.5v-1174h-502v109h88q22 0 41 4.5t33.5 18.5t22.5 40t8 70v714h-164v142h164v20z" />-<glyph glyph-name="agrave" unicode="à" horiz-adv-x="1227" d="M410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM592 999q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5 q108 0 188.5 -18.5t134 -59.5t80.5 -107.5t27 -162.5v-522q0 -42 6.5 -70t20.5 -44.5t38 -23.5t58 -7h8v-109h-381l-43 141h-18q-34 -41 -64 -71.5t-64 -50.5t-76.5 -29.5t-100.5 -9.5q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113 q0 51 -4 94t-17 74t-38.5 48t-67.5 17zM618 1241q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="aacute" unicode="á" horiz-adv-x="1227" d="M410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM592 999q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5 q108 0 188.5 -18.5t134 -59.5t80.5 -107.5t27 -162.5v-522q0 -42 6.5 -70t20.5 -44.5t38 -23.5t58 -7h8v-109h-381l-43 141h-18q-34 -41 -64 -71.5t-64 -50.5t-76.5 -29.5t-100.5 -9.5q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113 q0 51 -4 94t-17 74t-38.5 48t-67.5 17zM467 1268l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="acircumflex" unicode="â" horiz-adv-x="1227" d="M410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM592 999q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5 q108 0 188.5 -18.5t134 -59.5t80.5 -107.5t27 -162.5v-522q0 -42 6.5 -70t20.5 -44.5t38 -23.5t58 -7h8v-109h-381l-43 141h-18q-34 -41 -64 -71.5t-64 -50.5t-76.5 -29.5t-100.5 -9.5q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113 q0 51 -4 94t-17 74t-38.5 48t-67.5 17zM256 1268l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="atilde" unicode="ã" horiz-adv-x="1227" d="M410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM592 999q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5 q108 0 188.5 -18.5t134 -59.5t80.5 -107.5t27 -162.5v-522q0 -42 6.5 -70t20.5 -44.5t38 -23.5t58 -7h8v-109h-381l-43 141h-18q-34 -41 -64 -71.5t-64 -50.5t-76.5 -29.5t-100.5 -9.5q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113 q0 51 -4 94t-17 74t-38.5 48t-67.5 17zM789 1436q22 0 39.5 9t30 24t20 34.5t10.5 40.5h133q-3 -62 -23 -117t-53.5 -96.5t-79 -65.5t-100.5 -24t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-23 0 -40.5 -9t-30 -24t-20 -34.5t-10.5 -40.5h-133q3 62 23.5 117t54 96.5t79.5 65.5 t101 24t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="adieresis" unicode="ä" horiz-adv-x="1227" d="M410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM592 999q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5 q108 0 188.5 -18.5t134 -59.5t80.5 -107.5t27 -162.5v-522q0 -42 6.5 -70t20.5 -44.5t38 -23.5t58 -7h8v-109h-381l-43 141h-18q-34 -41 -64 -71.5t-64 -50.5t-76.5 -29.5t-100.5 -9.5q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113 q0 51 -4 94t-17 74t-38.5 48t-67.5 17zM278 1409q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM698 1409q0 35 10 59.5t27 39.5t39 21.5t47 6.5 q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="aring" unicode="å" horiz-adv-x="1227" d="M740 1444q0 30 -9.5 51t-26 34t-38.5 19t-47 6t-47 -6t-38.5 -19t-26 -34t-9.5 -51t9.5 -51t26 -34.5t38.5 -19.5t47 -6t47 6t38.5 19.5t26 34.5t9.5 51zM865 1444q0 -55 -19 -96.5t-52.5 -69.5t-78.5 -42.5t-96 -14.5t-96 14.5t-78.5 42.5t-52.5 69.5t-19 96.5 q0 54 19 96t52.5 70t78.5 42.5t96 14.5t96 -14.5t78.5 -42.5t52.5 -70t19 -96zM410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM592 999q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70 t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5q108 0 188.5 -18.5t134 -59.5t80.5 -107.5t27 -162.5v-522q0 -42 6.5 -70t20.5 -44.5t38 -23.5t58 -7h8v-109h-381l-43 141h-18q-34 -41 -64 -71.5t-64 -50.5t-76.5 -29.5t-100.5 -9.5 q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113q0 51 -4 94t-17 74t-38.5 48t-67.5 17z" />-<glyph glyph-name="ae" unicode="æ" horiz-adv-x="1792" d="M410 305q0 -88 28 -132t88 -44q44 0 79.5 18.5t61 52.5t39 82.5t13.5 108.5v154l-92 -6q-61 -3 -103 -19.5t-67 -45.5t-36 -71t-11 -98zM1231 991q-85 0 -136.5 -85t-56.5 -249h355q0 160 -39 247t-123 87zM1253 -20q-151 0 -260.5 50t-175.5 146q-69 -103 -171 -149.5 t-232 -46.5q-68 0 -126.5 20t-102 61.5t-68.5 104t-25 147.5q0 167 114.5 247t344.5 87l168 6v113q0 51 -4 94t-17 74t-38.5 48t-67.5 17q-39 0 -65.5 -16.5t-42.5 -46t-22.5 -70t-6.5 -88.5q-138 0 -207.5 31t-69.5 106q0 56 33.5 96t91 65t134 36.5t163.5 11.5 q109 0 190.5 -27t135.5 -89q60 57 135 86.5t166 29.5q111 0 200 -31.5t151 -93.5t95 -154t33 -214v-105h-672q3 -103 22.5 -177t54.5 -122t84.5 -71t113.5 -23q53 0 98 12.5t81.5 35t63.5 53t45 65.5q56 -30 56 -100q0 -44 -23.5 -83.5t-72.5 -69.5t-124.5 -48t-179.5 -18z " />-<glyph glyph-name="ccedilla" unicode="ç" horiz-adv-x="1079" d="M604 -20q-113 0 -206.5 29t-160.5 96t-104 175t-37 265q0 166 38.5 277t106 178t159.5 95.5t198 28.5q99 0 175 -16.5t127 -45.5t77.5 -68.5t26.5 -84.5q0 -33 -11.5 -64.5t-41 -55.5t-81 -39t-131.5 -15q0 53 -6.5 101t-21.5 84t-40.5 57.5t-64.5 21.5 q-45 0 -80.5 -21.5t-61 -73.5t-39 -139t-13.5 -218q0 -208 57 -311t186 -103q53 0 99.5 12.5t84.5 35t66.5 53t46.5 65.5q25 -15 37 -40.5t12 -53.5q0 -39 -23 -79t-71.5 -72.5t-123.5 -53t-179 -20.5zM839 -258q0 -54 -21 -97.5t-59 -74t-91.5 -46.5t-118.5 -16 q-16 0 -39 1.5t-48 4.5t-49 7.5t-43 9.5v125q38 -8 75 -12t65 -4q58 0 91.5 20.5t33.5 73.5q0 30 -11.5 49t-32.5 30.5t-49 17t-61 7.5l43 180h117l-21 -88q50 -4 90.5 -18.5t69 -38.5t44 -57.5t15.5 -73.5z" />-<glyph glyph-name="egrave" unicode="è" horiz-adv-x="1169" d="M608 991q-86 0 -136.5 -85t-55.5 -249h354q0 78 -9 140t-28.5 105t-50 66t-74.5 23zM627 -20q-130 0 -229.5 38t-166.5 110t-101 176.5t-34 238.5q0 144 34 253t99 182t159.5 109.5t215.5 36.5q111 0 200 -31.5t151 -93.5t95 -154t33 -214v-105h-671q3 -103 22.5 -177 t54 -122t84 -71t113.5 -23q53 0 98 12.5t81.5 35t64 53t45.5 65.5q55 -30 55 -100q0 -44 -24 -83.5t-74 -69.5t-125.5 -48t-179.5 -18zM642 1241q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="eacute" unicode="é" horiz-adv-x="1169" d="M608 991q-86 0 -136.5 -85t-55.5 -249h354q0 78 -9 140t-28.5 105t-50 66t-74.5 23zM627 -20q-130 0 -229.5 38t-166.5 110t-101 176.5t-34 238.5q0 144 34 253t99 182t159.5 109.5t215.5 36.5q111 0 200 -31.5t151 -93.5t95 -154t33 -214v-105h-671q3 -103 22.5 -177 t54 -122t84 -71t113.5 -23q53 0 98 12.5t81.5 35t64 53t45.5 65.5q55 -30 55 -100q0 -44 -24 -83.5t-74 -69.5t-125.5 -48t-179.5 -18zM473 1268l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="1169" d="M608 991q-86 0 -136.5 -85t-55.5 -249h354q0 78 -9 140t-28.5 105t-50 66t-74.5 23zM627 -20q-130 0 -229.5 38t-166.5 110t-101 176.5t-34 238.5q0 144 34 253t99 182t159.5 109.5t215.5 36.5q111 0 200 -31.5t151 -93.5t95 -154t33 -214v-105h-671q3 -103 22.5 -177 t54 -122t84 -71t113.5 -23q53 0 98 12.5t81.5 35t64 53t45.5 65.5q55 -30 55 -100q0 -44 -24 -83.5t-74 -69.5t-125.5 -48t-179.5 -18zM254 1268l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50 l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="edieresis" unicode="ë" horiz-adv-x="1169" d="M608 991q-86 0 -136.5 -85t-55.5 -249h354q0 78 -9 140t-28.5 105t-50 66t-74.5 23zM627 -20q-130 0 -229.5 38t-166.5 110t-101 176.5t-34 238.5q0 144 34 253t99 182t159.5 109.5t215.5 36.5q111 0 200 -31.5t151 -93.5t95 -154t33 -214v-105h-671q3 -103 22.5 -177 t54 -122t84 -71t113.5 -23q53 0 98 12.5t81.5 35t64 53t45.5 65.5q55 -30 55 -100q0 -44 -24 -83.5t-74 -69.5t-125.5 -48t-179.5 -18zM281 1409q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22 t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM701 1409q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="igrave" unicode="ì" horiz-adv-x="721" d="M59 109q23 0 48.5 4.5t47 18.5t36 40t14.5 70v622q0 41 -14.5 65.5t-36.5 38t-47.5 17.5t-47.5 4h-24v109h481v-856q0 -44 14.5 -70t36 -40t47.5 -18.5t48 -4.5h24v-109h-651v109h24zM370 1241q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5 l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="iacute" unicode="í" horiz-adv-x="721" d="M59 109q23 0 48.5 4.5t47 18.5t36 40t14.5 70v622q0 41 -14.5 65.5t-36.5 38t-47.5 17.5t-47.5 4h-24v109h481v-856q0 -44 14.5 -70t36 -40t47.5 -18.5t48 -4.5h24v-109h-651v109h24zM267 1268l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5 t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="721" d="M59 109q23 0 48.5 4.5t47 18.5t36 40t14.5 70v622q0 41 -14.5 65.5t-36.5 38t-47.5 17.5t-47.5 4h-24v109h481v-856q0 -44 14.5 -70t36 -40t47.5 -18.5t48 -4.5h24v-109h-651v109h24zM-30 1268l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81 l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="721" d="M59 109q23 0 48.5 4.5t47 18.5t36 40t14.5 70v622q0 41 -14.5 65.5t-36.5 38t-47.5 17.5t-47.5 4h-24v109h481v-856q0 -44 14.5 -70t36 -40t47.5 -18.5t48 -4.5h24v-109h-651v109h24zM-1 1409q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5 t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM419 1409q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22 t-27 39.5t-10 58.5z" />-<glyph glyph-name="eth" unicode="ð" horiz-adv-x="1253" d="M1157 596q0 -312 -135.5 -464t-398.5 -152q-122 0 -219.5 33t-166 100.5t-105 169.5t-36.5 239q0 136 32.5 237.5t95.5 169t155 101t211 33.5q68 0 126.5 -16t96.5 -39q-11 33 -25 65.5t-34 65t-48 65t-67 64.5l-289 -148v133l182 95q-51 32 -108.5 50.5t-132.5 31.5v129 q38 -3 90.5 -14.5t108.5 -29t109.5 -39.5t92.5 -46l258 131v-136l-143 -73q78 -61 142.5 -140.5t110.5 -175.5t71.5 -206.5t25.5 -233.5zM414 520q0 -101 11.5 -178t37 -128.5t66.5 -78t100 -26.5q58 0 98.5 26.5t66 78t37 128.5t11.5 178q0 105 -11.5 182.5t-37 128.5 t-66.5 76t-100 25q-58 0 -99 -24.5t-66 -75t-36.5 -128t-11.5 -184.5z" />-<glyph glyph-name="ntilde" unicode="ñ" horiz-adv-x="1366" d="M858 0v674q0 66 -8.5 117.5t-28 86.5t-51 53.5t-76.5 18.5q-51 0 -85 -26t-54.5 -69.5t-29.5 -101t-9 -120.5v-391q0 -43 10.5 -69t29.5 -40.5t46.5 -19t61.5 -4.5h6v-109h-629v109h4q35 0 64 4.5t50.5 19.5t33.5 43t12 74v606q0 43 -10.5 69t-30 40.5t-46.5 19t-61 4.5 h-6v109h430l27 -146h10q31 58 65.5 92t73.5 52t82.5 23t91.5 5q79 0 142 -23t106.5 -71t66.5 -122.5t23 -178.5v-475q0 -48 8.5 -76.5t25.5 -43.5t43 -20t61 -5h6v-109h-455zM842 1436q22 0 39.5 9t30 24t20 34.5t10.5 40.5h133q-3 -62 -23 -117t-53.5 -96.5t-79 -65.5 t-100.5 -24t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-23 0 -40.5 -9t-30 -24t-20 -34.5t-10.5 -40.5h-133q3 62 23.5 117t54 96.5t79.5 65.5t101 24t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="ograve" unicode="ò" horiz-adv-x="1255" d="M1159 553q0 -289 -135.5 -431t-398.5 -142q-123 0 -221 35.5t-166.5 106.5t-105 179t-36.5 252q0 289 135.5 430t399.5 141q123 0 220.5 -35t166 -106t105 -178.5t36.5 -251.5zM414 553q0 -109 11.5 -192t37 -139t66.5 -84.5t100 -28.5t99.5 28.5t66 84.5t36.5 139 t11 192q0 110 -11.5 192.5t-37 137.5t-66.5 82.5t-100 27.5t-100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5zM618 1241q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="oacute" unicode="ó" horiz-adv-x="1255" d="M1159 553q0 -289 -135.5 -431t-398.5 -142q-123 0 -221 35.5t-166.5 106.5t-105 179t-36.5 252q0 289 135.5 430t399.5 141q123 0 220.5 -35t166 -106t105 -178.5t36.5 -251.5zM414 553q0 -109 11.5 -192t37 -139t66.5 -84.5t100 -28.5t99.5 28.5t66 84.5t36.5 139 t11 192q0 110 -11.5 192.5t-37 137.5t-66.5 82.5t-100 27.5t-100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5zM504 1268l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="ocircumflex" unicode="ô" horiz-adv-x="1255" d="M1159 553q0 -289 -135.5 -431t-398.5 -142q-123 0 -221 35.5t-166.5 106.5t-105 179t-36.5 252q0 289 135.5 430t399.5 141q123 0 220.5 -35t166 -106t105 -178.5t36.5 -251.5zM414 553q0 -109 11.5 -192t37 -139t66.5 -84.5t100 -28.5t99.5 28.5t66 84.5t36.5 139 t11 192q0 110 -11.5 192.5t-37 137.5t-66.5 82.5t-100 27.5t-100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5zM262 1268l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50 l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="otilde" unicode="õ" horiz-adv-x="1255" d="M1159 553q0 -289 -135.5 -431t-398.5 -142q-123 0 -221 35.5t-166.5 106.5t-105 179t-36.5 252q0 289 135.5 430t399.5 141q123 0 220.5 -35t166 -106t105 -178.5t36.5 -251.5zM414 553q0 -109 11.5 -192t37 -139t66.5 -84.5t100 -28.5t99.5 28.5t66 84.5t36.5 139 t11 192q0 110 -11.5 192.5t-37 137.5t-66.5 82.5t-100 27.5t-100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5zM795 1436q22 0 39.5 9t30 24t20 34.5t10.5 40.5h133q-3 -62 -23 -117t-53.5 -96.5t-79 -65.5t-100.5 -24t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-23 0 -40.5 -9 t-30 -24t-20 -34.5t-10.5 -40.5h-133q3 62 23.5 117t54 96.5t79.5 65.5t101 24t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="odieresis" unicode="ö" horiz-adv-x="1255" d="M1159 553q0 -289 -135.5 -431t-398.5 -142q-123 0 -221 35.5t-166.5 106.5t-105 179t-36.5 252q0 289 135.5 430t399.5 141q123 0 220.5 -35t166 -106t105 -178.5t36.5 -251.5zM414 553q0 -109 11.5 -192t37 -139t66.5 -84.5t100 -28.5t99.5 28.5t66 84.5t36.5 139 t11 192q0 110 -11.5 192.5t-37 137.5t-66.5 82.5t-100 27.5t-100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5zM293 1409q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22 t-26.5 39.5t-10 58.5zM713 1409q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="divide" unicode="÷" d="M459 1120q0 35 8.5 59t24 38.5t36.5 21t45 6.5t45 -6.5t36.5 -21t24.5 -38.5t9 -59q0 -34 -9 -58t-24.5 -39t-36.5 -21.5t-45 -6.5q-49 0 -81.5 28t-32.5 97zM459 344q0 35 8.5 59t24 38.5t36.5 21t45 6.5t45 -6.5t36.5 -21t24.5 -38.5t9 -59q0 -34 -9 -58t-24.5 -39 t-36.5 -21.5t-45 -6.5q-49 0 -81.5 28t-32.5 97zM1012 659h-879v146h879v-146z" />-<glyph glyph-name="oslash" unicode="ø" horiz-adv-x="1255" d="M1159 553q0 -289 -135.5 -431t-398.5 -142q-138 0 -242 43l-66 -105h-145l102 168q-86 71 -132 187t-46 280q0 289 135.5 430t399.5 141q72 0 136 -12t118 -37l65 105h144l-105 -172q82 -72 126 -184t44 -271zM414 553q0 -63 3 -117.5t11 -99.5l352 571q-52 86 -153 86 q-59 0 -100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5zM842 553q0 56 -3 104.5t-10 92.5l-348 -566q51 -75 148 -75q59 0 99.5 28.5t66 84.5t36.5 139t11 192z" />-<glyph glyph-name="ugrave" unicode="ù" horiz-adv-x="1366" d="M907 0l-45 145h-10q-31 -53 -67 -85.5t-77 -50t-86.5 -23.5t-93.5 -6q-160 0 -245.5 99t-85.5 306v459q0 45 -8 73t-25 44t-43.5 22t-63.5 6h-4v109h455v-656q0 -66 7.5 -119t25.5 -90.5t48 -58t75 -20.5q49 0 84.5 21.5t58 62t33 98t10.5 129.5v393q0 45 -12 71 t-32 39.5t-47 17t-57 3.5h-6v109h465v-860q0 -45 10.5 -70.5t28.5 -38.5t43 -16.5t55 -3.5h17v-109h-408zM634 1241q-48 28 -106.5 69.5t-113 85.5t-98.5 84.5t-63 67.5v21h321q16 -34 41 -74.5l52.5 -81l55.5 -78.5l50 -67v-27h-139z" />-<glyph glyph-name="uacute" unicode="ú" horiz-adv-x="1366" d="M907 0l-45 145h-10q-31 -53 -67 -85.5t-77 -50t-86.5 -23.5t-93.5 -6q-160 0 -245.5 99t-85.5 306v459q0 45 -8 73t-25 44t-43.5 22t-63.5 6h-4v109h455v-656q0 -66 7.5 -119t25.5 -90.5t48 -58t75 -20.5q49 0 84.5 21.5t58 62t33 98t10.5 129.5v393q0 45 -12 71 t-32 39.5t-47 17t-57 3.5h-6v109h465v-860q0 -45 10.5 -70.5t28.5 -38.5t43 -16.5t55 -3.5h17v-109h-408zM527 1268l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="ucircumflex" unicode="û" horiz-adv-x="1366" d="M907 0l-45 145h-10q-31 -53 -67 -85.5t-77 -50t-86.5 -23.5t-93.5 -6q-160 0 -245.5 99t-85.5 306v459q0 45 -8 73t-25 44t-43.5 22t-63.5 6h-4v109h455v-656q0 -66 7.5 -119t25.5 -90.5t48 -58t75 -20.5q49 0 84.5 21.5t58 62t33 98t10.5 129.5v393q0 45 -12 71 t-32 39.5t-47 17t-57 3.5h-6v109h465v-860q0 -45 10.5 -70.5t28.5 -38.5t43 -16.5t55 -3.5h17v-109h-408zM295 1268l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50 l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="udieresis" unicode="ü" horiz-adv-x="1366" d="M907 0l-45 145h-10q-31 -53 -67 -85.5t-77 -50t-86.5 -23.5t-93.5 -6q-160 0 -245.5 99t-85.5 306v459q0 45 -8 73t-25 44t-43.5 22t-63.5 6h-4v109h455v-656q0 -66 7.5 -119t25.5 -90.5t48 -58t75 -20.5q49 0 84.5 21.5t58 62t33 98t10.5 129.5v393q0 45 -12 71 t-32 39.5t-47 17t-57 3.5h-6v109h465v-860q0 -45 10.5 -70.5t28.5 -38.5t43 -16.5t55 -3.5h17v-109h-408zM332 1409q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22 t-26.5 39.5t-10 58.5zM752 1409q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="yacute" unicode="ý" horiz-adv-x="1186" d="M1186 1098v-109q-31 0 -54.5 -7t-42.5 -24.5t-35 -46t-32 -71.5l-75 -208l-78.5 -212.5l-79 -212l-76.5 -207.5q-36 -99 -68 -174t-67.5 -130t-78.5 -91t-100 -57.5t-132.5 -30.5t-176.5 -9h-35v119q107 0 182 26t127 74t85.5 115t58.5 148l-369 901q-12 29 -27 46 t-32 26t-37 11.5t-43 2.5v121h584v-109q-60 0 -94.5 -15.5t-34.5 -60.5q0 -17 7 -40.5t13 -38.5l37.5 -93.5l38 -101l35.5 -97.5l30 -83q15 -39 25 -70.5t16.5 -57t10.5 -47t6 -42.5q2 21 8 46.5t13 49t14 42l10 26.5l135 401q4 10 7.5 23.5t6.5 27.5t4.5 27t1.5 22 q0 47 -39 64.5t-110 17.5v109h461zM463 1268l49.5 67l55.5 78.5t52.5 81t40.5 74.5h322v-21q-19 -27 -63 -67.5t-98.5 -84.5t-113 -85.5t-106.5 -69.5h-139v27z" />-<glyph glyph-name="thorn" unicode="þ" horiz-adv-x="1321" d="M51 -383q22 0 48 4.5t47.5 18.5t36 40t14.5 70v1555q0 47 -10.5 75t-29 43t-44 20t-54.5 5h-14v108h463v-376q0 -29 -4 -70.5t-9 -79.5q-5 -45 -12 -92h9q22 40 51.5 73t68 57t86.5 37t107 13q102 0 180.5 -33.5t131.5 -104t80.5 -178.5t27.5 -257q0 -148 -27 -255.5 t-79.5 -177.5t-129 -103.5t-176.5 -33.5q-117 0 -190 44.5t-117 119.5h-14l8 -92q3 -38 5.5 -81t2.5 -75v-141q0 -44 14.5 -70t36 -40t47 -18.5t47.5 -4.5h45v-109h-671v109h24zM717 127q103 0 147.5 103.5t44.5 312.5q0 204 -44.5 313t-145.5 109q-62 0 -102.5 -27.5 t-64.5 -81t-34 -132t-10 -179.5q0 -106 10 -184.5t34 -130.5t64 -77.5t101 -25.5z" />-<glyph glyph-name="ydieresis" unicode="ÿ" horiz-adv-x="1186" d="M1186 1098v-109q-31 0 -54.5 -7t-42.5 -24.5t-35 -46t-32 -71.5l-75 -208l-78.5 -212.5l-79 -212l-76.5 -207.5q-36 -99 -68 -174t-67.5 -130t-78.5 -91t-100 -57.5t-132.5 -30.5t-176.5 -9h-35v119q107 0 182 26t127 74t85.5 115t58.5 148l-369 901q-12 29 -27 46 t-32 26t-37 11.5t-43 2.5v121h584v-109q-60 0 -94.5 -15.5t-34.5 -60.5q0 -17 7 -40.5t13 -38.5l37.5 -93.5l38 -101l35.5 -97.5l30 -83q15 -39 25 -70.5t16.5 -57t10.5 -47t6 -42.5q2 21 8 46.5t13 49t14 42l10 26.5l135 401q4 10 7.5 23.5t6.5 27.5t4.5 27t1.5 22 q0 47 -39 64.5t-110 17.5v109h461zM266 1409q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM686 1409q0 35 10 59.5t27 39.5t39 21.5t47 6.5 q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="2087" d="M1323 125h410q31 0 53 11.5t37.5 32.5t25 49.5t15.5 62.5l16 96h141l-14 -377h-987q-45 -9 -103.5 -14.5t-109.5 -5.5q-175 0 -305.5 54t-216.5 153t-129 238.5t-43 309.5t43 308.5t129.5 236.5t217 151.5t306.5 53.5q53 0 112.5 -6t104.5 -17h918l8 -377h-144l-10 97 q-8 75 -38 115t-93 40h-344v-512h485v-123h-485v-577zM807 113q59 0 105.5 15t84.5 44v1118q-34 26 -82.5 44t-105.5 18q-96 0 -163 -41.5t-109 -121t-61 -194.5t-19 -262t19 -262t61 -194.5t108.5 -121.5t161.5 -42z" />-<glyph glyph-name="oe" unicode="œ" horiz-adv-x="1915" d="M414 553q0 -109 11.5 -192t37 -139t66.5 -84.5t100 -28.5q56 0 95.5 26t65 77t38 127.5t14.5 176.5v55q-1 211 -50.5 316.5t-164.5 105.5q-59 0 -100 -27.5t-66 -82.5t-36 -137.5t-11 -192.5zM1354 991q-85 0 -136.5 -85t-56.5 -249h355q0 160 -39 247t-123 87zM1376 -20 q-118 0 -211 40t-161 117q-67 -81 -162.5 -119t-216.5 -38q-123 0 -221 35.5t-166.5 106.5t-105 179t-36.5 252q0 289 135.5 430t399.5 141q114 0 206 -39.5t160 -117.5q63 78 152 117.5t201 39.5q111 0 200 -31.5t151 -93.5t95 -154t33 -214v-105h-670q0 -6 -1 -12t-1 -12 q5 -97 25.5 -166.5t55 -114.5t83.5 -66.5t111 -21.5q53 0 98 12.5t81.5 35t63.5 53t45 65.5q56 -30 56 -100q0 -44 -23.5 -83.5t-72.5 -69.5t-124.5 -48t-179.5 -18z" />-<glyph glyph-name="Ydieresis" unicode="Ÿ" horiz-adv-x="1419" d="M336 0v109h96q25 0 46.5 3t37.5 15.5t25.5 37.5t9.5 68v285l-379 727q-15 30 -28.5 51t-29.5 33.5t-36.5 18.5t-50.5 6h-27v108h686v-108h-35q-62 0 -92.5 -25t-30.5 -67q0 -26 9.5 -56.5t21.5 -56.5l152 -301q32 -65 52.5 -115t37.5 -98q21 54 48.5 117.5t61.5 132.5 l119 245q22 45 28.5 75.5t6.5 47.5q0 53 -33.5 77t-101.5 24h-47v108h536v-108h-39q-26 0 -44.5 -7t-35 -25t-34 -49t-41.5 -79l-348 -678v-280q0 -45 9 -70t24.5 -38t36 -16t44.5 -3h101v-109h-756zM401 1747q0 35 10 59.5t26.5 39.5t38.5 21.5t46 6.5t46 -6.5t39 -21.5 t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-39 -22t-46 -7t-46 7t-38.5 22t-26.5 39.5t-10 58.5zM821 1747q0 35 10 59.5t27 39.5t39 21.5t47 6.5q23 0 44.5 -6.5t38.5 -21.5t27.5 -39.5t10.5 -59.5q0 -34 -10.5 -58.5t-27.5 -39.5t-38.5 -22t-44.5 -7 q-25 0 -47 7t-39 22t-27 39.5t-10 58.5z" />-<glyph glyph-name="circumflex" unicode="ˆ" horiz-adv-x="1182" d="M227 1268l56.5 67l64.5 78.5t60.5 81t44.5 74.5h276q16 -34 44.5 -74.5t60.5 -81l64 -78.5l56 -67v-27h-141l-50 40l-60 48l-60.5 50l-52.5 46l-52.5 -46l-60 -50l-59 -48l-49.5 -40h-142v27z" />-<glyph glyph-name="tilde" unicode="˜" horiz-adv-x="1182" d="M762 1436q22 0 39.5 9t30 24t20 34.5t10.5 40.5h133q-3 -62 -23 -117t-53.5 -96.5t-79 -65.5t-100.5 -24t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-23 0 -40.5 -9t-30 -24t-20 -34.5t-10.5 -40.5h-133q3 62 23.5 117t54 96.5t79.5 65.5t101 24t99.5 -20t83 -44.5l72 -44.5 t65.5 -20z" />-<glyph glyph-name="endash" unicode="–" horiz-adv-x="1024" d="M1034 477h-1044v146h1044v-146z" />-<glyph glyph-name="emdash" unicode="—" horiz-adv-x="2048" d="M2058 477h-2068v146h2068v-146z" />-<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="573" d="M115 1061q0 65 20 126t63.5 113t113 93.5t169.5 68.5v-106q-45 -16 -78.5 -32t-56 -34.5t-34 -41t-11.5 -52.5q0 -20 11 -32t28 -23l36 -22.5t36 -29t28 -44.5t11 -68q0 -69 -42.5 -105t-105.5 -36q-87 0 -137.5 60t-50.5 165z" />-<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="573" d="M459 1237q0 -65 -20 -126t-64 -113t-113.5 -93.5t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 20 -11 32t-27.5 23t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165z" />-<glyph glyph-name="quotesinglbase" unicode="‚" horiz-adv-x="602" d="M459 86q0 -65 -20 -126t-64 -113t-113.5 -93.5t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 19 -11 31.5t-27.5 23.5t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165z" />-<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="1001" d="M543 1061q0 65 20 126t63.5 113t113 93.5t169.5 68.5v-106q-44 -16 -78 -32t-56.5 -34.5t-34 -41t-11.5 -52.5q0 -20 11 -32t28 -23l36 -22.5t36 -29t28 -44.5t11 -68q0 -69 -42.5 -105t-105.5 -36q-87 0 -137.5 60t-50.5 165zM115 1061q0 65 20 126t63.5 113t113 93.5 t169.5 68.5v-106q-45 -16 -78.5 -32t-56 -34.5t-34 -41t-11.5 -52.5q0 -20 11 -32t28 -23l36 -22.5t36 -29t28 -44.5t11 -68q0 -69 -42.5 -105t-105.5 -36q-87 0 -137.5 60t-50.5 165z" />-<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="1001" d="M459 1237q0 -65 -20 -126t-64 -113t-113.5 -93.5t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 20 -11 32t-27.5 23t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165zM887 1237q0 -65 -20 -126t-64 -113t-113.5 -93.5 t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 20 -11 32t-27.5 23t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165z" />-<glyph glyph-name="quotedblbase" unicode="„" horiz-adv-x="1030" d="M459 86q0 -65 -20 -126t-64 -113t-113.5 -93.5t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 19 -11 31.5t-27.5 23.5t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165zM887 86q0 -65 -20 -126t-64 -113t-113.5 -93.5 t-169.5 -68.5v106q45 16 78.5 32t56 34.5t34 41t11.5 52.5q0 19 -11 31.5t-27.5 23.5t-36 22.5t-36 29.5t-27.5 44.5t-11 67.5q0 69 42 105t105 36q87 0 138 -60t51 -165z" />-<glyph glyph-name="bullet" unicode="•" horiz-adv-x="819" d="M115 729q0 92 22 154.5t61.5 100t93.5 53.5t118 16q60 0 114 -16t94 -53.5t63.5 -100t23.5 -154.5q0 -91 -23.5 -153t-63.5 -100t-94 -54t-114 -16q-64 0 -118 16t-93.5 54t-61.5 100t-22 153z" />-<glyph glyph-name="ellipsis" unicode="…" horiz-adv-x="1868" d="M143 147q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77t-36.5 -50t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50t-13 77zM766 147q0 47 13 78.5t35.5 50.5t53.5 27t66 8q34 0 64.5 -8t53.5 -27 t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77t-36.5 -50t-53.5 -27.5t-64.5 -8.5q-35 0 -66 8.5t-53.5 27.5t-35.5 50t-13 77zM1389 147q0 47 13 78.5t35.5 50.5t53 27t65.5 8q34 0 64.5 -8t53.5 -27t36.5 -50.5t13.5 -78.5q0 -46 -13.5 -77t-36.5 -50t-53.5 -27.5t-64.5 -8.5 q-35 0 -65.5 8.5t-53 27.5t-35.5 50t-13 77z" />-<glyph glyph-name="guilsinglleft" unicode="‹" horiz-adv-x="723" d="M133 606l313 357h144l-207 -410l207 -410h-144l-313 357v106z" />-<glyph glyph-name="guilsinglright" unicode="›" horiz-adv-x="723" d="M590 500l-314 -357h-143l207 410l-207 410h143l314 -357v-106z" />-<glyph glyph-name="Euro" unicode="€" d="M737 -20q-105 0 -198 30.5t-167 97.5t-124.5 174t-71.5 261h-121v127h109v63v64h-109v127h119q18 159 68 265.5t123 171t164.5 91.5t193.5 27q91 0 162.5 -18t121.5 -50t76.5 -75t26.5 -93q0 -35 -16.5 -66.5t-49 -55.5t-79.5 -38t-109 -14q0 48 -7.5 98t-25.5 90.5 t-47.5 66.5t-73.5 26q-43 0 -81.5 -18t-69 -65.5t-51 -130t-29.5 -212.5h377v-127h-383v-68v-59h301v-127h-291q17 -206 90.5 -308t212.5 -102q49 0 91.5 12.5t77.5 35t61.5 53t44.5 65.5q21 -17 32 -41.5t11 -52.5q0 -39 -19 -79t-61.5 -72.5t-111 -53t-167.5 -20.5z" />-<glyph glyph-name="trademark" unicode="™" horiz-adv-x="1710" d="M1321 754v55q35 0 56 10t24 45v457l-232 -567h-71l-232 569v-451q0 -41 21 -52t61 -11v-55h-248v55h21q31 0 54.5 10t25.5 47v482q-1 19 -7.5 30.5t-17.5 17.5t-25.5 7.5t-29.5 1.5h-21v57h236l225 -567l232 567h231v-57h-22q-17 0 -31.5 -2t-25 -8t-16 -18.5t-5.5 -33.5 v-471q0 -21 5.5 -33t16 -19t25 -9t31.5 -2h22v-55h-303zM422 872q0 -21 6.5 -33t17 -19t25 -9t29.5 -2h32v-55h-348v55h35q15 0 29 2t24.5 8t16.5 17.5t6 29.5v531h-90q-22 -1 -37 -6.5t-24 -15.5t-14 -22.5t-7 -27.5l-8 -49h-60l6 186h598l7 -186h-60l-8 49q-4 29 -21 50 t-61 22h-94v-525z" />-</font>-</defs></svg>
− extra/fonts/DroidSerif-Bold.ttf
binary file changed (47256 → absent bytes)
− extra/fonts/DroidSerif-Bold.woff
binary file changed (30824 → absent bytes)
− extra/fonts/DroidSerif-BoldItalic.eot
binary file changed (44230 → absent bytes)
− extra/fonts/DroidSerif-BoldItalic.svg
@@ -1,223 +0,0 @@-<?xml version="1.0" standalone="no"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >-<svg xmlns="http://www.w3.org/2000/svg">-<defs>-<font id="DroidSerif-BoldItalic" horiz-adv-x="1145" >-<font-face font-family="Droid Serif" font-weight="700" font-style="italic" font-stretch="normal" units-per-em="2048" panose-1="2 2 8 0 6 5 0 9 2 0" ascent="1638" descent="-410" x-height="1098" cap-height="1462" bbox="-344 -492 2390 1907" underline-thickness="102" underline-position="-103" slope="-12" unicode-range="U+0020-U+2122"/>-<missing-glyph horiz-adv-x="532" />-<glyph glyph-name=".notdef" horiz-adv-x="532" />-<glyph glyph-name=".null" horiz-adv-x="0" />-<glyph glyph-name="nonmarkingreturn" horiz-adv-x="682" />-<glyph glyph-name="space" unicode=" " horiz-adv-x="532" />-<glyph glyph-bame="tab" unicode="	" horiz-adv-x="532" />-<glyph glyph-bame="uni00A0" unicode=" " horiz-adv-x="532" />-<glyph glyph-name="exclam" unicode="!" horiz-adv-x="809" d="M430 1462h356l-354 -995h-119zM502 168q0 -51 -15.5 -86.5t-41 -57t-57.5 -31t-64 -9.5q-75 0 -120.5 36t-45.5 111q0 42 12.5 76t35.5 58t56 37t74 13q35 0 65.5 -9t53 -27t35 -46t12.5 -65z" />-<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="1040" d="M807 1462h319l-213 -563h-135zM360 1462h320l-234 -563h-135z" />-<glyph glyph-name="numbersign" unicode="#" d="M1036 551l-14 -141h-256l-119 -410h-145l119 410h-213l-121 -410h-146l121 410h-205l15 141h231l111 371h-238l17 143h264l112 397h148l-115 -397h213l117 397h145l-116 -397h196l-16 -143h-223l-109 -371h227zM449 551h215l110 371h-215z" />-<glyph glyph-name="dollar" unicode="$" d="M1030 481q0 -95 -34.5 -169t-99 -126t-156 -80t-205.5 -30l-50 -238h-114l51 240q-187 15 -279 87t-92 187q0 97 59.5 141t168.5 44q0 -72 12 -127t34.5 -95t53.5 -66t70 -40l92 436q-73 39 -129 78.5t-94.5 86t-58 102t-19.5 126.5q0 85 33.5 152.5t94.5 114.5t146.5 73 t190.5 29l32 149h115l-35 -153q162 -13 243 -68t81 -139q0 -42 -12 -75t-39 -56t-71.5 -35t-109.5 -12q0 37 -7 75.5t-21 74t-36.5 64t-53.5 44.5l-86 -404l47 -24q141 -74 209.5 -162t68.5 -205zM768 389q0 28 -5 52.5t-19 47.5t-38.5 47t-62.5 50l-84 -393q48 1 86.5 15.5 t65.5 40.5t42 62t15 78zM504 1106q0 -59 24.5 -98t73.5 -74l76 356q-35 -5 -66.5 -17.5t-55.5 -35t-38 -55t-14 -76.5z" />-<glyph glyph-name="percent" unicode="%" horiz-adv-x="1835" d="M526 0h-159l1015 1462h154zM147 872q0 64 12 134t37.5 138t63.5 129.5t90.5 108t119 74t148.5 27.5q78 0 134 -23t92 -64t53.5 -97t17.5 -121q0 -59 -12.5 -127t-37.5 -135t-64 -129t-92.5 -109.5t-121.5 -76t-151 -28.5q-66 0 -119.5 19.5t-91 57.5t-58 93.5 t-20.5 128.5zM612 1376q-40 0 -73.5 -27.5t-60.5 -71.5t-47.5 -100t-34 -114t-20.5 -112.5t-7 -94.5q0 -81 20 -129.5t70 -48.5q40 0 73.5 27.5t60.5 71.5t47.5 100.5t34 114.5t20.5 112.5t7 95.5q0 82 -19.5 128t-70.5 48zM997 279q0 64 12 134t37.5 138t63.5 129 t90.5 107.5t119 74t148.5 27.5q78 0 134 -23t92 -64t53.5 -97t17.5 -121q0 -59 -12.5 -126.5t-37.5 -135t-64 -129t-92.5 -109t-121.5 -76t-151 -28.5q-66 0 -119.5 19.5t-91 57t-58 93.5t-20.5 129zM1462 782q-40 0 -73.5 -27.5t-60.5 -71.5t-47.5 -100t-34 -114 t-20.5 -112.5t-7 -94.5q0 -81 20 -129.5t70 -48.5q40 0 73.5 27.5t60.5 71.5t47.5 100.5t34 114.5t20.5 112.5t7 95.5q0 82 -19.5 128t-70.5 48z" />-<glyph glyph-name="ampersand" unicode="&" horiz-adv-x="1640" d="M1110 0l-102 141q-85 -72 -197.5 -116.5t-261.5 -44.5q-124 0 -214 29t-149 81t-87.5 122t-28.5 153q0 102 36 174.5t97 125.5t142 91t171 71q-46 79 -71 155t-25 148q0 88 31 154t89.5 110t144 66.5t194.5 22.5q94 0 162.5 -20.5t113.5 -56.5t66.5 -84.5t21.5 -104.5 q0 -71 -21 -124.5t-68.5 -98.5t-123.5 -85.5t-186 -85.5l252 -331q35 74 60 151t40 152l16 77h410l-23 -108h-18q-35 0 -68 -4t-64.5 -18.5t-59.5 -41.5t-52 -73l-65.5 -127.5t-79.5 -137.5l129 -169q31 -42 77.5 -63t112.5 -21h15l-23 -109h-393zM371 381q0 -57 16 -105.5 t47 -83.5t76 -55t102 -20q96 0 174.5 36.5t141.5 98.5l-334 463q-61 -34 -103.5 -70t-69 -76.5t-38.5 -87t-12 -100.5zM1010 1188q0 81 -36.5 126.5t-109.5 45.5q-36 0 -67 -14t-53.5 -41t-35 -67t-12.5 -91q0 -59 20 -112t60 -113q63 27 107.5 54t72.5 58t41 68.5t13 85.5z " />-<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="594" d="M340 1462h319l-213 -563h-135z" />-<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="819" d="M401 285q0 -63 9 -126t30 -120.5t55.5 -107t84.5 -85.5l-27 -131q-124 43 -212.5 111t-145 154.5t-83 188t-26.5 212.5q0 127 23.5 256t70.5 251t118 233t166.5 202t215 157.5t264.5 100.5l-20 -129q-77 -42 -137.5 -97t-107.5 -117t-82 -129t-60.5 -133t-43 -128 t-30.5 -115q-38 -154 -50 -264.5t-12 -183.5z" />-<glyph glyph-name="parenright" unicode=")" horiz-adv-x="819" d="M453 1014q0 63 -9 126t-30 120t-55.5 106.5t-84.5 85.5l27 131q124 -43 212.5 -111t145 -154.5t83 -188t26.5 -211.5q0 -127 -23.5 -256t-70.5 -251t-118 -233t-166.5 -202t-215 -158t-264.5 -103l20 131q77 42 137.5 97t107.5 117t82 129t60.5 133t43 128t30.5 115 q38 155 50 264.5t12 184.5z" />-<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="1266" d="M295 1323l133 184l252 -280l4 340l225 -47l-141 -308l344 146l47 -219l-328 -13l295 -147l-133 -178l-256 272l2 -340l-223 47l135 314l-342 -150l-49 217l330 17z" />-<glyph glyph-name="plus" unicode="+" d="M678 659v-366h-148v366h-364v146h364v366h148v-366h366v-146h-366z" />-<glyph glyph-name="comma" unicode="," horiz-adv-x="602" d="M428 127q0 -78 -28.5 -148t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5z" />-<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="635" d="M20 451l48 215h532l-47 -215h-533z" />-<glyph glyph-name="period" unicode="." horiz-adv-x="623" d="M434 168q0 -51 -15.5 -86.5t-41 -57t-57.5 -31t-64 -9.5q-74 0 -120 36t-46 111q0 42 12.5 76t36 58t56 37t73.5 13q35 0 65.5 -9t53 -27t35 -46t12.5 -65z" />-<glyph glyph-name="slash" unicode="/" horiz-adv-x="590" d="M-51 -248h-160l873 1804h159z" />-<glyph glyph-name="zero" unicode="0" d="M76 473q0 106 17.5 222t53 228.5t89.5 214.5t127.5 179t166.5 122.5t207 45.5q88 0 164 -27.5t132.5 -85t89 -146t32.5 -210.5q0 -103 -17 -220.5t-51.5 -233t-87.5 -221.5t-125.5 -187t-165.5 -129t-206 -48q-95 0 -173.5 32t-134.5 95t-87 155.5t-31 213.5zM356 385 q0 -137 43 -202.5t115 -65.5q60 0 111 47.5t92 126.5t72.5 180t52.5 208.5t32 212.5t11 191q0 135 -41.5 200t-116.5 65q-58 0 -108 -47t-91 -125t-73 -179t-54 -208t-33.5 -212t-11.5 -192z" />-<glyph glyph-name="one" unicode="1" d="M969 1470l-260 -1222l-8 -36t-5 -36q0 -22 11.5 -35.5t32.5 -20.5t49 -9t61 -2h100l-22 -109h-846l22 109h121q73 0 118 29.5t60 103.5l158 745q13 62 25 113t22 89q11 44 21 79h-8l-88.5 -89.5t-75.5 -67t-67.5 -42t-65.5 -14.5q-44 0 -71.5 39.5t-27.5 111.5 q35 9 72 21t79 30t90.5 43.5t106.5 63.5l166 106h230z" />-<glyph glyph-name="two" unicode="2" d="M-29 0l43 211l478 403q104 88 171 161t106 137.5t54 125t15 125.5q0 42 -9.5 77.5t-28 61t-45.5 40t-61 14.5q-51 0 -90.5 -27t-67.5 -73.5t-44.5 -109.5t-20.5 -136q-51 0 -94 10.5t-74.5 32t-49 55t-17.5 78.5q0 61 31.5 115t92 94.5t150 64t205.5 23.5q105 0 186 -20 t136 -56.5t83.5 -89.5t28.5 -119q0 -68 -28 -133.5t-83.5 -134.5t-138.5 -144.5t-192 -164.5l-492 -396h477q49 0 83.5 14.5t58.5 38t40.5 53.5t30.5 62l15 37h120l-100 -430h-969z" />-<glyph glyph-name="three" unicode="3" d="M457 125q51 0 99 20t85 60.5t59.5 100.5t22.5 140q0 118 -76 182t-213 64h-88l21 127h65q86 0 159 26t126.5 74t83.5 115t30 148q0 38 -8.5 70.5t-25.5 56t-43.5 36.5t-63.5 13q-56 0 -95.5 -25t-66.5 -67t-44 -97.5t-27 -115.5q-49 0 -91.5 6.5t-73.5 21.5t-49 40 t-18 63q0 63 39.5 117.5t107.5 95t159.5 63.5t195.5 23q94 0 171.5 -19.5t133 -57t85.5 -92t30 -124.5q0 -72 -25.5 -141t-77 -126.5t-129 -100t-180.5 -60.5q71 -8 128 -31t96.5 -61t61 -90.5t21.5 -118.5q0 -91 -26 -162t-71 -124t-105 -90.5t-128 -60.5t-140.5 -33.5 t-141.5 -10.5q-120 0 -202.5 22.5t-133.5 58t-73.5 79.5t-22.5 87q0 81 59.5 127.5t165.5 46.5q0 -60 14 -110.5t43 -87t73 -57.5t104 -21z" />-<glyph glyph-name="four" unicode="4" d="M674 874q8 41 19 89.5l23.5 100.5t26.5 104t29 100q-22 -35 -51 -77l-59.5 -84.5l-59.5 -80.5l-51 -65l-363 -445h410zM264 0l21 109h59q30 0 61 3.5t58 18t48 44t32 81.5l26 125h-569l29 127l784 954h287l-203 -946h213l-29 -135h-213l-26 -127q-3 -12 -5.5 -33 t-2.5 -31q0 -26 9.5 -42t27 -24.5t42.5 -11.5t56 -3h37l-23 -109h-719z" />-<glyph glyph-name="five" unicode="5" d="M434 123q67 0 121.5 23t93 69t59.5 115.5t21 161.5q0 66 -19 115t-52 82t-78.5 49t-98.5 16q-37 0 -67 -4t-55 -10.5t-47 -14.5l-42 -16l-86 43l209 710h774l-59 -372h-125q2 26 4 55.5t2 42.5q0 23 -21 37t-79 14h-412l-121 -383q38 11 88 22t125 11q106 0 192 -25 t146.5 -73.5t93.5 -120t33 -164.5q0 -112 -43 -208.5t-123.5 -167t-196.5 -110.5t-263 -40q-107 0 -181 19t-120 51.5t-66.5 76t-20.5 92.5q0 34 11.5 63.5t35 52t59.5 35.5t85 13q1 -44 10.5 -90t34 -84t67.5 -62t111 -24z" />-<glyph glyph-name="six" unicode="6" d="M829 1362q-132 0 -231 -140.5t-162 -426.5q23 18 53 36t67.5 32.5t82 24t96.5 9.5q89 0 154.5 -29t108 -78.5t63 -115.5t20.5 -139q0 -108 -33.5 -208t-102 -177t-172 -123.5t-243.5 -46.5q-88 0 -165.5 30.5t-135.5 92.5t-91.5 154.5t-33.5 217.5q0 128 23.5 252t69 236 t111.5 207t150.5 165t187 109t220.5 39q84 0 147.5 -17t106.5 -46.5t64.5 -67.5t21.5 -80q0 -82 -67 -128t-189 -46q0 50 -3.5 97.5t-16 84.5t-36.5 59.5t-65 22.5zM641 772q-33 0 -65.5 -9.5t-62.5 -24.5t-56 -34t-47 -38q-25 -149 -25 -256q0 -155 47 -226t127 -71 q52 0 95 31t74 85.5t48 128.5t17 160q0 124 -38.5 189t-113.5 65z" />-<glyph glyph-name="seven" unicode="7" d="M213 0l809 1239h-526q-56 0 -92 -26.5t-50 -77.5l-28 -103h-125l84 430h977l-23 -121l-852 -1341h-174z" />-<glyph glyph-name="eight" unicode="8" d="M506 -20q-108 0 -196 26t-151 73t-97.5 111.5t-34.5 141.5q0 86 31 148t85 109t127.5 83t159.5 69q-44 33 -80 73.5t-62 86.5t-40.5 97t-14.5 106q0 77 28.5 146t91 120.5t161 82t238.5 30.5q97 0 173 -22.5t128.5 -62.5t80 -95t27.5 -119q0 -78 -25 -137.5t-70.5 -106.5 t-109 -84.5t-139.5 -71.5q53 -34 98.5 -72.5t78.5 -84t52 -98.5t19 -115q0 -112 -41 -194t-115.5 -135t-177 -79t-225.5 -26zM522 98q54 0 102 16t84 48.5t57 80.5t21 113q0 50 -15 92t-44 79.5t-72.5 71t-101.5 65.5q-117 -48 -183.5 -131t-66.5 -209q0 -106 58 -166 t161 -60zM903 1169q0 42 -9.5 77.5t-29.5 61.5t-50.5 41t-72.5 15q-48 0 -89 -17.5t-71 -50t-47.5 -78.5t-17.5 -104q0 -160 174 -266q59 31 100 66.5t66 75.5t36 85t11 94z" />-<glyph glyph-name="nine" unicode="9" d="M391 109q75 0 135.5 39t111 114t92.5 185.5t81 254.5q-26 -27 -58 -52t-70 -44.5t-83 -31t-98 -11.5q-82 0 -146 25.5t-107.5 70.5t-66 107.5t-22.5 136.5q0 128 46.5 235t125.5 183.5t183.5 119t221.5 42.5q92 0 166.5 -27t127 -78.5t80.5 -126.5t28 -172q0 -24 -2 -60 t-6.5 -78t-12 -88.5t-18.5 -92.5q-22 -99 -55.5 -195t-80 -182.5t-106 -160.5t-133.5 -127.5t-162.5 -84t-193.5 -30.5q-82 0 -141 17t-97 45.5t-56 66.5t-18 81q0 69 42.5 105.5t117.5 36.5q1 -39 11 -79t31 -72t53.5 -52t78.5 -20zM606 711q40 1 74.5 15t64 36.5 t53.5 50.5t42 57q6 25 11.5 55t9.5 60t6.5 58t2.5 49q0 67 -11 115.5t-31.5 79t-48 45t-60.5 14.5q-58 0 -106.5 -38t-83.5 -99.5t-54.5 -139t-19.5 -156.5q0 -100 41 -151t110 -51z" />-<glyph glyph-name="colon" unicode=":" horiz-adv-x="733" d="M434 168q0 -51 -15.5 -86.5t-41 -57t-57.5 -31t-64 -9.5q-74 0 -120 36t-46 111q0 42 12.5 76t36 58t56 37t73.5 13q35 0 65.5 -9t53 -27t35 -46t12.5 -65zM614 961q0 -52 -15.5 -87.5t-41 -57t-57.5 -31t-64 -9.5q-74 0 -120 36t-46 112q0 41 12.5 75t36 58t56.5 37.5 t74 13.5q35 0 65.5 -9t52.5 -27t34.5 -46t12.5 -65z" />-<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="733" d="M428 127q0 -78 -28.5 -148t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5zM614 961q0 -52 -15.5 -87.5 t-41 -57t-57.5 -31t-64 -9.5q-74 0 -120 36t-46 112q0 41 12.5 75t36 58t56.5 37.5t74 13.5q35 0 65.5 -9t52.5 -27t34.5 -46t12.5 -65z" />-<glyph glyph-name="less" unicode="<" d="M166 690v84l878 479v-161l-659 -361l659 -356v-162z" />-<glyph glyph-name="equal" unicode="=" d="M1053 604v-143h-887v143h887zM1053 1001v-143h-887v143h887z" />-<glyph glyph-name="greater" unicode=">" d="M166 213v162l659 356l-659 361v161l878 -479v-84z" />-<glyph glyph-name="question" unicode="?" horiz-adv-x="1096" d="M1122 1143q0 -89 -39 -162.5t-107 -134t-161.5 -109.5t-202.5 -88l-73 -182h-131l-5 254q91 33 164.5 72.5t126 90t81 115t28.5 148.5q0 51 -11.5 90t-31 66t-47 41t-58.5 14q-48 0 -82.5 -25t-57.5 -66.5t-36 -95.5t-20 -112q-252 0 -252 158q0 55 33 103.5t94.5 84.5 t149 57t196.5 21q102 0 184 -20t139 -62t88 -106t31 -152zM602 168q0 -51 -15.5 -86.5t-41 -57t-57.5 -31t-64 -9.5q-74 0 -120 36t-46 111q0 42 12.5 76t36 58t56 37t73.5 13q35 0 65.5 -9t53 -27t35 -46t12.5 -65z" />-<glyph glyph-name="at" unicode="@" horiz-adv-x="1886" d="M1790 803q0 -153 -37 -273t-97 -202.5t-135.5 -126t-152.5 -43.5q-91 0 -154.5 44.5t-97.5 147.5h-12q-21 -40 -48 -75t-61 -61t-77 -41t-97 -15q-65 0 -123 21t-102 64t-70 109t-26 156q0 55 13 119t41 127.5t72 123t105 105t140.5 73t179.5 27.5q71 0 121.5 -18 t82.5 -43l86 43h50l-86 -512q-3 -12 -5.5 -31t-4.5 -39t-3.5 -38.5t-1.5 -30.5q0 -42 9 -69t23 -42.5t32 -21t35 -5.5q40 0 82 34t76 99.5t55.5 162.5t21.5 223q0 140 -42.5 245.5t-118.5 176t-180.5 106t-227.5 35.5q-97 0 -191.5 -27t-180 -79t-157.5 -127.5t-125 -172 t-82.5 -213.5t-29.5 -252q0 -181 54 -309t146.5 -209t216 -118t261.5 -37q83 0 162 15t150 39t132 55t109 63l49 -78q-54 -41 -123 -77t-149 -63t-171 -43t-188 -16q-117 0 -225 21.5t-202.5 65.5t-172.5 109.5t-133.5 153.5t-86 198t-30.5 243q0 137 33.5 262t95 231.5 t149.5 193t197 148t236.5 94.5t269.5 33q177 0 312 -51t226 -139.5t137 -209t46 -259.5zM752 487q0 -102 36 -156.5t95 -54.5q43 0 74.5 21t53.5 55.5t36 77.5t22 88l82 418q-6 14 -17.5 24.5t-26.5 18t-32 11t-33 3.5q-52 0 -93.5 -26t-73.5 -68.5t-55.5 -97t-38.5 -110.5 t-22 -109.5t-7 -94.5z" />-<glyph glyph-name="A" unicode="A" horiz-adv-x="1542" d="M438 481l-100 -184q-20 -37 -29.5 -65t-9.5 -50q0 -38 28 -55.5t87 -17.5h41l-23 -109h-532l22 109h43q28 0 49.5 6.5t41.5 24.5t41.5 49t49.5 79l695 1194h280l172 -1206q5 -32 13.5 -59t22.5 -46.5t35.5 -30.5t53.5 -11h37l-22 -109h-676l22 109h47q66 0 105 20.5 t39 65.5q0 17 -1 33.5t-3 31.5l-31 221h-498zM885 950l-9.5 84.5t-8 76.5t-6 72t-3.5 72q-15 -37 -30 -68.5l-32 -64l-37.5 -69l-47.5 -84.5l-203 -363h414z" />-<glyph glyph-name="B" unicode="B" horiz-adv-x="1376" d="M-25 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 986q5 20 9 39.5t4 27.5q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h635q238 0 358.5 -77.5t120.5 -229.5q0 -84 -25.5 -148t-70.5 -110.5t-106 -76.5t-132 -46l-2 -8q55 -10 101 -34t79 -61.5t51.5 -88.5 t18.5 -115q0 -112 -38 -199t-112 -146.5t-184.5 -90.5t-255.5 -31h-745zM489 125h142q87 0 147.5 23t98.5 68t55.5 111.5t17.5 153.5q0 112 -51 166.5t-158 54.5h-129zM639 829h115q145 0 209.5 75.5t64.5 215.5q0 109 -49 163t-143 54h-91z" />-<glyph glyph-name="C" unicode="C" horiz-adv-x="1368" d="M823 152q71 0 128 16t102 42.5t79 59.5t60 68q12 -9 23.5 -28t11.5 -42q0 -51 -31 -102.5t-91.5 -93t-149.5 -67t-205 -25.5q-147 0 -262.5 36.5t-195 107t-121.5 173t-42 233.5q0 123 29 242t84 226t134.5 197t180 156t220.5 103t257 37q102 0 178.5 -17.5t127 -49 t75.5 -77t25 -100.5q0 -45 -22 -79t-60.5 -57.5t-91.5 -35.5t-115 -12q0 43 -6 95t-24.5 97t-52.5 75t-91 30q-81 0 -149.5 -37t-125 -100.5t-100 -147.5t-73 -177.5t-45 -191t-15.5 -188.5q0 -175 89 -270.5t265 -95.5z" />-<glyph glyph-name="D" unicode="D" horiz-adv-x="1573" d="M-27 109h29q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h655q147 0 262.5 -36t195 -106.5t121.5 -174.5t42 -240q0 -122 -25.5 -236.5t-75 -215t-122.5 -184t-169 -143.5t-214.5 -93 t-257.5 -33h-721zM584 127q144 0 257 58.5t191 164t119 251.5t41 321q0 107 -25 185.5t-71.5 129.5t-113 75.5t-148.5 24.5h-86l-256 -1210h92z" />-<glyph glyph-name="E" unicode="E" horiz-adv-x="1296" d="M-25 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h1112l-72 -381h-145q1 7 2.5 25l3 37.5t3 36t1.5 20.5q0 28 -8 53t-25 44t-44.5 29.5t-67.5 10.5h-272l-109 -512h465l-27 -123h-465 l-123 -577h324q48 0 86 13.5t66 36.5t47.5 53.5t31.5 64.5l33 88h146l-95 -381h-1175z" />-<glyph glyph-name="F" unicode="F" horiz-adv-x="1272" d="M514 242q-5 -23 -7.5 -39.5t-2.5 -24.5q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h27l-23 -109h-704l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h1126l-71 -381h-146q2 17 4 36t3.5 36.5 l2.5 30t1 16.5q0 29 -8 54t-26 43.5t-47.5 29t-72.5 10.5h-278l-119 -559h485l-24 -121h-486z" />-<glyph glyph-name="G" unicode="G" horiz-adv-x="1630" d="M1544 590h-2q-34 0 -65.5 -4.5t-57 -17.5t-44.5 -38t-27 -65l-78 -391q-62 -24 -121.5 -41.5t-121 -29.5t-126.5 -17.5t-137 -5.5q-158 0 -276.5 38t-198.5 109t-120 172.5t-40 228.5q0 132 31 254.5t89 228.5t142 193t189 149t230.5 96t266.5 34q118 0 205 -21t145 -55 t86.5 -78t28.5 -90q0 -40 -23.5 -74.5t-63.5 -60t-94.5 -40.5t-115.5 -15q0 64 -13.5 119.5t-42 96.5t-72 64t-103.5 23q-78 0 -149 -32t-132 -89t-110.5 -136t-84.5 -173t-54 -200.5t-19 -217.5q0 -86 17 -156.5t54.5 -121.5t96 -79t141.5 -28q47 0 96 8t86 20l68 304 q12 54 12 69q0 22 -11 36t-30.5 21.5t-46.5 10t-59 2.5h-27l23 108h682z" />-<glyph glyph-name="H" unicode="H" horiz-adv-x="1677" d="M807 0l22 109h27q33 0 64 4t57 17.5t44.5 37.5t27.5 65l98 467h-535l-100 -475q-3 -11 -5.5 -25t-2.5 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h27l-23 -109h-704l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5 t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-84 -404h535l86 398q5 21 7.5 37t2.5 24q0 22 -11.5 36t-31.5 21.5t-47.5 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-33 0 -64 -4.5t-57 -17.5t-44.5 -38t-27.5 -65 l-211 -1004q-3 -11 -5.5 -25t-2.5 -22q0 -22 11 -35.5t30.5 -21t46.5 -10t59 -2.5h27l-23 -109h-706z" />-<glyph glyph-name="I" unicode="I" horiz-adv-x="821" d="M-47 0l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-211 -1004q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21 t47.5 -10t59.5 -2.5h27l-23 -109h-704z" />-<glyph glyph-name="J" unicode="J" horiz-adv-x="821" d="M463 -6q-26 -125 -87 -216.5t-144 -151.5t-183 -89t-205 -29q-55 0 -92.5 6t-75.5 17l29 113q13 -5 29.5 -8.5t34.5 -6t36 -3.5t33 -1q53 0 98.5 19t83 62.5t67.5 114t52 173.5l264 1243q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707 l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65z" />-<glyph glyph-name="K" unicode="K" horiz-adv-x="1518" d="M1036 1110q42 37 68.5 66.5t42 53t21.5 41.5t6 32q0 26 -20 39.5t-71 13.5l23 106h553l-23 -106q-41 0 -79 -10t-77 -31t-81.5 -53t-91.5 -76l-332 -293l239 -576q25 -57 45.5 -97t42 -64.5t47 -35.5t60.5 -11h6l-20 -109h-107q-102 0 -169.5 12.5t-114 44.5t-79 86.5 t-65.5 139.5l-151 391l-121 -86l-76 -363q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h27l-23 -109h-704l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26 q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-102 -486z" />-<glyph glyph-name="L" unicode="L" horiz-adv-x="1339" d="M834 125q56 0 97 14t71.5 41.5t53.5 69.5t42 98l37 109h131l-113 -457h-1200l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65 l-231 -1104h342z" />-<glyph glyph-name="M" unicode="M" horiz-adv-x="1950" d="M2097 1462l-22 -108h-27q-33 0 -64 -4.5t-57 -17.5t-44.5 -38t-27.5 -65l-210 -1004q-4 -11 -6.5 -25t-2.5 -22q0 -22 11 -35.5t30.5 -21t47 -10t59.5 -2.5h26l-22 -109h-698l22 109h27q33 0 64 4t56.5 17.5t44.5 37.5t27 65l217 1027l-678 -1260h-141l-166 1260 l-217 -1018q-5 -23 -7.5 -39.5t-2.5 -24.5q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h7l-23 -109h-516l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h571l138 -995l536 995h592z" />-<glyph glyph-name="N" unicode="N" horiz-adv-x="1614" d="M1094 0l-555 1159l-193 -917q-5 -23 -7.5 -39.5t-2.5 -24.5q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h7l-23 -109h-516l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h455l499 -1050 l172 809q11 47 11 63q0 22 -11.5 36t-31.5 21.5t-47.5 10t-59.5 2.5h-6l23 108h516l-23 -108h-26q-32 0 -62.5 -4.5t-55.5 -17.5t-43.5 -37t-27.5 -64l-260 -1231h-188z" />-<glyph glyph-name="O" unicode="O" horiz-adv-x="1622" d="M129 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q113 0 215.5 -33t180.5 -102t124 -175t46 -253q0 -94 -23.5 -201t-71 -212t-119 -201t-168 -169.5t-218 -117.5t-267.5 -44q-121 0 -225.5 36.5t-181 108.5t-120.5 178t-44 245zM463 496 q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22q85 0 154.5 41t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5q0 100 -21 172t-57.5 119t-87.5 69.5t-111 22.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5z" />-<glyph glyph-name="P" unicode="P" horiz-adv-x="1358" d="M610 678h86q93 0 157.5 28t104.5 78.5t58 120t18 152.5q0 77 -17.5 131t-48.5 88t-74.5 49.5t-94.5 15.5h-45zM512 225q-3 -11 -5.5 -25t-2.5 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h68l-23 -109h-745l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983 q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h586q120 0 217 -25.5t164.5 -76t104 -125t36.5 -172.5q0 -52 -10 -110t-35.5 -114t-70.5 -106.5t-114.5 -89t-167 -61.5t-229.5 -23h-155z" />-<glyph glyph-name="Q" unicode="Q" horiz-adv-x="1612" d="M127 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q113 0 215.5 -33t180.5 -102t124 -175t46 -253q0 -84 -18.5 -177t-55 -186.5t-92.5 -182t-130.5 -163t-168.5 -130.5t-207 -83q3 -113 21 -185.5t49 -114t72.5 -57.5t92.5 -16h33l-26 -119h-148 q-92 0 -171 27.5t-137.5 86t-92.5 150.5t-37 222q-93 19 -170.5 63.5t-133.5 114t-87 163t-31 210.5zM461 496q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22q85 0 154.5 41t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5q0 100 -21 172t-57.5 119t-87.5 69.5 t-111 22.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5zM700 -23z" />-<glyph glyph-name="R" unicode="R" horiz-adv-x="1448" d="M621 754h127q65 0 121.5 19t98 59.5t65.5 105t24 156.5q0 69 -12 116t-37 76.5t-63 42t-89 12.5h-104zM918 1462q245 0 366 -85t121 -257q0 -104 -33.5 -177t-86 -122.5t-117.5 -78.5t-128 -44l142 -381q21 -58 41 -98t42.5 -64.5t49 -35t61.5 -10.5h8l-22 -109h-21 q-107 0 -185.5 9t-134.5 34.5t-93 71t-60 118.5l-129 402h-141l-80 -375q-8 -37 -11 -55.5t-3 -26.5q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h68l-23 -109h-745l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10 t-59.5 2.5h-26l22 108h658z" />-<glyph glyph-name="S" unicode="S" horiz-adv-x="1200" d="M535 -20q-127 0 -222 23t-158 63t-94.5 94.5t-31.5 118.5q0 48 19.5 84t55 60t84 36t107.5 12q0 -94 20 -163t56 -114.5t86 -67.5t110 -22q58 0 103 16.5t76.5 45t48 67t16.5 82.5q0 43 -10.5 79t-38.5 70t-77 69t-126 77q-80 44 -140.5 90.5t-101 100.5t-61 118.5 t-20.5 145.5q0 92 37 169t106 132.5t167 86t220 30.5q114 0 199 -18t141.5 -49t84.5 -73t28 -90q0 -83 -63 -130.5t-206 -47.5q0 46 -9 96t-32 91.5t-62 68.5t-99 27q-41 0 -81.5 -13t-72.5 -39t-52 -65.5t-20 -93.5t17 -92t51 -70.5t85 -63t120 -67.5q155 -84 229 -185.5 t74 -232.5q0 -109 -39.5 -194t-113 -143t-177.5 -88.5t-233 -30.5z" />-<glyph glyph-name="T" unicode="T" horiz-adv-x="1337" d="M213 0l23 109h26q32 0 62.5 4t55.5 17t43.5 37t27.5 64l231 1106h-164q-48 0 -81.5 -12t-58 -35.5t-41.5 -57.5t-32 -79l-29 -88h-137l94 397h1274l-71 -397h-138q1 7 3.5 31.5l5.5 52.5l5.5 51.5t2.5 28.5q0 54 -32.5 81t-111.5 27h-163l-236 -1112q-2 -11 -5 -25 t-3 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h27l-22 -109h-705z" />-<glyph glyph-name="U" unicode="U" horiz-adv-x="1530" d="M772 125q93 0 157 27t107 74.5t69 113t42 143.5l158 740q3 17 5.5 35t2.5 26q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h539l-23 -108h-26q-33 0 -64 -4.5t-57 -17.5t-44.5 -38t-27.5 -65l-164 -778q-24 -115 -71.5 -203t-121 -147.5t-173.5 -90t-230 -30.5 q-120 0 -212 23.5t-155 69t-95.5 111.5t-32.5 150q0 16 2 40t5 49.5t7 50t8 42.5l150 698q12 55 12 70q0 22 -11 36t-30.5 21.5t-46.5 10t-59 2.5h-27l23 108h708l-22 -108h-27q-34 0 -65.5 -4.5t-57.5 -17t-44.5 -36.5t-27.5 -63l-155 -721l-8.5 -40t-8 -45.5t-6 -47.5 t-2.5 -45q0 -103 64 -156t188 -53z" />-<glyph glyph-name="V" unicode="V" horiz-adv-x="1430" d="M659 1272q0 -17 1.5 -36.5t3.5 -33.5l65 -540q4 -36 7.5 -83.5t5 -96t2.5 -92t1 -71.5l25.5 59l26 60l23.5 54t20 40l368 662q20 35 28.5 61t8.5 48q0 30 -30 40.5t-89 10.5h-47l21 108h534l-22 -108h-49q-30 0 -51.5 -5t-40.5 -19.5t-38 -41.5t-44 -71l-682 -1217h-205 l-172 1255q-5 31 -16.5 50.5t-28 30.5t-38 14.5t-46.5 3.5h-27l23 108h675l-22 -108h-47q-66 0 -105 -16.5t-39 -65.5z" />-<glyph glyph-name="W" unicode="W" horiz-adv-x="2185" d="M2367 1354h-49q-30 0 -53 -6t-42.5 -22.5t-39 -46t-41.5 -75.5l-573 -1204h-234l-141 977l-498 -977h-254l-110 1255q-3 31 -14 50.5t-28.5 30.5t-39.5 14.5t-47 3.5h-27l23 108h669l-22 -108h-47q-66 0 -105 -16.5t-39 -65.5q0 -17 1 -39t3 -51l39 -510q3 -27 6 -71.5 t5.5 -93.5t4 -96.5t1.5 -80.5q21 60 49 120.5t59 120.5l457 877h150l116 -782q14 -97 24.5 -185.5t10.5 -154.5l29 79l37.5 95.5l43.5 102.5l46 102l227 489q14 29 22.5 58t8.5 51q0 30 -27 40.5t-86 10.5h-47l20 108h535z" />-<glyph glyph-name="X" unicode="X" horiz-adv-x="1499" d="M1610 1354h-19q-30 0 -55 -7t-51.5 -24t-56 -45t-68.5 -70l-385 -405l252 -586q28 -63 65.5 -85.5t75.5 -22.5h27l-23 -109h-676l23 109h31q61 0 88.5 18.5t27.5 52.5q0 29 -10 64.5t-29 77.5l-125 282l-286 -297q-37 -38 -59.5 -73t-22.5 -64q0 -15 5 -26t17.5 -19 t34 -12t55.5 -4h7l-23 -109h-516l23 109h20q31 0 57.5 7.5t54 24.5t59 45t71.5 70l452 467l-229 526q-15 34 -30.5 55t-34.5 32t-42.5 14.5t-52.5 3.5h-18l22 108h678l-22 -108h-48q-51 0 -73.5 -15t-22.5 -43q0 -20 9.5 -49.5t27.5 -72.5l109 -254l241 258q28 29 50 63 t22 62q0 26 -25 38.5t-73 12.5h-6l22 108h477z" />-<glyph glyph-name="Y" unicode="Y" horiz-adv-x="1419" d="M227 0l23 109h55q32 0 62 4.5t55 18t43 37.5t27 64l59 285l-221 727q-9 30 -18.5 51t-22.5 33.5t-32.5 18.5t-49.5 6h-27l23 108h665l-22 -108h-92q-47 0 -66.5 -16t-19.5 -44q0 -18 6 -52t18 -81l74 -289l15 -64t14.5 -68t11 -66.5t6.5 -57.5q19 41 58 104t92 138 l202 289q25 35 43.5 76t18.5 75q0 28 -28.5 42t-96.5 14h-43l24 108h537l-23 -108h-38q-23 0 -42.5 -6t-39.5 -21.5t-42.5 -41t-50.5 -64.5l-507 -705l-62 -291q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h50l-23 -109h-756z" />-<glyph glyph-name="Z" unicode="Z" horiz-adv-x="1364" d="M1423 1358l-1011 -1233h422q46 0 87 12t75 38t61 68.5t45 104.5l22 74h148l-98 -422h-1178l18 102l1010 1235h-356q-93 0 -149.5 -42t-82.5 -136l-35 -119h-147l100 422h1090z" />-<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="848" d="M43 -262l387 1818h567l-22 -108h-88q-34 0 -65.5 -5t-58.5 -20.5t-47 -44.5t-30 -78l-276 -1306q-3 -16 -5 -28t-2 -23q0 -32 11 -51t30.5 -29t45.5 -13.5t55 -3.5h88l-23 -108h-567z" />-<glyph glyph-name="backslash" unicode="\" horiz-adv-x="590" d="M221 1556h144l110 -1804h-143z" />-<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="848" d="M844 1556l-387 -1818h-566l23 108h88q34 0 65.5 5t57.5 20.5t46 45t30 77.5l276 1306q6 31 6 52q0 31 -11 50t-30 29.5t-45 13.5t-55 3h-88l22 108h568z" />-<glyph glyph-name="asciicircum" unicode="^" d="M569 1462h88l435 -925h-160l-320 702l-315 -702h-160z" />-<glyph glyph-name="underscore" unicode="_" horiz-adv-x="940" d="M772 -291h-958l26 121h959z" />-<glyph glyph-name="grave" unicode="`" horiz-adv-x="1182" d="M831 1241q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="a" unicode="a" horiz-adv-x="1362" d="M969 -20q-91 0 -146 41.5t-55 121.5q0 32 3 62.5t11 70.5h-14q-38 -71 -75.5 -126.5t-83.5 -93t-102.5 -57t-131.5 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q40 0 81.5 -6.5t79.5 -16.5 t71.5 -22.5t56.5 -25.5l108 49h109l-135 -639q-4 -17 -10 -45t-11.5 -59.5t-9.5 -61t-4 -49.5q0 -51 20 -76t52 -25q29 0 55.5 12.5t58.5 30.5l45 -82q-26 -20 -59 -41.5t-73.5 -39.5t-88 -29.5t-102.5 -11.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q45 0 93 39 t90 102.5t75.5 143.5t50.5 162l72 340q-20 29 -55.5 43t-75.5 14q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126z" />-<glyph glyph-name="b" unicode="b" horiz-adv-x="1276" d="M315 1274l6 27t5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-34 12t-50 3h-47l19 108h497l-82 -389q-4 -19 -12.5 -48l-19 -63t-23 -69.5l-23.5 -67.5l-20 -58l-14 -40h10q37 75 77 130.5t87 92.5t102 55.5t123 18.5q65 0 120 -24t94.5 -70.5t62 -116t22.5 -159.5 q0 -83 -20 -172t-59 -174.5t-95.5 -162t-130 -134t-162.5 -91.5t-192 -34q-42 0 -81 6t-72.5 16t-61 23t-46.5 28l-116 -59h-115zM883 733q0 61 -8.5 103t-23.5 68t-35 38t-42 12q-38 0 -73 -22.5t-66.5 -58.5t-58 -80.5t-47 -89t-34.5 -84t-20 -64.5l-84 -387 q22 -25 56 -41t77 -16q60 0 110 31.5t90 83t69.5 117.5t49.5 135t30 135.5t10 119.5z" />-<glyph glyph-name="c" unicode="c" horiz-adv-x="1081" d="M621 135q54 0 97.5 14.5t78.5 38.5t62 54t48 61q13 -12 22 -35.5t9 -54.5q0 -40 -23.5 -81.5t-73 -75t-125.5 -55t-181 -21.5q-93 0 -175.5 26t-144 79t-97.5 132t-36 186q0 76 19 158.5t57 162t94.5 151t131.5 125.5t168 86t204 32q85 0 146.5 -17.5t101 -47t58.5 -69 t19 -83.5q0 -32 -13.5 -62.5t-43.5 -55t-77.5 -39.5t-115.5 -15q0 54 -9.5 102.5t-28.5 85t-46.5 57.5t-64.5 21q-44 0 -82.5 -29.5t-70.5 -78t-56.5 -111t-42 -129t-26.5 -131t-9 -117.5q0 -125 57 -194.5t169 -69.5z" />-<glyph glyph-name="d" unicode="d" horiz-adv-x="1362" d="M393 352q0 -58 8.5 -98t23 -64.5t35 -35.5t44.5 -11q45 0 92.5 39t89.5 102t75.5 143t51.5 163l72 340q-22 28 -60 42.5t-75 14.5q-58 0 -107 -31.5t-88.5 -83t-70 -118t-50.5 -137t-30.5 -140t-10.5 -125.5zM1092 440l-8.5 -42.5t-10.5 -57.5t-8.5 -59t-3.5 -48 q0 -48 22 -70t50 -22q26 0 57.5 14t56.5 29l45 -80q-27 -22 -61 -44t-74.5 -40t-87.5 -29t-100 -11q-45 0 -82 10.5t-63.5 30.5t-41 50.5t-14.5 71.5q0 19 1 34t2.5 29.5t4 31t6.5 38.5h-12q-38 -79 -80 -135t-89.5 -92t-102 -52.5t-117.5 -16.5q-79 0 -135.5 30t-93 81 t-53.5 119t-17 144q0 80 18.5 167.5t55 172.5t90 162t123.5 135t155.5 92.5t186.5 34.5q60 0 112 -13t92 -36q3 13 6 30.5t6.5 35t7 33l5.5 24.5l18 82l6 27t5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-34 12t-50 3h-47l19 108h493z" />-<glyph glyph-name="e" unicode="e" horiz-adv-x="1096" d="M618 135q50 0 95 14.5t83.5 38t69 53t52.5 60.5q12 -15 19 -38.5t7 -49.5q0 -37 -24 -78t-73.5 -75.5t-126 -57t-181.5 -22.5q-94 0 -177 26t-145.5 78.5t-98.5 132t-36 186.5q0 76 20 159t59.5 162.5t98 151t135.5 125.5t172.5 85.5t208.5 31.5q147 0 228 -63.5 t81 -177.5q0 -83 -46 -159t-127 -133.5t-193 -91.5t-244 -34h-37t-39 2q-3 -20 -3.5 -40.5t-0.5 -37.5q0 -119 55.5 -183.5t167.5 -64.5zM690 995q-50 0 -95 -37.5t-81 -97.5t-62 -134.5t-38 -147.5h18q76 0 141.5 20t114 57.5t76 89.5t27.5 117q0 63 -26.5 98t-74.5 35z " />-<glyph glyph-name="f" unicode="f" horiz-adv-x="827" d="M870 958h-260l-194 -915q-23 -109 -59.5 -191t-82 -141.5t-98.5 -98.5t-109 -62t-114 -32.5t-113 -9.5q-15 0 -33 1.5t-35 4t-32 5.5t-25 6l25 119q17 -5 44 -10t50 -5q50 0 88.5 17t69 57.5t55 108.5t45.5 170l207 976h-186l20 97l197 43l16 76q24 101 64 176.5t99 126 t138.5 75.5t183.5 25q79 0 139.5 -14t101 -38t61 -56.5t20.5 -69.5q0 -68 -60 -106t-175 -38q0 39 -4.5 75.5t-15.5 64.5t-29 44.5t-46 16.5q-65 0 -99.5 -56t-55.5 -171l-27 -131h258z" />-<glyph glyph-name="g" unicode="g" horiz-adv-x="1188" d="M182 674q0 71 31.5 149.5t95 144t159.5 108t226 42.5q68 0 127.5 -15.5t104.5 -49.5q23 29 49 54.5t55 44t62 29.5t71 11q63 0 92 -30.5t29 -78.5q0 -25 -6.5 -51t-21.5 -47t-40.5 -34t-62.5 -13q0 42 -18.5 65t-53.5 23q-28 0 -51 -10t-43 -27q22 -29 36.5 -73t14.5 -91 q0 -45 -13 -94.5t-39 -98t-66 -93t-95 -78.5t-125 -54t-155 -20q-9 0 -23.5 0.5l-29.5 1t-29 1.5t-23 3q-48 -21 -80 -48.5t-32 -59.5q0 -17 8.5 -28t23 -17.5t34.5 -10.5t44 -6l230 -22q150 -14 233.5 -81.5t83.5 -197.5q0 -93 -42.5 -169.5t-124 -130.5t-200 -84 t-270.5 -30q-125 0 -213.5 18.5t-144.5 52.5t-82.5 82.5t-26.5 107.5q0 54 27.5 98t73.5 76.5t105 54.5t122 33q-20 10 -39 27.5t-33.5 40t-23.5 48t-9 52.5q0 32 13 60t40 55t69 54.5t100 59.5q-68 32 -106 95t-38 151zM721 -174q0 58 -44.5 89t-150.5 40l-182 16 q-45 -6 -84.5 -23t-69.5 -42t-47.5 -56.5t-17.5 -66.5q0 -32 11.5 -59.5t40 -48t78 -32.5t124.5 -12q90 0 154.5 16t106 43t61.5 62.5t20 73.5zM551 512q36 0 66 17t54 45t42 63.5t29.5 73.5t17.5 74.5t6 66.5q0 72 -28.5 105.5t-82.5 33.5q-53 0 -93 -35t-67 -87 t-41 -110.5t-14 -105.5q0 -75 29 -108t82 -33z" />-<glyph glyph-name="h" unicode="h" horiz-adv-x="1343" d="M754 190q0 44 7.5 105t24.5 139l35 162q5 20 11.5 49t12 60.5t9.5 63t4 56.5q0 19 -3.5 40t-12.5 38t-26 28t-44 11q-35 0 -69.5 -23.5t-66.5 -62t-60.5 -88t-52 -101.5t-40.5 -102t-26 -90l-107 -475h-307l270 1274l6 27t5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-34 12 t-50 3h-43l19 108h495l-96 -450l-17.5 -70l-18.5 -74q-11 -41 -21 -83h12q39 61 80.5 106t89.5 74.5t104.5 44t124.5 14.5q65 0 110 -19t72.5 -51.5t39.5 -75t12 -89.5q0 -26 -4 -55.5t-9.5 -59.5t-12 -60t-11.5 -57l-47 -219q-13 -56 -21 -104.5t-8 -91.5q0 -45 19 -69 t53 -24q32 0 58.5 12t62.5 35l49 -69q-25 -26 -56 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-117 0 -180 55.5t-63 154.5z" />-<glyph glyph-name="i" unicode="i" horiz-adv-x="725" d="M621 1098l-142 -666q-12 -56 -20 -104.5t-8 -91.5q0 -45 18.5 -69t52.5 -24q32 0 59 12t62 35l49 -69q-24 -26 -55 -51.5t-70 -45.5t-85.5 -32t-102.5 -12q-118 0 -181 55.5t-63 154.5q0 44 8 105t25 139l80 381q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45t-19 26 t-33.5 12t-49.5 3h-37l18 109h486zM479 1282q-34 0 -63 7.5t-50.5 23.5t-34 40t-12.5 56q0 45 15.5 76.5t41.5 52t61 30t73 9.5q33 0 62.5 -7t52 -23t36 -40.5t13.5 -58.5q0 -42 -16.5 -73.5t-44 -52t-62.5 -30.5t-72 -10z" />-<glyph glyph-name="j" unicode="j" horiz-adv-x="692" d="M479 1282q-34 0 -63 7.5t-50.5 23.5t-34 40t-12.5 56q0 45 15.5 76.5t41.5 52t61 30t73 9.5q33 0 62.5 -7t52 -23t36 -40.5t13.5 -58.5q0 -42 -16.5 -73.5t-44 -52t-62.5 -30.5t-72 -10zM621 1098l-238 -1114q-28 -137 -75 -228.5t-108.5 -146.5t-133.5 -78t-150 -23 q-65 0 -112 7t-91 18l25 107q15 -5 42.5 -10t49.5 -5q48 0 83.5 17.5t63.5 59.5t50.5 111t44.5 171l176 831q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-33.5 12t-49.5 3h-37l18 109h486z" />-<glyph glyph-name="k" unicode="k" horiz-adv-x="1223" d="M438 408l-88 -408h-307l270 1274l6 27t5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-34 12t-50 3h-43l19 108h495l-108 -499l-31.5 -144.5t-27 -120.5l-28 -114l-32.5 -125l319 289q25 22 40 39t23.5 29.5t11.5 22t3 17.5q0 22 -25 33.5t-71 11.5l20 103h516l-20 -103 q-71 0 -149 -41.5t-177 -132.5l-163 -151l153 -334q33 -72 64 -116t58 -69t50 -33.5t41 -8.5h8l-22 -109h-105q-75 0 -134 10.5t-104 34t-77 60t-53 88.5l-121 286z" />-<glyph glyph-name="l" unicode="l" horiz-adv-x="725" d="M489 143q32 0 59 12t62 35l49 -69q-24 -26 -55 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-118 0 -181 55.5t-63 154.5q0 88 33 244l178 840l6 27t5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-34 12t-50 3h-43l19 108h495l-244 -1124q-12 -56 -20 -104.5t-8 -91.5 q0 -45 18.5 -69t52.5 -24z" />-<glyph glyph-name="m" unicode="m" horiz-adv-x="1985" d="M1638 -14q-117 0 -180 56t-63 155q0 43 7.5 104t24.5 139l35 162q5 20 11.5 49t12 60.5t9.5 63t4 56.5q0 19 -3.5 40t-12.5 38t-25 28t-41 11q-33 0 -65.5 -23t-63.5 -60.5t-58.5 -86t-50 -99.5t-38.5 -100.5t-23 -89.5l-16 -86q-4 -21 -9.5 -57.5l-11.5 -78.5l-12 -86 t-10.5 -81.5t-7 -64.5t-2.5 -35h-318q0 12 3.5 42t9.5 70.5t14 87.5l16 94t16 89.5t15 73.5l31 143q4 19 9.5 48l11 60.5t9.5 63.5t4 57q0 19 -2 39t-8.5 36.5t-20 27t-36.5 10.5q-34 0 -67.5 -21t-64.5 -56t-59 -80t-50.5 -92.5t-39 -94t-24.5 -84.5l-115 -514h-307 l172 815q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-33.5 12t-49.5 3h-37l18 109h475l-39 -209h15q40 62 82.5 105.5t89.5 71t99.5 40t113.5 12.5q64 0 107 -18t69 -49t37.5 -71t11.5 -85v-16h12q38 61 78.5 107t87.5 76.5t102 46t121 15.5q63 0 106 -19 t70 -51.5t38.5 -75t11.5 -89.5q0 -26 -4 -55.5t-9.5 -59.5t-12 -60t-11.5 -57l-47 -219q-13 -55 -21 -104t-8 -92q0 -45 19 -68.5t53 -23.5q32 0 58.5 12t62.5 35l49 -70q-25 -26 -56 -51.5t-69.5 -45.5t-85.5 -32t-103 -12z" />-<glyph glyph-name="n" unicode="n" horiz-adv-x="1376" d="M786 190q0 88 33 244l33 162l10 49l12 60.5t10.5 63t4.5 56.5q0 19 -3.5 40t-13 38t-26 28t-43.5 11q-35 0 -69.5 -23.5t-66.5 -62t-61 -88t-52.5 -101.5t-40.5 -102t-26 -90l-104 -475h-307l172 815q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-33.5 12 t-49.5 3h-37l18 109h455l-23 -219h13q39 61 80.5 106t89.5 74.5t104.5 44t124.5 14.5q65 0 109.5 -19t72 -51.5t39.5 -75t12 -89.5q0 -26 -3.5 -55.5t-9 -59.5t-12 -60t-11.5 -57l-46 -219q-12 -56 -20 -104.5t-8 -91.5q0 -45 18.5 -69t53.5 -24q32 0 58.5 12t61.5 35 l49 -69q-24 -26 -55 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-118 0 -181 55.5t-63 154.5z" />-<glyph glyph-name="o" unicode="o" horiz-adv-x="1266" d="M82 410q0 77 18 159t54.5 161t91.5 149.5t129.5 123.5t169 84t209.5 31q88 0 166 -24.5t136 -76.5t92 -133.5t34 -195.5q0 -74 -17 -155t-52.5 -159.5t-90 -150t-128.5 -125.5t-168 -86t-210 -32q-96 0 -176 26.5t-137 80t-89 134.5t-32 189zM553 127q55 0 99.5 31.5 t80 83t61.5 117.5t42.5 136t25 137.5t8.5 121.5q0 121 -41.5 174t-113.5 53q-52 0 -96 -30t-79.5 -80t-62.5 -114.5t-45.5 -133.5t-27.5 -137.5t-9 -125.5q0 -125 42 -179t116 -54z" />-<glyph glyph-name="p" unicode="p" horiz-adv-x="1276" d="M885 733q0 42 -5.5 81.5t-18 70.5t-34 50t-53.5 19q-34 0 -67.5 -19.5t-65 -52.5t-59 -76t-50 -89.5t-39 -93.5t-24.5 -88l-78 -367q9 -9 24 -19.5t34 -18.5t41.5 -13.5t46.5 -5.5q55 0 102.5 30t86 80t68.5 114.5t50 133.5t30.5 137.5t10.5 126.5zM-61 -492l278 1307 q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-33.5 12t-49.5 3h-37l18 109h441l-53 -273h14q35 64 72 118t82 93t102 60.5t133 21.5q67 0 122.5 -24t94.5 -71t60.5 -116t21.5 -159q0 -74 -17.5 -159.5t-52.5 -171t-87.5 -164.5t-123.5 -139.5t-159.5 -97 t-194.5 -36.5q-62 0 -115.5 12.5t-93.5 34.5q-1 -16 -4 -33q-2 -14 -5 -31.5t-7 -34.5l-29 -137q-3 -13 -5.5 -27t-4.5 -26.5t-3 -21.5t-1 -13q0 -28 6 -45t19 -26t33.5 -12t49.5 -3h78l-18 -109h-520z" />-<glyph glyph-name="q" unicode="q" horiz-adv-x="1292" d="M393 360q0 -59 8.5 -100t23 -67t35 -38t44.5 -12q31 0 62.5 18.5t62.5 51t59.5 76.5t52 94t42 103.5t28.5 105.5l74 338q-14 23 -49 40t-84 17q-61 0 -111 -32t-90 -84.5t-69.5 -119.5t-49 -136.5t-29.5 -136t-10 -118.5zM705 -82q3 16 8 39.5l11 51.5l12.5 58.5 l12.5 60.5l33 148h-12q-35 -67 -72 -121.5t-82.5 -93.5t-104.5 -60t-138 -21q-65 0 -118.5 24t-91.5 71t-59.5 117t-21.5 162q0 80 19.5 167.5t56.5 172.5t91.5 162t124.5 135t154.5 92.5t182.5 34.5q45 0 88 -6t82 -15.5t72 -21.5t59 -24l121 67h102l-281 -1327 q-6 -26 -10 -55t-4 -49q0 -37 25 -53.5t84 -16.5h77l-18 -109h-485z" />-<glyph glyph-name="r" unicode="r" horiz-adv-x="1128" d="M262 918q0 38 -25 54.5t-83 16.5h-37l18 109h453l-43 -281h10q35 74 70.5 130t78 94t96.5 57.5t126 19.5q109 0 162 -41t53 -119q0 -106 -62 -158t-180 -52q0 46 -4.5 83.5t-16 64t-31 40.5t-48.5 14t-61 -23.5t-64 -64.5t-62.5 -97.5t-58.5 -123t-51 -139.5t-39 -148 l-78 -354h-309l174 823q3 17 7.5 45t4.5 50z" />-<glyph glyph-name="s" unicode="s" horiz-adv-x="1053" d="M457 102q42 0 78 10.5t62 30t41 48t15 65.5q0 35 -13.5 62t-42 50.5t-72 46.5t-103.5 52q-60 28 -108.5 60t-82.5 71t-52.5 87t-18.5 108q0 75 32 135t92 102.5t145.5 65t193.5 22.5q103 0 174.5 -16t116 -42.5t64 -61.5t19.5 -72q0 -82 -63 -119t-172 -37q0 41 -8 82.5 t-27 75.5t-49 55t-74 21q-40 0 -71.5 -11.5t-54 -31t-34.5 -45.5t-12 -56q0 -34 13.5 -59t42 -47t72.5 -43.5l104 -48.5q66 -30 114 -63.5t79.5 -73t47 -86t15.5 -103.5q0 -83 -31.5 -149t-94.5 -112t-156 -70.5t-216 -24.5q-88 0 -159.5 15t-122 44t-78 71t-27.5 95 q0 48 19 81t49.5 53.5t70 30t80.5 9.5q0 -55 11 -105t35 -88.5t62.5 -61t94.5 -22.5z" />-<glyph glyph-name="t" unicode="t" horiz-adv-x="854" d="M553 147q48 0 87 16t73 38l47 -78q-34 -29 -71.5 -55t-81.5 -45.5t-94.5 -31t-109.5 -11.5q-56 0 -104.5 14.5t-84.5 44t-56.5 74.5t-20.5 106q0 18 1.5 40t4.5 45t7 45.5t8 41.5l123 567h-158l22 105q44 0 96 15t106.5 49t109 89t102.5 134h119l-53 -252h247l-28 -140 h-250l-123 -561q-11 -45 -15.5 -81.5t-4.5 -65.5q0 -51 28 -77t74 -26z" />-<glyph glyph-name="u" unicode="u" horiz-adv-x="1378" d="M793 176q0 9 1 21t2.5 25t3 24.5t3.5 19.5h-17q-45 -64 -88.5 -116t-92.5 -89.5t-106 -58t-130 -20.5q-66 0 -111 18.5t-72 49.5t-39 72.5t-12 86.5q0 51 12 112l23 113l74 361q8 42 13 76t5 51q0 41 -25 54t-83 13h-37l18 109h492l-135 -613q-6 -24 -12 -54t-11 -60 t-8.5 -57t-3.5 -46q0 -45 19 -71.5t69 -26.5q45 0 92.5 40.5t91 105t77.5 144t52 156.5l109 482h305l-139 -666q-13 -56 -21 -104.5t-8 -91.5q0 -45 18.5 -69t53.5 -24q32 0 58.5 12t61.5 35l50 -69q-25 -26 -56 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-68 0 -113.5 15.5 t-73.5 42t-40 62t-12 76.5z" />-<glyph glyph-name="v" unicode="v" horiz-adv-x="1200" d="M195 881q-6 32 -17.5 53t-29 33t-41.5 17t-54 5h-20l24 109h402l94 -606q15 -104 21.5 -185.5t11.5 -132.5h6q70 72 134 155t113 166.5t78 162t29 141.5q0 69 -39 101t-96 32q0 84 46 134t124 50q32 0 60 -10.5t49 -33.5t33 -59t12 -87q0 -80 -26 -167t-68.5 -174.5 t-97.5 -172t-113.5 -160t-115.5 -140t-104 -110.5l-270 -20z" />-<glyph glyph-name="w" unicode="w" horiz-adv-x="1792" d="M1745 944q0 -106 -45 -224t-120 -240.5t-172 -244t-200 -233.5l-250 -22q0 63 -1.5 136.5l-3 151.5l-3 156t-3.5 149t-4 131t-3 103q-80 -190 -183 -394.5t-239 -406.5l-268 -18l-21 852q-1 47 -12 76t-29.5 45.5t-44 22t-55.5 5.5h-12l33 109h395q6 -102 11 -203.5 t8 -190t5 -159t2 -111.5q0 -78 -1 -125.5t-1 -52.5h15q51 81 102 177t101 202t98 218.5l92 225.5l250 8q6 -51 11.5 -125t10.5 -158t9.5 -172t8 -166.5t5.5 -142t2 -98.5h14q90 111 149 200.5t93.5 163.5t48.5 134t14 111q0 30 -9 54t-23 41.5t-32.5 28t-37.5 15.5 q3 39 16.5 66.5t34 45t46.5 25.5t55 8q68 0 105.5 -45t37.5 -129z" />-<glyph glyph-name="x" unicode="x" horiz-adv-x="1237" d="M-41 0l21 109h26q29 0 52.5 4.5t47 18.5t51.5 40t66 68l258 284l-141 340q-16 39 -31.5 63t-33.5 38t-40 19t-51 5h-24l20 109h385l144 -389l284 389h250l-20 -109h-37q-30 0 -53.5 -6t-47 -22.5t-50 -45t-62.5 -73.5l-211 -244l149 -344q19 -43 35.5 -71t34.5 -44.5 t40 -23t52 -6.5h27l-21 -109h-397l-154 414l-319 -414h-250z" />-<glyph glyph-name="y" unicode="y" horiz-adv-x="1200" d="M160 881q-17 61 -49.5 84.5t-92.5 23.5h-20l25 109h401l135 -531q10 -40 21 -93.5l21 -107t17 -100t9 -71.5h6q61 82 115 165t94.5 161.5t64 149.5t23.5 130q0 69 -33.5 105t-93.5 36q0 40 12.5 72.5t34.5 55.5t52 35.5t65 12.5q83 0 125.5 -46t42.5 -128q0 -80 -27 -169 t-77 -189t-121.5 -212t-161.5 -237l-139 -191t-127.5 -157t-127 -122.5t-137 -88t-158 -53t-190.5 -17.5q-59 0 -114.5 10t-98.5 27l31 115q24 -8 67.5 -17.5t106.5 -9.5q94 0 172 25t144.5 67.5t125 99.5t113.5 122z" />-<glyph glyph-name="z" unicode="z" horiz-adv-x="1143" d="M715 139q35 0 62 16.5t47.5 43t36.5 59.5t30 66l20 47h119l-88 -371h-942l23 104l684 854h-261q-41 0 -69 -13.5t-49.5 -37.5t-39 -58t-36.5 -75l-4 -8h-125l90 332h879l-23 -107l-686 -852h332z" />-<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="905" d="M487 -256q-146 0 -219 59t-73 164q0 9 0.5 20t2.5 27t6 39.5t11 57.5l61 286q7 29 7 56q0 40 -15.5 66t-43 41.5t-64.5 21.5t-80 8l26 125q51 1 96.5 9.5t82 29.5t62.5 57.5t38 93.5l74 352q16 77 46 133.5t78.5 93t119.5 54.5t169 18h195l-23 -108h-79q-44 0 -74.5 -13 t-52 -38t-35.5 -62.5t-25 -85.5l-76 -348q-20 -93 -84.5 -152.5t-189.5 -86.5l-4 -17q93 -25 136.5 -70.5t43.5 -113.5q0 -27 -6 -58l-76 -350q-6 -26 -8 -49t-2 -43q0 -53 26 -80.5t89 -27.5h80l-25 -109h-195z" />-<glyph glyph-name="bar" unicode="|" d="M678 -492h-148v2048h148v-2048z" />-<glyph glyph-name="braceright" unicode="}" horiz-adv-x="905" d="M469 1559q147 0 220 -59t73 -165q0 -9 -0.5 -20t-3 -27t-6.5 -39t-11 -57l-61 -287q-6 -30 -6 -55q0 -41 15.5 -67t43 -41t64.5 -21.5t80 -7.5l-27 -125q-51 -2 -96 -10t-81.5 -29t-63 -57.5t-38.5 -94.5l-73 -352q-16 -77 -46 -133.5t-79 -93t-120 -54.5t-169 -18h-195 l23 109h80q44 0 74.5 13t52 38t35 62t24.5 85l76 348q20 93 84.5 152.5t189.5 87.5l4 16q-92 25 -136 71t-44 114q0 27 6 57l76 350q6 26 8 49t2 43q0 53 -25.5 81t-88.5 28h-80l24 109h195z" />-<glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="1149" d="M528 664q-37 16 -64.5 26.5t-50 17t-43 9t-42.5 2.5q-29 0 -58.5 -9.5t-59 -25.5t-57.5 -38.5t-53 -47.5v158q100 108 248 108q29 0 54 -2.5t52.5 -9t61 -19t80.5 -32.5l64.5 -27t51 -17.5t43.5 -9t42 -2.5q28 0 58 9.5t59 26t57 38.5t53 47v-157q-50 -54 -111 -81.5 t-137 -27.5q-29 0 -54 2.5t-52.5 9.5t-61 19.5t-80.5 32.5z" />-<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="809" d="M381 -367h-356l354 996h119zM309 928q0 51 15.5 86.5t41 57t57.5 31t64 9.5q75 0 120.5 -36t45.5 -111q0 -42 -12.5 -76t-35.5 -58t-56 -37.5t-74 -13.5q-35 0 -65.5 9t-53 27t-35 46t-12.5 66z" />-<glyph glyph-name="cent" unicode="¢" d="M692 324q59 0 106 14.5t84.5 38.5t66.5 54t52 61q13 -13 23 -36.5t10 -54.5q0 -38 -23 -78t-71 -73.5t-122 -56t-175 -25.5l-35 -168h-127l37 174q-81 12 -151 43.5t-121 83.5t-80 124.5t-29 166.5q0 71 17.5 148.5t52.5 153.5t87.5 145.5t121.5 125.5t154.5 93.5 t187.5 48.5l33 155h127l-33 -151q77 -5 132.5 -24t91 -48t52.5 -66t17 -77q0 -32 -14 -62.5t-44 -55t-77.5 -39.5t-114.5 -15q0 74 -19 135t-57 96l-176 -831h16zM451 588q0 -84 26.5 -142.5t79.5 -89.5l174 830q-44 -10 -81.5 -44.5t-68.5 -84.5t-55 -111t-41 -124 t-25.5 -124t-8.5 -110z" />-<glyph glyph-name="sterling" unicode="£" d="M600 711q1 -8 2 -20t2 -26t1.5 -29t0.5 -28q0 -63 -20 -114.5t-58 -95t-93 -81t-126 -71.5l2 -8q54 20 98 28t83 8q46 0 95 -11.5t95.5 -25l88 -25t73.5 -11.5q35 0 62 4.5t50.5 14t46.5 24.5t50 37l65 -103q-24 -25 -64 -59t-88.5 -65t-102.5 -52.5t-105 -21.5 t-99.5 14.5t-99 32.5t-105.5 32.5t-118 14.5q-41 0 -75.5 -3.5t-66 -11t-63 -19.5t-65.5 -28l-33 -14l-45 108l69 44q51 30 102.5 71.5t93 94.5t67.5 118.5t26 143.5q0 34 -3.5 66.5t-8.5 64.5h-236l29 125h192q-6 38 -13 91t-7 103q0 108 38 193t107.5 143t168 88.5 t218.5 30.5q87 0 154 -17.5t112.5 -48t69 -71t23.5 -86.5q0 -88 -66 -134.5t-190 -46.5q0 140 -40 209.5t-110 69.5q-103 0 -158 -86t-55 -244q0 -60 7 -109.5l12 -84.5h364l-28 -125z" />-<glyph glyph-name="currency" unicode="¤" d="M227 729q0 59 17 113.5t49 99.5l-123 123l102 102l123 -123q45 29 96.5 45.5t110.5 16.5q57 0 109.5 -16.5t97.5 -47.5l127 127l102 -104l-125 -127q31 -45 48.5 -97.5t17.5 -111.5t-16 -110.5t-45 -96.5l120 -121l-102 -102l-121 121q-46 -31 -100 -48.5t-113 -17.5 t-112.5 16.5t-98.5 47.5l-119 -119l-104 104l119 119q-60 92 -60 207zM367 729q0 -49 18.5 -92t50 -75.5t74.5 -51t92 -18.5q51 0 94 18.5t74.5 51t49.5 75.5t18 92q0 51 -18 94.5t-49.5 76t-74.5 51t-94 18.5q-49 0 -92 -18.5t-74.5 -51t-50 -76t-18.5 -94.5z" />-<glyph glyph-name="yen" unicode="¥" horiz-adv-x="1104" d="M762 698h262l-25 -120h-286l-27 -119h287l-25 -121h-286l-23 -98q-5 -22 -7.5 -38t-2.5 -24q0 -22 11 -35.5t30.5 -21t46.5 -10t59 -2.5h49l-22 -109h-733l22 109h55q32 0 62 4.5t55 18t43 37.5t27 64l22 105h-286l24 121h287l27 119h-287l24 120h271l-125 547 q-7 31 -14 51.5t-18.5 33.5t-30 18.5t-48.5 5.5h-26l22 108h559l-22 -108h-58q-46 0 -66 -16t-20 -44q0 -18 8 -55.5t17 -85.5l37 -195q12 -65 21.5 -125t9.5 -102q11 28 32 67t47 83l158 266q22 37 42 77t20 74q0 28 -23 42t-57 14h-41l24 108h434l-22 -108h-6 q-47 0 -91.5 -39t-97.5 -121z" />-<glyph glyph-name="brokenbar" unicode="¦" d="M676 737h-148v819h148v-819zM676 -492h-148v820h148v-820z" />-<glyph glyph-name="section" unicode="§" horiz-adv-x="1114" d="M444 -236q-93 0 -167 18t-125.5 50.5t-79 78t-27.5 99.5q0 52 19 85.5t48 52t63 25.5t63 7q0 -65 15.5 -120t45 -95t72 -63t96.5 -23q53 0 95.5 17t72 46t45.5 69t16 85q0 41 -11 73.5t-41 64t-82 65.5t-134 78q-78 41 -129 82t-81 83t-42 87t-12 94q0 50 16.5 91.5 t43.5 76t61.5 62t70.5 48.5q-18 29 -33.5 76t-15.5 109q0 88 35.5 157t96 116t140.5 72t169 25q93 0 160.5 -17.5t112 -47.5t66 -70.5t21.5 -85.5q0 -44 -14.5 -73.5t-41.5 -47t-64.5 -25t-82.5 -7.5q0 55 -11.5 103t-34 83t-55.5 55.5t-75 20.5q-37 0 -73.5 -12t-66 -37 t-47.5 -63.5t-18 -90.5q0 -45 12.5 -78.5t41.5 -63t76.5 -58.5t117.5 -66q75 -40 127 -77.5t84.5 -76t46.5 -79t14 -87.5q0 -48 -15.5 -91t-42.5 -81.5t-62.5 -71t-75.5 -57.5q18 -29 32.5 -72.5t14.5 -97.5q0 -87 -32 -163.5t-91 -133.5t-142.5 -90t-185.5 -33zM639 784 q-66 31 -120.5 62.5t-100.5 68.5q-32 -24 -53 -53.5t-21 -73.5q0 -33 11 -61t37 -54.5t70.5 -54t112.5 -59.5q57 -28 111.5 -60t89.5 -61q32 26 51 60.5t19 76.5q0 23 -9 48t-32.5 51t-63.5 53.5t-102 56.5z" />-<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1182" d="M616 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM1044 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="copyright" unicode="©" horiz-adv-x="1731" d="M129 731q0 104 27 200.5t75.5 180t117.5 152.5t152.5 118t179.5 76t200 27t200 -27t179.5 -76t152.5 -118t118 -152.5t76 -180t27 -200.5t-27 -200t-76 -179.5t-118 -152t-152.5 -117.5t-179.5 -75.5t-200 -26.5t-200 26.5t-179.5 75.5t-152.5 117.5t-117.5 152 t-75.5 179.5t-27 200zM242 731q0 -88 23 -169.5t64.5 -152.5t99.5 -129.5t129 -100t153 -64.5t170 -23q89 0 170.5 23t153 64.5t130 100t100 129.5t64.5 152.5t23 169.5q0 133 -50.5 249.5t-137.5 203.5t-203.5 137.5t-249.5 50.5q-88 0 -170 -23t-153 -64.5t-129 -100 t-99.5 -130t-64.5 -153.5t-23 -170zM918 365q46 0 86 12t72.5 32t55.5 44.5t37 50.5q13 -9 21 -25.5t8 -38.5q0 -28 -19 -57t-57.5 -53t-96 -39t-134.5 -15q-102 0 -179 33t-128.5 93t-77 144t-25.5 187q0 100 28 183t83.5 143t137.5 93.5t190 33.5q70 0 123 -11.5t87.5 -31 t52 -46t17.5 -57.5q0 -22 -11 -40t-29.5 -30.5t-44 -19t-54.5 -6.5q0 28 -7.5 56t-24.5 50.5t-45 36t-69 13.5q-72 0 -122.5 -24t-82.5 -71t-46.5 -115.5t-14.5 -156.5q0 -177 69 -272.5t200 -95.5z" />-<glyph glyph-name="ordfeminine" unicode="ª" horiz-adv-x="883" d="M772 782q-68 0 -105.5 27.5t-37.5 75.5q0 25 3.5 57t6.5 55h-8q-26 -48 -55.5 -87t-63.5 -67t-73.5 -43.5t-84.5 -15.5q-51 0 -88.5 17.5t-62 48t-36 71.5t-11.5 89t12 101t37 104.5t63.5 97.5t90 81t117 55.5t145.5 20.5q55 0 91.5 -12t67.5 -31l72 29h70l-76 -373 q-8 -42 -15.5 -75.5t-7.5 -59.5q0 -53 43 -53q20 0 42.5 9.5t45.5 23.5l27 -49q-13 -14 -34.5 -31t-48.5 -31.5t-59.5 -24.5t-66.5 -10zM395 1022q0 -34 5 -56.5t14 -36.5t20.5 -20t24.5 -6q27 0 56 24.5t54 62t45 80.5t29 81l49 195q-12 18 -37.5 28t-50.5 10 q-34 0 -63 -17.5t-52 -47t-40.5 -67.5t-29.5 -78t-18 -79.5t-6 -72.5z" />-<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="1135" d="M143 621l389 342h144l-293 -410l119 -410h-144l-237 371zM555 621l389 342h143l-292 -410l118 -410h-143l-238 371z" />-<glyph glyph-name="logicalnot" unicode="¬" d="M1044 805v-512h-147v366h-731v146h878z" />-<glyph glyph-name="uni00AD" unicode="­" horiz-adv-x="635" d="M20 451l48 215h532l-47 -215h-533z" />-<glyph glyph-name="registered" unicode="®" horiz-adv-x="1731" d="M494 358h26q20 0 38 2.5t32 10t22.5 21.5t8.5 38v600q0 24 -8.5 38t-22.5 21.5t-32 10t-38 2.5h-26v72h368q352 0 352 -244q0 -49 -16 -86t-42 -64t-59.5 -45.5t-68.5 -29.5l182 -293q10 -17 19.5 -27.5t22.5 -16.5t30 -8t43 -2v-69h-217l-225 381h-109v-240 q1 -24 9.5 -38t22 -21.5t31 -10t37.5 -2.5h29v-69h-409v69zM774 748h86q55 0 92.5 11t59.5 33t31.5 56t9.5 80q0 45 -11 77t-35 51.5t-61.5 28.5t-91.5 9h-80v-346zM129 731q0 104 27 200.5t75.5 180t117.5 152.5t152.5 118t179.5 76t200 27t200 -27t179.5 -76t152.5 -118 t118 -152.5t76 -180t27 -200.5t-27 -200t-76 -179.5t-118 -152t-152.5 -117.5t-179.5 -75.5t-200 -26.5t-200 26.5t-179.5 75.5t-152.5 117.5t-117.5 152t-75.5 179.5t-27 200zM242 731q0 -88 23 -169.5t64.5 -152.5t99.5 -129.5t129 -100t153 -64.5t170 -23q89 0 170.5 23 t153 64.5t130 100t100 129.5t64.5 152.5t23 169.5q0 133 -50.5 249.5t-137.5 203.5t-203.5 137.5t-249.5 50.5q-88 0 -170 -23t-153 -64.5t-129 -100t-99.5 -130t-64.5 -153.5t-23 -170z" />-<glyph glyph-name="macron" unicode="¯" horiz-adv-x="940" d="M950 1556h-960v121h960v-121z" />-<glyph glyph-name="degree" unicode="°" horiz-adv-x="819" d="M225 1151q0 64 24 121t66 99t98.5 66.5t121.5 24.5q64 0 121 -24.5t99 -66.5t66.5 -99t24.5 -121q0 -65 -24.5 -121t-66.5 -98t-99 -66t-121 -24q-65 0 -121.5 24t-98.5 66t-66 98t-24 121zM367 1151q0 -35 13 -65.5t36 -54t53.5 -37t65.5 -13.5q36 0 67 13.5t54 37 t36 54t13 65.5q0 36 -13 67.5t-36 54.5t-54 36.5t-67 13.5q-35 0 -65.5 -13.5t-53.5 -36.5t-36 -54.5t-13 -67.5z" />-<glyph glyph-name="plusminus" unicode="±" d="M1044 0h-878v145h878v-145zM678 659v-366h-148v366h-364v146h364v366h148v-366h366v-146h-366z" />-<glyph glyph-name="uni00B2" unicode="²" horiz-adv-x="819" d="M59 586l29 147l303 221q62 45 104 86.5t67 81.5t35.5 80.5t10.5 83.5q0 20 -4.5 39t-14.5 33.5t-26.5 23.5t-40.5 9q-29 0 -52 -17t-40.5 -45t-29 -64.5t-15.5 -76.5q-72 0 -114 29t-42 75q0 42 22 77t63.5 60.5t100.5 39.5t134 14q64 0 115.5 -13.5t87.5 -37.5t55.5 -58 t19.5 -76q0 -43 -14.5 -82.5t-50 -82t-93.5 -92t-145 -111.5l-256 -185h301q48 0 72.5 25t36.5 59l16 43h80l-57 -286h-658z" />-<glyph glyph-name="uni00B3" unicode="³" horiz-adv-x="819" d="M360 573q-149 0 -225 44.5t-76 121.5q0 28 11.5 49.5t32 36.5t48.5 23t60 8q0 -29 9 -60.5t29 -57t52 -42t78 -16.5q37 0 69.5 9t56.5 29.5t38 52.5t14 77q0 28 -11 54t-33.5 45t-58 30.5t-83.5 11.5h-68l16 96h70q43 0 82 14.5t68.5 41.5t47 66.5t17.5 90.5 q0 41 -18.5 67t-59.5 26q-33 0 -57.5 -14.5t-42 -39.5t-28 -57t-15.5 -68q-75 0 -120.5 22.5t-45.5 72.5q0 36 22 68t63.5 56t101.5 38t135 14q73 0 126.5 -14.5t88.5 -40t52 -59.5t17 -73q0 -54 -19 -94t-53.5 -69t-82 -48t-103.5 -30l-2 -11q94 -11 150.5 -57t56.5 -131 q0 -69 -31 -122t-85.5 -88.5t-130 -54t-163.5 -18.5z" />-<glyph glyph-name="acute" unicode="´" horiz-adv-x="1182" d="M504 1268q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="uni00B5" unicode="µ" horiz-adv-x="1386" d="M803 188q-35 -47 -68.5 -85.5t-70.5 -65.5t-79 -42t-93 -15q-91 0 -154 40.5t-100 106.5q-7 -36 -12.5 -74t-9 -74t-5.5 -68.5t-2 -57.5q0 -35 6.5 -63.5t25 -49.5t51 -34.5t83.5 -18.5q-8 -45 -31.5 -79t-57 -56t-74.5 -33t-83 -11q-29 0 -53.5 7.5t-42 25t-27.5 45.5 t-10 70q0 61 17 137t44 173l60 219t65 276l135 637h312l-137 -643l-7 -35t-7.5 -42.5t-6 -45t-2.5 -41.5q0 -28 6.5 -53t21 -43.5t36 -29.5t51.5 -11q95 0 160 91.5t106 286.5l121 566h311l-141 -666q-13 -56 -21 -104.5t-8 -91.5q0 -45 19 -69t53 -24q32 0 58.5 12t62.5 35 l49 -69q-25 -26 -56 -51.5t-71 -45.5t-89 -32t-110 -12q-63 0 -104.5 17.5t-66 46t-34.5 66t-10 78.5h-10z" />-<glyph glyph-name="paragraph" unicode="¶" horiz-adv-x="1284" d="M909 1430h-172v-1657h-342v108h27q34 0 65 4.5t53.5 20t36 44.5t13.5 77v764h-146q-90 0 -150 32.5t-96 88t-51.5 128t-15.5 152.5q0 82 17 149t55 115t98.5 74t147.5 26h802v-108h-26q-35 0 -65.5 -5t-53 -20.5t-36 -44.5t-13.5 -78v-1273q0 -48 13.5 -77t36 -44.5 t53 -20t65.5 -4.5h26v-108h-342v1657z" />-<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="623" d="M518 746q0 -51 -15.5 -86.5t-41 -57t-57.5 -31t-64 -9.5q-74 0 -120 36t-46 111q0 42 12.5 76t36 58t56 37t73.5 13q35 0 65.5 -9t53 -27t35 -46t12.5 -65z" />-<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="682" d="M387 -70q41 -5 74.5 -20t57.5 -37.5t37 -51t13 -61.5q0 -66 -30.5 -113.5t-81.5 -78.5t-116.5 -45.5t-135.5 -14.5q-32 0 -75.5 7.5t-78.5 19.5l27 121q35 -8 70 -12t63 -4q31 0 59 6t48 18.5t32 32t12 47.5q0 20 -10.5 36.5t-28.5 29t-43 19.5t-53 9l82 180h117z" />-<glyph glyph-name="uni00B9" unicode="¹" horiz-adv-x="819" d="M717 1473l-146 -689q-5 -18 -6.5 -33t-1.5 -20q0 -18 6.5 -28.5t17.5 -16t25.5 -7t30.5 -1.5h84l-18 -90h-578l19 90h104q19 0 36.5 2.5t31.5 10.5t24.5 23.5t15.5 41.5l123 581q-58 -57 -103.5 -92t-82.5 -35q-29 0 -44 29.5t-15 71.5q24 4 48 11t50 18t56 27t65 38 l106 68h152z" />-<glyph glyph-name="ordmasculine" unicode="º" horiz-adv-x="834" d="M922 1219q0 -43 -12 -92t-37 -98t-62.5 -94t-89 -79.5t-116.5 -55t-144 -20.5q-71 0 -129 16.5t-99 49.5t-63.5 81t-22.5 111q0 46 13.5 96.5t39.5 98.5t65 91.5t91 76.5t116 52.5t140 19.5q64 0 120.5 -15t98.5 -46t66.5 -79t24.5 -114zM692 1225q0 68 -21 103.5 t-69 35.5q-52 0 -93.5 -33t-70 -83.5t-44 -109.5t-15.5 -110q0 -69 23 -107t69 -38q55 0 96.5 34.5t69 86.5t41.5 111.5t14 109.5z" />-<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="1135" d="M987 487l-387 -344h-143l295 410l-121 410h143l236 -369zM575 487l-387 -344h-143l295 410l-121 410h143l236 -369z" />-<glyph glyph-name="onequarter" unicode="¼" horiz-adv-x="1720" d="M1335 578q6 32 17 63.5t22 69.5q-11 -17 -24 -33t-19 -24l-287 -305h244zM1466 240l-8 -36q-5 -23 -6 -39q-2 -17 -2 -23q0 -17 5.5 -27t15.5 -15.5t23 -7t27 -1.5h41l-18 -90h-471l18 90h58q17 0 32.5 2.5t29 10.5t23.5 24q10 15 15 41l14 71h-387l17 82l528 564h182 l-112 -537h159l-24 -109h-160zM460 0h-174l1039 1462h172zM640 1473l-146 -689q-5 -18 -6.5 -33t-1.5 -20q0 -18 6.5 -28.5t17.5 -16t25.5 -7t30.5 -1.5h84l-18 -90h-578l19 90h104q19 0 36.5 2.5t31.5 10.5t24.5 23.5t15.5 41.5l123 581q-58 -57 -103.5 -92t-82.5 -35 q-29 0 -44 29.5t-15 71.5q24 4 48 11t50 18t56 27t65 38l106 68h152z" />-<glyph glyph-name="onehalf" unicode="½" horiz-adv-x="1720" d="M450 0h-174l1039 1462h172zM640 1473l-146 -689q-5 -18 -6.5 -33t-1.5 -20q0 -18 6.5 -28.5t17.5 -16t25.5 -7t30.5 -1.5h84l-18 -90h-578l19 90h104q19 0 36.5 2.5t31.5 10.5t24.5 23.5t15.5 41.5l123 581q-58 -57 -103.5 -92t-82.5 -35q-29 0 -44 29.5t-15 71.5 q24 4 48 11t50 18t56 27t65 38l106 68h152zM899 1l29 147l303 221q62 45 104 86.5t67 81.5t35.5 80.5t10.5 83.5q0 20 -4.5 39t-14.5 33.5t-26.5 23.5t-40.5 9q-29 0 -52 -17t-40.5 -45t-29 -64.5t-15.5 -76.5q-72 0 -114 29t-42 75q0 42 22 77t63.5 60.5t100.5 39.5t134 14 q64 0 115.5 -13.5t87.5 -37.5t55.5 -58t19.5 -76q0 -43 -14.5 -82.5t-50 -82t-93.5 -92t-145 -111.5l-256 -185h301q48 0 72.5 25t36.5 59l16 43h80l-57 -286h-658z" />-<glyph glyph-name="threequarters" unicode="¾" horiz-adv-x="1720" d="M1343 578q6 32 17 63.5t22 69.5q-11 -17 -24 -33t-19 -24l-287 -305h244zM1474 240l-8 -36q-5 -23 -6 -39q-2 -17 -2 -23q0 -17 5.5 -27t15.5 -15.5t23 -7t27 -1.5h41l-18 -90h-471l18 90h58q17 0 32.5 2.5t29 10.5t23.5 24q10 15 15 41l14 71h-387l17 82l528 564h182 l-112 -537h159l-24 -109h-160zM514 0h-174l1039 1462h172zM357 573q-149 0 -225 44.5t-76 121.5q0 28 11.5 49.5t32 36.5t48.5 23t60 8q0 -29 9 -60.5t29 -57t52 -42t78 -16.5q37 0 69.5 9t56.5 29.5t38 52.5t14 77q0 28 -11 54t-33.5 45t-58 30.5t-83.5 11.5h-68l16 96h70 q43 0 82 14.5t68.5 41.5t47 66.5t17.5 90.5q0 41 -18.5 67t-59.5 26q-33 0 -57.5 -14.5t-42 -39.5t-28 -57t-15.5 -68q-75 0 -120.5 22.5t-45.5 72.5q0 36 22 68t63.5 56t101.5 38t135 14q73 0 126.5 -14.5t88.5 -40t52 -59.5t17 -73q0 -54 -19 -94t-53.5 -69t-82 -48 t-103.5 -30l-2 -11q94 -11 150.5 -57t56.5 -131q0 -69 -31 -122t-85.5 -88.5t-130 -54t-163.5 -18.5z" />-<glyph glyph-name="questiondown" unicode="¿" horiz-adv-x="1096" d="M4 -49q0 89 39 162.5t107 134t161.5 109t202.5 87.5l74 183h131l4 -254q-91 -33 -164.5 -72.5t-125.5 -90t-80.5 -115t-28.5 -148.5q0 -51 11 -90t31 -66t46.5 -41t58.5 -14q48 0 82.5 25t57.5 66t36.5 95t20.5 113q252 0 252 -158q0 -55 -33 -103.5t-94.5 -84.5 t-149.5 -57t-197 -21q-102 0 -184 20t-139 61.5t-88 105.5t-31 153zM524 926q0 51 15.5 86.5t41 57t57.5 31t64 9.5q75 0 120.5 -36t45.5 -111q0 -42 -12.5 -76t-35.5 -58t-56 -37.5t-74 -13.5q-35 0 -65.5 9t-53 27t-35 46t-12.5 66z" />-<glyph glyph-name="Agrave" unicode="À" horiz-adv-x="1542" d="M438 481l-100 -184q-20 -37 -29.5 -65t-9.5 -50q0 -38 28 -55.5t87 -17.5h41l-23 -109h-532l22 109h43q28 0 49.5 6.5t41.5 24.5t41.5 49t49.5 79l695 1194h280l172 -1206q5 -32 13.5 -59t22.5 -46.5t35.5 -30.5t53.5 -11h37l-22 -109h-676l22 109h47q66 0 105 20.5 t39 65.5q0 17 -1 33.5t-3 31.5l-31 221h-498zM885 950l-9.5 84.5t-8 76.5t-6 72t-3.5 72q-15 -37 -30 -68.5l-32 -64l-37.5 -69l-47.5 -84.5l-203 -363h414zM987 1579q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60 l-6 -27h-121z" />-<glyph glyph-name="Aacute" unicode="Á" horiz-adv-x="1542" d="M438 481l-100 -184q-20 -37 -29.5 -65t-9.5 -50q0 -38 28 -55.5t87 -17.5h41l-23 -109h-532l22 109h43q28 0 49.5 6.5t41.5 24.5t41.5 49t49.5 79l695 1194h280l172 -1206q5 -32 13.5 -59t22.5 -46.5t35.5 -30.5t53.5 -11h37l-22 -109h-676l22 109h47q66 0 105 20.5 t39 65.5q0 17 -1 33.5t-3 31.5l-31 221h-498zM885 950l-9.5 84.5t-8 76.5t-6 72t-3.5 72q-15 -37 -30 -68.5l-32 -64l-37.5 -69l-47.5 -84.5l-203 -363h414zM864 1606q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5 l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="Acircumflex" unicode="Â" horiz-adv-x="1542" d="M438 481l-100 -184q-20 -37 -29.5 -65t-9.5 -50q0 -38 28 -55.5t87 -17.5h41l-23 -109h-532l22 109h43q28 0 49.5 6.5t41.5 24.5t41.5 49t49.5 79l695 1194h280l172 -1206q5 -32 13.5 -59t22.5 -46.5t35.5 -30.5t53.5 -11h37l-22 -109h-676l22 109h47q66 0 105 20.5 t39 65.5q0 17 -1 33.5t-3 31.5l-31 221h-498zM885 950l-9.5 84.5t-8 76.5t-6 72t-3.5 72q-15 -37 -30 -68.5l-32 -64l-37.5 -69l-47.5 -84.5l-203 -363h414zM619 1606l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40 l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="Atilde" unicode="Ã" horiz-adv-x="1542" d="M438 481l-100 -184q-20 -37 -29.5 -65t-9.5 -50q0 -38 28 -55.5t87 -17.5h41l-23 -109h-532l22 109h43q28 0 49.5 6.5t41.5 24.5t41.5 49t49.5 79l695 1194h280l172 -1206q5 -32 13.5 -59t22.5 -46.5t35.5 -30.5t53.5 -11h37l-22 -109h-676l22 109h47q66 0 105 20.5 t39 65.5q0 17 -1 33.5t-3 31.5l-31 221h-498zM885 950l-9.5 84.5t-8 76.5t-6 72t-3.5 72q-15 -37 -30 -68.5l-32 -64l-37.5 -69l-47.5 -84.5l-203 -363h414zM1188 1774q26 0 45 9t32.5 24t22 34.5t13.5 40.5h123q-11 -49 -33.5 -102.5t-56 -98t-78 -73.5t-99.5 -29t-99 20 t-81 44.5l-69.5 44.5t-65.5 20q-21 0 -40 -9t-34 -24t-25 -34.5t-14 -40.5h-122q9 46 32.5 99.5t59.5 98.5t82.5 75t101.5 30q54 0 96.5 -20t78 -44.5l67 -44.5t63.5 -20z" />-<glyph glyph-name="Adieresis" unicode="Ä" horiz-adv-x="1542" d="M438 481l-100 -184q-20 -37 -29.5 -65t-9.5 -50q0 -38 28 -55.5t87 -17.5h41l-23 -109h-532l22 109h43q28 0 49.5 6.5t41.5 24.5t41.5 49t49.5 79l695 1194h280l172 -1206q5 -32 13.5 -59t22.5 -46.5t35.5 -30.5t53.5 -11h37l-22 -109h-676l22 109h47q66 0 105 20.5 t39 65.5q0 17 -1 33.5t-3 31.5l-31 221h-498zM885 950l-9.5 84.5t-8 76.5t-6 72t-3.5 72q-15 -37 -30 -68.5l-32 -64l-37.5 -69l-47.5 -84.5l-203 -363h414zM913 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28 t31.5 -85zM1341 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="Aring" unicode="Å" horiz-adv-x="1542" d="M1092 1573q0 30 -10 50.5t-26.5 34t-38.5 19.5t-46 6q-25 0 -47 -6t-38.5 -19.5t-26 -34t-9.5 -50.5t9.5 -51t26 -34.5t38.5 -19.5t47 -6q24 0 46 6t38.5 19.5t26.5 34.5t10 51zM1217 1573q0 -55 -19 -96.5t-52.5 -70t-78.5 -43t-96 -14.5t-96 14.5t-78.5 43t-52.5 70 t-19 96.5q0 54 19 96t52.5 70t78.5 42.5t96 14.5t96 -14.5t78.5 -42.5t52.5 -70t19 -96zM438 481l-100 -184q-20 -37 -29.5 -65t-9.5 -50q0 -38 28 -55.5t87 -17.5h41l-23 -109h-532l22 109h43q28 0 49.5 6.5t41.5 24.5t41.5 49t49.5 79l695 1194h280l172 -1206 q5 -32 13.5 -59t22.5 -46.5t35.5 -30.5t53.5 -11h37l-22 -109h-676l22 109h47q66 0 105 20.5t39 65.5q0 17 -1 33.5t-3 31.5l-31 221h-498zM885 950l-9.5 84.5t-8 76.5t-6 72t-3.5 72q-15 -37 -30 -68.5l-32 -64l-37.5 -69l-47.5 -84.5l-203 -363h414z" />-<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="2034" d="M2083 1462l-72 -381h-145q1 7 2.5 25l3 37.5t3 36t1.5 20.5q0 28 -8 53t-25 44t-44.5 29.5t-67.5 10.5h-273l-108 -512h465l-27 -123h-465l-123 -577h324q48 0 85.5 13.5t66 36.5t48 53.5t31.5 64.5l33 88h145l-94 -381h-1175l22 109h27q32 0 62.5 4t55.5 17t43.5 37 t26.5 64l49 238h-467l-121 -172q-30 -43 -43.5 -76.5t-13.5 -50.5q0 -32 28 -46.5t81 -14.5h35l-23 -109h-516l22 109h25q27 0 52 9.5t50.5 29t52.5 49.5t58 71l805 1075l-133 11l22 108h1219zM1114 1337l-539 -745h402l158 745h-21z" />-<glyph glyph-name="Ccedilla" unicode="Ç" horiz-adv-x="1368" d="M823 152q71 0 128 16t102 42.5t79 59.5t60 68q12 -9 23.5 -28t11.5 -42q0 -51 -31 -102.5t-91.5 -93t-149.5 -67t-205 -25.5q-147 0 -262.5 36.5t-195 107t-121.5 173t-42 233.5q0 123 29 242t84 226t134.5 197t180 156t220.5 103t257 37q102 0 178.5 -17.5t127 -49 t75.5 -77t25 -100.5q0 -45 -22 -79t-60.5 -57.5t-91.5 -35.5t-115 -12q0 43 -6 95t-24.5 97t-52.5 75t-91 30q-81 0 -149.5 -37t-125 -100.5t-100 -147.5t-73 -177.5t-45 -191t-15.5 -188.5q0 -175 89 -270.5t265 -95.5zM684 -70q41 -5 74.5 -20t57.5 -37.5t37 -51t13 -61.5 q0 -66 -30.5 -113.5t-81.5 -78.5t-116.5 -45.5t-135.5 -14.5q-32 0 -75.5 7.5t-78.5 19.5l27 121q35 -8 70 -12t63 -4q31 0 59 6t48 18.5t32 32t12 47.5q0 20 -10.5 36.5t-28.5 29t-43 19.5t-53 9l82 180h117z" />-<glyph glyph-name="Egrave" unicode="È" horiz-adv-x="1296" d="M-25 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h1112l-72 -381h-145q1 7 2.5 25l3 37.5t3 36t1.5 20.5q0 28 -8 53t-25 44t-44.5 29.5t-67.5 10.5h-272l-109 -512h465l-27 -123h-465 l-123 -577h324q48 0 86 13.5t66 36.5t47.5 53.5t31.5 64.5l33 88h146l-95 -381h-1175zM870 1579q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="Eacute" unicode="É" horiz-adv-x="1296" d="M-25 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h1112l-72 -381h-145q1 7 2.5 25l3 37.5t3 36t1.5 20.5q0 28 -8 53t-25 44t-44.5 29.5t-67.5 10.5h-272l-109 -512h465l-27 -123h-465 l-123 -577h324q48 0 86 13.5t66 36.5t47.5 53.5t31.5 64.5l33 88h146l-95 -381h-1175zM748 1606q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="Ecircumflex" unicode="Ê" horiz-adv-x="1296" d="M-25 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h1112l-72 -381h-145q1 7 2.5 25l3 37.5t3 36t1.5 20.5q0 28 -8 53t-25 44t-44.5 29.5t-67.5 10.5h-272l-109 -512h465l-27 -123h-465 l-123 -577h324q48 0 86 13.5t66 36.5t47.5 53.5t31.5 64.5l33 88h146l-95 -381h-1175zM557 1606l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="Edieresis" unicode="Ë" horiz-adv-x="1296" d="M-25 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h1112l-72 -381h-145q1 7 2.5 25l3 37.5t3 36t1.5 20.5q0 28 -8 53t-25 44t-44.5 29.5t-67.5 10.5h-272l-109 -512h465l-27 -123h-465 l-123 -577h324q48 0 86 13.5t66 36.5t47.5 53.5t31.5 64.5l33 88h146l-95 -381h-1175zM811 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM1239 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5 q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="Igrave" unicode="Ì" horiz-adv-x="821" d="M-47 0l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-211 -1004q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21 t47.5 -10t59.5 -2.5h27l-23 -109h-704zM629 1579q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="821" d="M-47 0l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-211 -1004q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21 t47.5 -10t59.5 -2.5h27l-23 -109h-704zM501 1606q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="821" d="M-47 0l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-211 -1004q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21 t47.5 -10t59.5 -2.5h27l-23 -109h-704zM272 1606l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="821" d="M-47 0l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-211 -1004q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21 t47.5 -10t59.5 -2.5h27l-23 -109h-704zM556 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM984 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39 q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="1573" d="M-27 109h29q32 0 62.5 4t55.5 17t43.5 37t26.5 64l99 471h-168l26 125h168l88 410q3 11 5.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-46.5 10t-59 2.5h-27l23 108h655q147 0 262 -36t195 -106.5t122 -174.5t42 -240q0 -122 -25.5 -236.5t-75 -215t-122.5 -184t-169 -143.5 t-214.5 -93t-257.5 -33h-721zM584 127q144 0 257 58.5t191 164t119 251.5t41 321q0 107 -25 185.5t-72 129.5t-113.5 75.5t-148.5 24.5h-86l-108 -510h258l-27 -125h-258l-121 -575h93z" />-<glyph glyph-name="Ntilde" unicode="Ñ" horiz-adv-x="1614" d="M1094 0l-555 1159l-193 -917q-5 -23 -7.5 -39.5t-2.5 -24.5q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h7l-23 -109h-516l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l209 983q13 53 13 70q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h455l499 -1050 l172 809q11 47 11 63q0 22 -11.5 36t-31.5 21.5t-47.5 10t-59.5 2.5h-6l23 108h516l-23 -108h-26q-32 0 -62.5 -4.5t-55.5 -17.5t-43.5 -37t-27.5 -64l-260 -1231h-188zM1247 1774q26 0 45 9t32.5 24t22 34.5t13.5 40.5h123q-11 -49 -33.5 -102.5t-56 -98t-78 -73.5 t-99.5 -29t-99 20t-81 44.5l-69.5 44.5t-65.5 20q-21 0 -40 -9t-34 -24t-25 -34.5t-14 -40.5h-122q9 46 32.5 99.5t59.5 98.5t82.5 75t101.5 30q54 0 96.5 -20t78 -44.5l67 -44.5t63.5 -20z" />-<glyph glyph-name="Ograve" unicode="Ò" horiz-adv-x="1622" d="M129 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q113 0 215.5 -33t180.5 -102t124 -175t46 -253q0 -94 -23.5 -201t-71 -212t-119 -201t-168 -169.5t-218 -117.5t-267.5 -44q-121 0 -225.5 36.5t-181 108.5t-120.5 178t-44 245zM463 496 q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22q85 0 154.5 41t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5q0 100 -21 172t-57.5 119t-87.5 69.5t-111 22.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5zM983 1579q-44 26 -93.5 66 t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="Oacute" unicode="Ó" horiz-adv-x="1622" d="M129 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q113 0 215.5 -33t180.5 -102t124 -175t46 -253q0 -94 -23.5 -201t-71 -212t-119 -201t-168 -169.5t-218 -117.5t-267.5 -44q-121 0 -225.5 36.5t-181 108.5t-120.5 178t-44 245zM463 496 q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22q85 0 154.5 41t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5q0 100 -21 172t-57.5 119t-87.5 69.5t-111 22.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5zM881 1606q28 29 61 67 l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="Ocircumflex" unicode="Ô" horiz-adv-x="1622" d="M129 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q113 0 215.5 -33t180.5 -102t124 -175t46 -253q0 -94 -23.5 -201t-71 -212t-119 -201t-168 -169.5t-218 -117.5t-267.5 -44q-121 0 -225.5 36.5t-181 108.5t-120.5 178t-44 245zM463 496 q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22q85 0 154.5 41t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5q0 100 -21 172t-57.5 119t-87.5 69.5t-111 22.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5zM652 1606l68 66.5l78 77.5 l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="Otilde" unicode="Õ" horiz-adv-x="1622" d="M129 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q113 0 215.5 -33t180.5 -102t124 -175t46 -253q0 -94 -23.5 -201t-71 -212t-119 -201t-168 -169.5t-218 -117.5t-267.5 -44q-121 0 -225.5 36.5t-181 108.5t-120.5 178t-44 245zM463 496 q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22q85 0 154.5 41t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5q0 100 -21 172t-57.5 119t-87.5 69.5t-111 22.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5zM1184 1774q26 0 45 9 t32.5 24t22 34.5t13.5 40.5h123q-11 -49 -33.5 -102.5t-56 -98t-78 -73.5t-99.5 -29t-99 20t-81 44.5l-69.5 44.5t-65.5 20q-21 0 -40 -9t-34 -24t-25 -34.5t-14 -40.5h-122q9 46 32.5 99.5t59.5 98.5t82.5 75t101.5 30q54 0 96.5 -20t78 -44.5l67 -44.5t63.5 -20z" />-<glyph glyph-name="Odieresis" unicode="Ö" horiz-adv-x="1622" d="M129 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q113 0 215.5 -33t180.5 -102t124 -175t46 -253q0 -94 -23.5 -201t-71 -212t-119 -201t-168 -169.5t-218 -117.5t-267.5 -44q-121 0 -225.5 36.5t-181 108.5t-120.5 178t-44 245zM463 496 q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22q85 0 154.5 41t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5q0 100 -21 172t-57.5 119t-87.5 69.5t-111 22.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5zM942 1755q0 -40 -11 -67 t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM1370 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="multiply" unicode="×" d="M604 631l-301 -303l-104 104l301 303l-301 301l104 103l301 -301l301 303l105 -105l-303 -303l303 -303l-103 -102z" />-<glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1622" d="M129 545q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5q162 0 295 -68l97 129h143l-145 -192q80 -69 128 -176t48 -256q0 -94 -23.5 -201t-71 -212t-119 -201t-168 -169.5t-218 -117.5t-267.5 -44q-81 0 -154 17t-138 49l-93 -125h-145l143 186 q-86 73 -135 182.5t-49 258.5zM463 496q0 -96 18 -166l686 915q-37 54 -90.5 80.5t-118.5 26.5q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5zM1235 969q0 43 -4 82t-12 71l-682 -909q37 -53 89.5 -76.5t114.5 -23.5q85 0 154.5 41 t124.5 109.5t95.5 157t67 183.5t39.5 189.5t13 175.5z" />-<glyph glyph-name="Ugrave" unicode="Ù" horiz-adv-x="1530" d="M772 125q93 0 157 27t107 74.5t69 113t42 143.5l158 740q3 17 5.5 35t2.5 26q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h539l-23 -108h-26q-33 0 -64 -4.5t-57 -17.5t-44.5 -38t-27.5 -65l-164 -778q-24 -115 -71.5 -203t-121 -147.5t-173.5 -90t-230 -30.5 q-120 0 -212 23.5t-155 69t-95.5 111.5t-32.5 150q0 16 2 40t5 49.5t7 50t8 42.5l150 698q12 55 12 70q0 22 -11 36t-30.5 21.5t-46.5 10t-59 2.5h-27l23 108h708l-22 -108h-27q-34 0 -65.5 -4.5t-57.5 -17t-44.5 -36.5t-27.5 -63l-155 -721l-8.5 -40t-8 -45.5t-6 -47.5 t-2.5 -45q0 -103 64 -156t188 -53zM1015 1579q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="Uacute" unicode="Ú" horiz-adv-x="1530" d="M772 125q93 0 157 27t107 74.5t69 113t42 143.5l158 740q3 17 5.5 35t2.5 26q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h539l-23 -108h-26q-33 0 -64 -4.5t-57 -17.5t-44.5 -38t-27.5 -65l-164 -778q-24 -115 -71.5 -203t-121 -147.5t-173.5 -90t-230 -30.5 q-120 0 -212 23.5t-155 69t-95.5 111.5t-32.5 150q0 16 2 40t5 49.5t7 50t8 42.5l150 698q12 55 12 70q0 22 -11 36t-30.5 21.5t-46.5 10t-59 2.5h-27l23 108h708l-22 -108h-27q-34 0 -65.5 -4.5t-57.5 -17t-44.5 -36.5t-27.5 -63l-155 -721l-8.5 -40t-8 -45.5t-6 -47.5 t-2.5 -45q0 -103 64 -156t188 -53zM914 1606q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="Ucircumflex" unicode="Û" horiz-adv-x="1530" d="M772 125q93 0 157 27t107 74.5t69 113t42 143.5l158 740q3 17 5.5 35t2.5 26q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h539l-23 -108h-26q-33 0 -64 -4.5t-57 -17.5t-44.5 -38t-27.5 -65l-164 -778q-24 -115 -71.5 -203t-121 -147.5t-173.5 -90t-230 -30.5 q-120 0 -212 23.5t-155 69t-95.5 111.5t-32.5 150q0 16 2 40t5 49.5t7 50t8 42.5l150 698q12 55 12 70q0 22 -11 36t-30.5 21.5t-46.5 10t-59 2.5h-27l23 108h708l-22 -108h-27q-34 0 -65.5 -4.5t-57.5 -17t-44.5 -36.5t-27.5 -63l-155 -721l-8.5 -40t-8 -45.5t-6 -47.5 t-2.5 -45q0 -103 64 -156t188 -53zM697 1606l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="Udieresis" unicode="Ü" horiz-adv-x="1530" d="M772 125q93 0 157 27t107 74.5t69 113t42 143.5l158 740q3 17 5.5 35t2.5 26q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h539l-23 -108h-26q-33 0 -64 -4.5t-57 -17.5t-44.5 -38t-27.5 -65l-164 -778q-24 -115 -71.5 -203t-121 -147.5t-173.5 -90t-230 -30.5 q-120 0 -212 23.5t-155 69t-95.5 111.5t-32.5 150q0 16 2 40t5 49.5t7 50t8 42.5l150 698q12 55 12 70q0 22 -11 36t-30.5 21.5t-46.5 10t-59 2.5h-27l23 108h708l-22 -108h-27q-34 0 -65.5 -4.5t-57.5 -17t-44.5 -36.5t-27.5 -63l-155 -721l-8.5 -40t-8 -45.5t-6 -47.5 t-2.5 -45q0 -103 64 -156t188 -53zM956 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM1384 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39 q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="Yacute" unicode="Ý" horiz-adv-x="1419" d="M227 0l23 109h55q32 0 62 4.5t55 18t43 37.5t27 64l59 285l-221 727q-9 30 -18.5 51t-22.5 33.5t-32.5 18.5t-49.5 6h-27l23 108h665l-22 -108h-92q-47 0 -66.5 -16t-19.5 -44q0 -18 6 -52t18 -81l74 -289l15 -64t14.5 -68t11 -66.5t6.5 -57.5q19 41 58 104t92 138 l202 289q25 35 43.5 76t18.5 75q0 28 -28.5 42t-96.5 14h-43l24 108h537l-23 -108h-38q-23 0 -42.5 -6t-39.5 -21.5t-42.5 -41t-50.5 -64.5l-507 -705l-62 -291q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h50l-23 -109h-756zM832 1606q28 29 61 67 l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="Thorn" unicode="Þ" horiz-adv-x="1307" d="M-47 0l22 109h27q32 0 62.5 4t55.5 17t43.5 37t26.5 64l213 1006q4 11 6.5 25t2.5 22q0 22 -11 36t-30.5 21.5t-47 10t-59.5 2.5h-26l22 108h707l-23 -108h-26q-34 0 -65.5 -4.5t-57.5 -17.5t-45 -38t-27 -65l-6 -31h67q121 0 217.5 -25.5t164.5 -76t104.5 -125 t36.5 -172.5q0 -52 -10 -110t-35.5 -114t-70.5 -106.5t-114.5 -89t-167.5 -61.5t-229 -23h-154l-14 -70q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h27l-23 -109h-704zM551 414h84q93 0 157.5 28t104.5 78t58 120t18 153q0 76 -17.5 130t-49 88.5 t-75 50t-94.5 15.5h-45z" />-<glyph glyph-name="germandbls" unicode="ß" horiz-adv-x="1423" d="M895 1460q-55 0 -97.5 -19.5t-74 -56t-53 -89t-33.5 -119.5l-256 -1192q-20 -94 -54.5 -166t-78 -125t-94.5 -88.5t-105 -57t-109.5 -30.5t-107.5 -9q-40 0 -75.5 6.5t-55.5 14.5l29 113q17 -5 40.5 -9t55.5 -4q45 0 81 19.5t65.5 62t53.5 109.5t46 162l207 976h-166 l26 140h170l17 63q27 116 81.5 195.5t130.5 129t170 71.5t201 22q111 0 194 -23t138.5 -64.5t83 -100.5t27.5 -131q0 -26 -3.5 -58.5t-8.5 -66.5t-11.5 -67.5t-13.5 -61.5h-117q-61 0 -105 -12t-72.5 -33.5t-42 -51.5t-13.5 -67q0 -29 8.5 -53t28.5 -47t54.5 -47.5 t86.5 -55.5q99 -57 141.5 -129.5t42.5 -171.5q0 -81 -32.5 -147t-92 -113t-143 -72.5t-185.5 -25.5q-77 0 -140 15t-108 44t-69.5 70t-24.5 94q0 40 15 71.5t43 53t66.5 32.5t86.5 11q0 -48 8 -95t26.5 -85t48 -61.5t71.5 -23.5q68 0 103.5 45t35.5 119q0 32 -6 60.5 t-23 55.5t-47.5 53t-78.5 55q-96 55 -149.5 131t-53.5 176q0 83 31.5 142.5t83 98t116.5 56.5t133 18q10 47 15.5 85.5t5.5 72.5q0 84 -41 135t-127 51z" />-<glyph glyph-name="agrave" unicode="à" horiz-adv-x="1362" d="M969 -20q-91 0 -146 41.5t-55 121.5q0 32 3 62.5t11 70.5h-14q-38 -71 -75.5 -126.5t-83.5 -93t-102.5 -57t-131.5 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q40 0 81.5 -6.5t79.5 -16.5 t71.5 -22.5t56.5 -25.5l108 49h109l-135 -639q-4 -17 -10 -45t-11.5 -59.5t-9.5 -61t-4 -49.5q0 -51 20 -76t52 -25q29 0 55.5 12.5t58.5 30.5l45 -82q-26 -20 -59 -41.5t-73.5 -39.5t-88 -29.5t-102.5 -11.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q45 0 93 39 t90 102.5t75.5 143.5t50.5 162l72 340q-20 29 -55.5 43t-75.5 14q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126zM758 1241q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="aacute" unicode="á" horiz-adv-x="1362" d="M969 -20q-91 0 -146 41.5t-55 121.5q0 32 3 62.5t11 70.5h-14q-38 -71 -75.5 -126.5t-83.5 -93t-102.5 -57t-131.5 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q40 0 81.5 -6.5t79.5 -16.5 t71.5 -22.5t56.5 -25.5l108 49h109l-135 -639q-4 -17 -10 -45t-11.5 -59.5t-9.5 -61t-4 -49.5q0 -51 20 -76t52 -25q29 0 55.5 12.5t58.5 30.5l45 -82q-26 -20 -59 -41.5t-73.5 -39.5t-88 -29.5t-102.5 -11.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q45 0 93 39 t90 102.5t75.5 143.5t50.5 162l72 340q-20 29 -55.5 43t-75.5 14q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126zM637 1268q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5 t-77 -43.5h-139z" />-<glyph glyph-name="acircumflex" unicode="â" horiz-adv-x="1362" d="M969 -20q-91 0 -146 41.5t-55 121.5q0 32 3 62.5t11 70.5h-14q-38 -71 -75.5 -126.5t-83.5 -93t-102.5 -57t-131.5 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q40 0 81.5 -6.5t79.5 -16.5 t71.5 -22.5t56.5 -25.5l108 49h109l-135 -639q-4 -17 -10 -45t-11.5 -59.5t-9.5 -61t-4 -49.5q0 -51 20 -76t52 -25q29 0 55.5 12.5t58.5 30.5l45 -82q-26 -20 -59 -41.5t-73.5 -39.5t-88 -29.5t-102.5 -11.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q45 0 93 39 t90 102.5t75.5 143.5t50.5 162l72 340q-20 29 -55.5 43t-75.5 14q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126zM389 1268l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50 t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="atilde" unicode="ã" horiz-adv-x="1362" d="M969 -20q-91 0 -146 41.5t-55 121.5q0 32 3 62.5t11 70.5h-14q-38 -71 -75.5 -126.5t-83.5 -93t-102.5 -57t-131.5 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q40 0 81.5 -6.5t79.5 -16.5 t71.5 -22.5t56.5 -25.5l108 49h109l-135 -639q-4 -17 -10 -45t-11.5 -59.5t-9.5 -61t-4 -49.5q0 -51 20 -76t52 -25q29 0 55.5 12.5t58.5 30.5l45 -82q-26 -20 -59 -41.5t-73.5 -39.5t-88 -29.5t-102.5 -11.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q45 0 93 39 t90 102.5t75.5 143.5t50.5 162l72 340q-20 29 -55.5 43t-75.5 14q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126zM979 1436q26 0 45 9t32.5 24t22 34.5t13.5 40.5h123q-11 -49 -33.5 -102.5t-56 -98t-78 -73.5t-99.5 -29t-99 20t-81 44.5l-69.5 44.5 t-65.5 20q-21 0 -40 -9t-34 -24t-25 -34.5t-14 -40.5h-122q9 46 32.5 99.5t59.5 98.5t82.5 75t101.5 30q54 0 96.5 -20t78 -44.5l67 -44.5t63.5 -20z" />-<glyph glyph-name="adieresis" unicode="ä" horiz-adv-x="1362" d="M969 -20q-91 0 -146 41.5t-55 121.5q0 32 3 62.5t11 70.5h-14q-38 -71 -75.5 -126.5t-83.5 -93t-102.5 -57t-131.5 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q40 0 81.5 -6.5t79.5 -16.5 t71.5 -22.5t56.5 -25.5l108 49h109l-135 -639q-4 -17 -10 -45t-11.5 -59.5t-9.5 -61t-4 -49.5q0 -51 20 -76t52 -25q29 0 55.5 12.5t58.5 30.5l45 -82q-26 -20 -59 -41.5t-73.5 -39.5t-88 -29.5t-102.5 -11.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q45 0 93 39 t90 102.5t75.5 143.5t50.5 162l72 340q-20 29 -55.5 43t-75.5 14q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126zM659 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z M1087 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="aring" unicode="å" horiz-adv-x="1362" d="M924 1432q0 30 -10 50.5t-26.5 34t-38.5 19.5t-46 6q-25 0 -47 -6t-38.5 -19.5t-26 -34t-9.5 -50.5t9.5 -51t26 -34.5t38.5 -19.5t47 -6q24 0 46 6t38.5 19.5t26.5 34.5t10 51zM1049 1432q0 -55 -19 -96.5t-52.5 -70t-78.5 -43t-96 -14.5t-96 14.5t-78.5 43t-52.5 70 t-19 96.5q0 54 19 96t52.5 70t78.5 42.5t96 14.5t96 -14.5t78.5 -42.5t52.5 -70t19 -96zM969 -20q-91 0 -146 41.5t-55 121.5q0 32 3 62.5t11 70.5h-14q-38 -71 -75.5 -126.5t-83.5 -93t-102.5 -57t-131.5 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5 t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q40 0 81.5 -6.5t79.5 -16.5t71.5 -22.5t56.5 -25.5l108 49h109l-135 -639q-4 -17 -10 -45t-11.5 -59.5t-9.5 -61t-4 -49.5q0 -51 20 -76t52 -25q29 0 55.5 12.5t58.5 30.5l45 -82q-26 -20 -59 -41.5 t-73.5 -39.5t-88 -29.5t-102.5 -11.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q45 0 93 39t90 102.5t75.5 143.5t50.5 162l72 340q-20 29 -55.5 43t-75.5 14q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126z" />-<glyph glyph-name="ae" unicode="æ" horiz-adv-x="1802" d="M1325 135q50 0 95 14.5t83 38t69 53t52 60.5q12 -15 19.5 -38.5t7.5 -49.5q0 -37 -24 -78t-73.5 -75.5t-126.5 -57t-182 -22.5q-187 0 -299.5 75t-150.5 221h-19q-38 -71 -77 -126.5t-86 -93t-105 -57t-133 -19.5q-73 0 -128 28.5t-91.5 78.5t-55 118.5t-18.5 148.5 t18.5 167.5t55.5 172.5t91.5 162t126 135t159.5 92.5t192 34.5q103 0 186 -31.5t154 -93.5q80 62 181.5 95.5t226.5 33.5q154 0 236.5 -63.5t82.5 -177.5q0 -83 -46 -159.5t-127 -135t-193 -93t-244 -34.5h-37.5t-38.5 2q-3 -20 -3.5 -40.5t-0.5 -37.5q0 -119 55.5 -183.5 t167.5 -64.5zM393 352q0 -59 8.5 -99t23 -64.5t35 -35t44.5 -10.5q37 0 77 28t77.5 74.5t70.5 108t57 129.5q10 53 24 107.5t33.5 106.5t44 101t56.5 91q-10 15 -29.5 32t-45 31.5t-55 24.5t-60.5 10q-60 0 -109.5 -31t-89.5 -83t-70.5 -118t-51 -137t-30.5 -140t-10 -126z M1397 999q-33 0 -64.5 -17.5t-59.5 -48t-52 -71.5t-44 -88t-34.5 -97t-22.5 -99h19q76 0 141.5 21t113.5 58.5t75.5 90.5t27.5 118q0 63 -26 98t-74 35z" />-<glyph glyph-name="ccedilla" unicode="ç" horiz-adv-x="1081" d="M621 135q54 0 97.5 14.5t78.5 38.5t62 54t48 61q13 -12 22 -35.5t9 -54.5q0 -40 -23.5 -81.5t-73 -75t-125.5 -55t-181 -21.5q-93 0 -175.5 26t-144 79t-97.5 132t-36 186q0 76 19 158.5t57 162t94.5 151t131.5 125.5t168 86t204 32q85 0 146.5 -17.5t101 -47t58.5 -69 t19 -83.5q0 -32 -13.5 -62.5t-43.5 -55t-77.5 -39.5t-115.5 -15q0 54 -9.5 102.5t-28.5 85t-46.5 57.5t-64.5 21q-44 0 -82.5 -29.5t-70.5 -78t-56.5 -111t-42 -129t-26.5 -131t-9 -117.5q0 -125 57 -194.5t169 -69.5zM487 -70q41 -5 74.5 -20t57.5 -37.5t37 -51t13 -61.5 q0 -66 -30.5 -113.5t-81.5 -78.5t-116.5 -45.5t-135.5 -14.5q-32 0 -75.5 7.5t-78.5 19.5l27 121q35 -8 70 -12t63 -4q31 0 59 6t48 18.5t32 32t12 47.5q0 20 -10.5 36.5t-28.5 29t-43 19.5t-53 9l82 180h117z" />-<glyph glyph-name="egrave" unicode="è" horiz-adv-x="1096" d="M618 135q50 0 95 14.5t83.5 38t69 53t52.5 60.5q12 -15 19 -38.5t7 -49.5q0 -37 -24 -78t-73.5 -75.5t-126 -57t-181.5 -22.5q-94 0 -177 26t-145.5 78.5t-98.5 132t-36 186.5q0 76 20 159t59.5 162.5t98 151t135.5 125.5t172.5 85.5t208.5 31.5q147 0 228 -63.5 t81 -177.5q0 -83 -46 -159t-127 -133.5t-193 -91.5t-244 -34h-37t-39 2q-3 -20 -3.5 -40.5t-0.5 -37.5q0 -119 55.5 -183.5t167.5 -64.5zM690 995q-50 0 -95 -37.5t-81 -97.5t-62 -134.5t-38 -147.5h18q76 0 141.5 20t114 57.5t76 89.5t27.5 117q0 63 -26.5 98t-74.5 35z M762 1241q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="eacute" unicode="é" horiz-adv-x="1096" d="M618 135q50 0 95 14.5t83.5 38t69 53t52.5 60.5q12 -15 19 -38.5t7 -49.5q0 -37 -24 -78t-73.5 -75.5t-126 -57t-181.5 -22.5q-94 0 -177 26t-145.5 78.5t-98.5 132t-36 186.5q0 76 20 159t59.5 162.5t98 151t135.5 125.5t172.5 85.5t208.5 31.5q147 0 228 -63.5 t81 -177.5q0 -83 -46 -159t-127 -133.5t-193 -91.5t-244 -34h-37t-39 2q-3 -20 -3.5 -40.5t-0.5 -37.5q0 -119 55.5 -183.5t167.5 -64.5zM690 995q-50 0 -95 -37.5t-81 -97.5t-62 -134.5t-38 -147.5h18q76 0 141.5 20t114 57.5t76 89.5t27.5 117q0 63 -26.5 98t-74.5 35z M633 1268q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="1096" d="M618 135q50 0 95 14.5t83.5 38t69 53t52.5 60.5q12 -15 19 -38.5t7 -49.5q0 -37 -24 -78t-73.5 -75.5t-126 -57t-181.5 -22.5q-94 0 -177 26t-145.5 78.5t-98.5 132t-36 186.5q0 76 20 159t59.5 162.5t98 151t135.5 125.5t172.5 85.5t208.5 31.5q147 0 228 -63.5 t81 -177.5q0 -83 -46 -159t-127 -133.5t-193 -91.5t-244 -34h-37t-39 2q-3 -20 -3.5 -40.5t-0.5 -37.5q0 -119 55.5 -183.5t167.5 -64.5zM690 995q-50 0 -95 -37.5t-81 -97.5t-62 -134.5t-38 -147.5h18q76 0 141.5 20t114 57.5t76 89.5t27.5 117q0 63 -26.5 98t-74.5 35z M371 1268l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="edieresis" unicode="ë" horiz-adv-x="1096" d="M618 135q50 0 95 14.5t83.5 38t69 53t52.5 60.5q12 -15 19 -38.5t7 -49.5q0 -37 -24 -78t-73.5 -75.5t-126 -57t-181.5 -22.5q-94 0 -177 26t-145.5 78.5t-98.5 132t-36 186.5q0 76 20 159t59.5 162.5t98 151t135.5 125.5t172.5 85.5t208.5 31.5q147 0 228 -63.5 t81 -177.5q0 -83 -46 -159t-127 -133.5t-193 -91.5t-244 -34h-37t-39 2q-3 -20 -3.5 -40.5t-0.5 -37.5q0 -119 55.5 -183.5t167.5 -64.5zM690 995q-50 0 -95 -37.5t-81 -97.5t-62 -134.5t-38 -147.5h18q76 0 141.5 20t114 57.5t76 89.5t27.5 117q0 63 -26.5 98t-74.5 35z M634 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM1062 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="igrave" unicode="ì" horiz-adv-x="725" d="M621 1098l-142 -666q-12 -57 -20 -104q-8 -49 -8 -92q0 -45 18.5 -69t52.5 -24q32 0 59 12t62 35l49 -69q-24 -26 -55 -51.5t-70 -45.5t-85.5 -32t-102.5 -12q-118 0 -181 55.5t-63 154.5q0 44 8 105q7 53 25 139l80 381q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45 t-19 26t-33.5 12t-49.5 3h-37l18 109h486zM457 1241q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="iacute" unicode="í" horiz-adv-x="725" d="M621 1098l-142 -666q-12 -57 -20 -104q-8 -49 -8 -92q0 -45 18.5 -69t52.5 -24q32 0 59 12t62 35l49 -69q-24 -26 -55 -51.5t-70 -45.5t-85.5 -32t-102.5 -12q-118 0 -181 55.5t-63 154.5q0 44 8 105q7 53 25 139l80 381q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45 t-19 26t-33.5 12t-49.5 3h-37l18 109h486zM345 1268q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="725" d="M621 1098l-142 -666q-12 -57 -20 -104q-8 -49 -8 -92q0 -45 18.5 -69t52.5 -24q32 0 59 12t62 35l49 -69q-24 -26 -55 -51.5t-70 -45.5t-85.5 -32t-102.5 -12q-118 0 -181 55.5t-63 154.5q0 44 8 105q7 53 25 139l80 381q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45 t-19 26t-33.5 12t-49.5 3h-37l18 109h486zM69 1268l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="725" d="M621 1098l-142 -666q-12 -57 -20 -104q-8 -49 -8 -92q0 -45 18.5 -69t52.5 -24q32 0 59 12t62 35l49 -69q-24 -26 -55 -51.5t-70 -45.5t-85.5 -32t-102.5 -12q-118 0 -181 55.5t-63 154.5q0 44 8 105q7 53 25 139l80 381q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45 t-19 26t-33.5 12t-49.5 3h-37l18 109h486zM355 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM783 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39 q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="eth" unicode="ð" horiz-adv-x="1260" d="M82 410q0 63 16.5 135t49.5 143t83 137t118 116t153.5 80t189.5 30q51 0 98.5 -15t79.5 -41q-14 81 -46.5 146t-82.5 119l-321 -150l29 143l194 90q-48 35 -102 59.5t-113 43.5l39 125q91 -22 177.5 -59t164.5 -91l305 140l-31 -146l-170 -78q59 -56 108 -122t84 -144.5 t54 -170.5t19 -200q0 -89 -17.5 -177t-53 -168t-89.5 -148.5t-128 -119t-168.5 -79t-209.5 -28.5q-95 0 -174 26.5t-136 79.5t-88.5 134t-31.5 190zM393 393q0 -69 11.5 -117.5t33 -78.5t52.5 -44t69 -14q55 0 99 25.5t78 68t58.5 97.5t40 114t22.5 117.5t7 108.5 q0 125 -42.5 182t-121.5 57q-56 0 -100.5 -25.5t-78.5 -68t-58 -96.5t-39.5 -111.5t-23 -113.5t-7.5 -101z" />-<glyph glyph-name="ntilde" unicode="ñ" horiz-adv-x="1376" d="M800 190q0 88 33 244l33 162l10 49l12 60.5t10.5 63t4.5 56.5q0 19 -3.5 40t-13 38t-26 28t-43.5 11q-35 0 -69.5 -23.5t-66.5 -62t-61 -88t-52.5 -101.5t-40.5 -102t-26 -90l-104 -475h-307l172 815q3 13 5.5 27t4.5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-33.5 12 t-49.5 3h-37l18 109h455l-23 -219h13q39 61 80.5 106t89.5 74.5t104.5 44t124.5 14.5q65 0 109.5 -19t72 -51.5t39.5 -75t12 -89.5q0 -26 -3.5 -55.5t-9 -59.5t-12 -60t-11.5 -57l-46 -219q-12 -56 -20 -104.5t-8 -91.5q0 -45 18.5 -69t53.5 -24q32 0 58.5 12t61.5 35 l49 -69q-24 -26 -55 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-118 0 -181 55.5t-63 154.5zM995 1436q26 0 45 9t32.5 24t22 34.5t13.5 40.5h123q-11 -49 -33.5 -102.5t-56 -98t-78 -73.5t-99.5 -29t-99 20t-81 44.5l-69.5 44.5t-65.5 20q-21 0 -40 -9t-34 -24t-25 -34.5 t-14 -40.5h-122q9 46 32.5 99.5t59.5 98.5t82.5 75t101.5 30q54 0 96.5 -20t78 -44.5l67 -44.5t63.5 -20z" />-<glyph glyph-name="ograve" unicode="ò" horiz-adv-x="1266" d="M82 410q0 77 18 159t54.5 161t91.5 149.5t129.5 123.5t169 84t209.5 31q88 0 166 -24.5t136 -76.5t92 -133.5t34 -195.5q0 -74 -17 -155t-52.5 -159.5t-90 -150t-128.5 -125.5t-168 -86t-210 -32q-96 0 -176 26.5t-137 80t-89 134.5t-32 189zM553 127q55 0 99.5 31.5 t80 83t61.5 117.5t42.5 136t25 137.5t8.5 121.5q0 121 -41.5 174t-113.5 53q-52 0 -96 -30t-79.5 -80t-62.5 -114.5t-45.5 -133.5t-27.5 -137.5t-9 -125.5q0 -125 42 -179t116 -54zM758 1241q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80 t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="oacute" unicode="ó" horiz-adv-x="1266" d="M82 410q0 77 18 159t54.5 161t91.5 149.5t129.5 123.5t169 84t209.5 31q88 0 166 -24.5t136 -76.5t92 -133.5t34 -195.5q0 -74 -17 -155t-52.5 -159.5t-90 -150t-128.5 -125.5t-168 -86t-210 -32q-96 0 -176 26.5t-137 80t-89 134.5t-32 189zM553 127q55 0 99.5 31.5 t80 83t61.5 117.5t42.5 136t25 137.5t8.5 121.5q0 121 -41.5 174t-113.5 53q-52 0 -96 -30t-79.5 -80t-62.5 -114.5t-45.5 -133.5t-27.5 -137.5t-9 -125.5q0 -125 42 -179t116 -54zM674 1268q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5 t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="ocircumflex" unicode="ô" horiz-adv-x="1266" d="M82 410q0 77 18 159t54.5 161t91.5 149.5t129.5 123.5t169 84t209.5 31q88 0 166 -24.5t136 -76.5t92 -133.5t34 -195.5q0 -74 -17 -155t-52.5 -159.5t-90 -150t-128.5 -125.5t-168 -86t-210 -32q-96 0 -176 26.5t-137 80t-89 134.5t-32 189zM553 127q55 0 99.5 31.5 t80 83t61.5 117.5t42.5 136t25 137.5t8.5 121.5q0 121 -41.5 174t-113.5 53q-52 0 -96 -30t-79.5 -80t-62.5 -114.5t-45.5 -133.5t-27.5 -137.5t-9 -125.5q0 -125 42 -179t116 -54zM408 1268l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68 l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="otilde" unicode="õ" horiz-adv-x="1266" d="M82 410q0 77 18 159t54.5 161t91.5 149.5t129.5 123.5t169 84t209.5 31q88 0 166 -24.5t136 -76.5t92 -133.5t34 -195.5q0 -74 -17 -155t-52.5 -159.5t-90 -150t-128.5 -125.5t-168 -86t-210 -32q-96 0 -176 26.5t-137 80t-89 134.5t-32 189zM553 127q55 0 99.5 31.5 t80 83t61.5 117.5t42.5 136t25 137.5t8.5 121.5q0 121 -41.5 174t-113.5 53q-52 0 -96 -30t-79.5 -80t-62.5 -114.5t-45.5 -133.5t-27.5 -137.5t-9 -125.5q0 -125 42 -179t116 -54zM958 1436q26 0 45 9t32.5 24t22 34.5t13.5 40.5h123q-11 -49 -33.5 -102.5t-56 -98 t-78 -73.5t-99.5 -29t-99 20t-81 44.5l-69.5 44.5t-65.5 20q-21 0 -40 -9t-34 -24t-25 -34.5t-14 -40.5h-122q9 46 32.5 99.5t59.5 98.5t82.5 75t101.5 30q54 0 96.5 -20t78 -44.5l67 -44.5t63.5 -20z" />-<glyph glyph-name="odieresis" unicode="ö" horiz-adv-x="1266" d="M82 410q0 77 18 159t54.5 161t91.5 149.5t129.5 123.5t169 84t209.5 31q88 0 166 -24.5t136 -76.5t92 -133.5t34 -195.5q0 -74 -17 -155t-52.5 -159.5t-90 -150t-128.5 -125.5t-168 -86t-210 -32q-96 0 -176 26.5t-137 80t-89 134.5t-32 189zM553 127q55 0 99.5 31.5 t80 83t61.5 117.5t42.5 136t25 137.5t8.5 121.5q0 121 -41.5 174t-113.5 53q-52 0 -96 -30t-79.5 -80t-62.5 -114.5t-45.5 -133.5t-27.5 -137.5t-9 -125.5q0 -125 42 -179t116 -54zM690 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105 t90 39q49 0 80.5 -28t31.5 -85zM1118 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="divide" unicode="÷" d="M492 1120q0 70 32.5 97.5t81.5 27.5q24 0 45 -6.5t36.5 -21t24.5 -38.5t9 -59t-9 -58.5t-24.5 -38.5t-36.5 -21.5t-45 -6.5q-49 0 -81.5 28t-32.5 97zM492 344q0 70 32.5 97.5t81.5 27.5q24 0 45 -6.5t36.5 -21t24.5 -38.5t9 -59t-9 -58.5t-24.5 -38.5t-36.5 -21.5 t-45 -6.5q-49 0 -81.5 28t-32.5 97zM1044 659h-878v146h878v-146z" />-<glyph glyph-name="oslash" unicode="ø" horiz-adv-x="1266" d="M82 410q0 77 18 159t54.5 161t91.5 149.5t129.5 123.5t169 84t209.5 31q60 0 114.5 -11t102.5 -34l92 107h154l-146 -179q51 -52 81 -129.5t30 -183.5q0 -74 -17 -155t-52.5 -159.5t-90 -150t-128.5 -125.5t-168 -86t-210 -32q-137 0 -240 53l-94 -115h-155l153 188 q-48 54 -73 129.5t-25 174.5zM553 127q55 0 99.5 31.5t80 83t61.5 117.5t42.5 136t25 137.5t8.5 121.5v4l-450 -549q20 -43 53.5 -62.5t79.5 -19.5zM715 981q-52 0 -95.5 -29.5t-79 -78t-62.5 -112t-45 -131.5t-28 -135.5t-10 -125.5l443 542q-20 35 -51.5 52.5t-71.5 17.5z " />-<glyph glyph-name="ugrave" unicode="ù" horiz-adv-x="1378" d="M793 176q0 9 1 21t2.5 25t3 24.5t3.5 19.5h-17q-45 -64 -88.5 -116t-92.5 -89.5t-106 -58t-130 -20.5q-66 0 -111 18.5t-72 49.5t-39 72.5t-12 86.5q0 51 12 112l23 113l74 361q8 42 13 76t5 51q0 41 -25 54t-83 13h-37l18 109h492l-135 -613q-6 -24 -12 -54t-11 -60 t-8.5 -57t-3.5 -46q0 -45 19 -71.5t69 -26.5q45 0 92.5 40.5t91 105t77.5 144t52 156.5l109 482h305l-139 -666q-13 -56 -21 -104.5t-8 -91.5q0 -45 18.5 -69t53.5 -24q32 0 58.5 12t61.5 35l50 -69q-25 -26 -56 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-68 0 -113.5 15.5 t-73.5 42t-40 62t-12 76.5zM752 1241q-44 26 -93.5 66t-95.5 83.5t-84.5 85.5t-59.5 72l6 21h301q12 -37 31.5 -80t40.5 -84t42.5 -77t38.5 -60l-6 -27h-121z" />-<glyph glyph-name="uacute" unicode="ú" horiz-adv-x="1378" d="M793 176q0 9 1 21t2.5 25t3 24.5t3.5 19.5h-17q-45 -64 -88.5 -116t-92.5 -89.5t-106 -58t-130 -20.5q-66 0 -111 18.5t-72 49.5t-39 72.5t-12 86.5q0 51 12 112l23 113l74 361q8 42 13 76t5 51q0 41 -25 54t-83 13h-37l18 109h492l-135 -613q-6 -24 -12 -54t-11 -60 t-8.5 -57t-3.5 -46q0 -45 19 -71.5t69 -26.5q45 0 92.5 40.5t91 105t77.5 144t52 156.5l109 482h305l-139 -666q-13 -56 -21 -104.5t-8 -91.5q0 -45 18.5 -69t53.5 -24q32 0 58.5 12t61.5 35l50 -69q-25 -26 -56 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-68 0 -113.5 15.5 t-73.5 42t-40 62t-12 76.5zM688 1268q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="ucircumflex" unicode="û" horiz-adv-x="1378" d="M793 176q0 9 1 21t2.5 25t3 24.5t3.5 19.5h-17q-45 -64 -88.5 -116t-92.5 -89.5t-106 -58t-130 -20.5q-66 0 -111 18.5t-72 49.5t-39 72.5t-12 86.5q0 51 12 112l23 113l74 361q8 42 13 76t5 51q0 41 -25 54t-83 13h-37l18 109h492l-135 -613q-6 -24 -12 -54t-11 -60 t-8.5 -57t-3.5 -46q0 -45 19 -71.5t69 -26.5q45 0 92.5 40.5t91 105t77.5 144t52 156.5l109 482h305l-139 -666q-13 -56 -21 -104.5t-8 -91.5q0 -45 18.5 -69t53.5 -24q32 0 58.5 12t61.5 35l50 -69q-25 -26 -56 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-68 0 -113.5 15.5 t-73.5 42t-40 62t-12 76.5zM451 1268l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="udieresis" unicode="ü" horiz-adv-x="1378" d="M793 176q0 9 1 21t2.5 25t3 24.5t3.5 19.5h-17q-45 -64 -88.5 -116t-92.5 -89.5t-106 -58t-130 -20.5q-66 0 -111 18.5t-72 49.5t-39 72.5t-12 86.5q0 51 12 112l23 113l74 361q8 42 13 76t5 51q0 41 -25 54t-83 13h-37l18 109h492l-135 -613q-6 -24 -12 -54t-11 -60 t-8.5 -57t-3.5 -46q0 -45 19 -71.5t69 -26.5q45 0 92.5 40.5t91 105t77.5 144t52 156.5l109 482h305l-139 -666q-13 -56 -21 -104.5t-8 -91.5q0 -45 18.5 -69t53.5 -24q32 0 58.5 12t61.5 35l50 -69q-25 -26 -56 -51.5t-69.5 -45.5t-85.5 -32t-103 -12q-68 0 -113.5 15.5 t-73.5 42t-40 62t-12 76.5zM731 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM1159 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28 t31.5 -85z" />-<glyph glyph-name="yacute" unicode="ý" horiz-adv-x="1200" d="M160 881q-17 61 -49.5 84.5t-92.5 23.5h-20l25 109h401l135 -531q10 -40 21 -93.5l21 -107t17 -100t9 -71.5h6q61 82 115 165t94.5 161.5t64 149.5t23.5 130q0 69 -33.5 105t-93.5 36q0 40 12.5 72.5t34.5 55.5t52 35.5t65 12.5q83 0 125.5 -46t42.5 -128q0 -80 -27 -169 t-77 -189t-121.5 -212t-161.5 -237l-139 -191t-127.5 -157t-127 -122.5t-137 -88t-158 -53t-190.5 -17.5q-59 0 -114.5 10t-98.5 27l31 115q24 -8 67.5 -17.5t106.5 -9.5q94 0 172 25t144.5 67.5t125 99.5t113.5 122zM508 1268q28 29 61 67l65.5 78.5l63 80.5t54.5 75h321 l-6 -21q-16 -18 -44 -42.5t-63.5 -52.5l-76 -57.5l-82.5 -57.5l-83 -53.5t-77 -43.5h-139z" />-<glyph glyph-name="thorn" unicode="þ" horiz-adv-x="1276" d="M885 733q0 42 -5.5 81.5t-18 70.5t-34 50t-53.5 19q-34 0 -67.5 -19.5t-65 -52.5t-59 -76t-50 -89.5t-39 -93.5t-24.5 -88l-78 -367q9 -9 24 -19.5t34 -18.5t41.5 -13.5t46.5 -5.5q55 0 102.5 30t86 80t68.5 114.5t50 133.5t30.5 137.5t10.5 126.5zM506 825q35 64 72 118 t82 93t102 60.5t133 21.5q67 0 122.5 -24t94.5 -71t60.5 -116t21.5 -159q0 -74 -17.5 -159.5t-52.5 -171t-87.5 -164.5t-123.5 -139.5t-159.5 -97t-194.5 -36.5q-62 0 -115.5 12.5t-93.5 34.5q-1 -16 -4 -33q-2 -14 -5 -31.5t-7 -34.5l-29 -137q-3 -13 -5.5 -27t-4.5 -26.5 t-3 -21.5t-1 -13q0 -28 6 -45t19 -26t33.5 -12t49.5 -3h78l-18 -109h-520l376 1766l6 27t5 26.5t3 21.5t1 13q0 28 -6 45t-19 26t-34 12t-50 3h-47l19 108h497l-82 -389q-4 -19 -13 -48l-20 -62l-23.5 -68l-24 -66.5l-21 -57.5l-14.5 -40h14z" />-<glyph glyph-name="ydieresis" unicode="ÿ" horiz-adv-x="1200" d="M160 881q-17 61 -49.5 84.5t-92.5 23.5h-20l25 109h401l135 -531q10 -40 21 -93.5l21 -107t17 -100t9 -71.5h6q61 82 115 165t94.5 161.5t64 149.5t23.5 130q0 69 -33.5 105t-93.5 36q0 40 12.5 72.5t34.5 55.5t52 35.5t65 12.5q83 0 125.5 -46t42.5 -128q0 -80 -27 -169 t-77 -189t-121.5 -212t-161.5 -237l-139 -191t-127.5 -157t-127 -122.5t-137 -88t-158 -53t-190.5 -17.5q-59 0 -114.5 10t-98.5 27l31 115q24 -8 67.5 -17.5t106.5 -9.5q94 0 172 25t144.5 67.5t125 99.5t113.5 122zM556 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5 q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM984 1417q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="2030" d="M1001 1485q47 0 96.5 -6t92.5 -17h915l-71 -381h-146q1 7 2.5 25l3 37.5t3 36t1.5 20.5q0 28 -7.5 53t-25 44t-45 29.5t-67.5 10.5h-272l-109 -512h465l-27 -123h-464l-123 -577h323q48 0 86 13.5t66 36.5t48 53.5t32 64.5l32 88h146l-94 -381h-969q-45 -11 -93.5 -17 t-99.5 -6q-121 0 -225.5 36.5t-181 108.5t-120.5 178t-44 245q0 98 24.5 206t73.5 212.5t122 199t169.5 166t217.5 114t265 42.5zM741 113q45 0 86 8.5t78 28.5l244 1153q-35 21 -85 35t-106 14q-85 0 -154.5 -41t-124.5 -109.5t-96 -157t-67.5 -184t-39.5 -190t-13 -174.5 q0 -101 21.5 -173.5t59 -119t88.5 -68.5t109 -22z" />-<glyph glyph-name="oe" unicode="œ" horiz-adv-x="1845" d="M1368 135q50 0 95 14.5t83 38t69 53t52 60.5q12 -15 19.5 -38.5t7.5 -49.5q0 -37 -24 -78t-73.5 -75.5t-126.5 -57t-182 -22.5q-117 0 -208.5 40t-147.5 121q-74 -72 -177 -116.5t-239 -44.5q-96 0 -176 26t-137 79t-89 132t-32 186q0 76 18 158.5t54.5 162t92 151 t130.5 125.5t169.5 86t209.5 32t203.5 -38t138.5 -122q80 75 186 119.5t242 44.5q146 0 227.5 -63.5t81.5 -177.5q0 -83 -46 -159.5t-127 -135t-193 -93t-244 -34.5h-37t-39 2q-3 -20 -3.5 -40.5t-0.5 -37.5q0 -119 55.5 -183.5t167.5 -64.5zM553 127q55 0 100 32t80 84.5 t61.5 119.5t43.5 137t25.5 137.5t8.5 120.5q0 120 -41.5 171.5t-113.5 51.5q-52 0 -96.5 -30.5t-80 -81t-63 -116t-45.5 -135t-27.5 -138t-9.5 -124.5q0 -62 11 -105.5t31.5 -71t49.5 -40t66 -12.5zM1440 999q-33 0 -64.5 -17.5t-59.5 -48t-52 -71.5t-44 -88t-34.5 -97 t-22.5 -99h19q76 0 141.5 21t113.5 58.5t75.5 90.5t27.5 118q0 63 -26 98t-74 35z" />-<glyph glyph-name="Ydieresis" unicode="Ÿ" horiz-adv-x="1419" d="M227 0l23 109h55q32 0 62 4.5t55 18t43 37.5t27 64l59 285l-221 727q-9 30 -18.5 51t-22.5 33.5t-32.5 18.5t-49.5 6h-27l23 108h665l-22 -108h-92q-47 0 -66.5 -16t-19.5 -44q0 -18 6 -52t18 -81l74 -289l15 -64t14.5 -68t11 -66.5t6.5 -57.5q19 41 58 104t92 138 l202 289q25 35 43.5 76t18.5 75q0 28 -28.5 42t-96.5 14h-43l24 108h537l-23 -108h-38q-23 0 -42.5 -6t-39.5 -21.5t-42.5 -41t-50.5 -64.5l-507 -705l-62 -291q-2 -11 -5 -25t-3 -22q0 -22 11 -35.5t31 -21t47.5 -10t59.5 -2.5h50l-23 -109h-756zM919 1755q0 -40 -11 -67 t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85zM1347 1755q0 -40 -11 -67t-28 -44t-39 -24.5t-44 -7.5q-51 0 -82 27.5t-31 84.5q0 66 33 105t90 39q49 0 80.5 -28t31.5 -85z" />-<glyph glyph-name="circumflex" unicode="ˆ" horiz-adv-x="1182" d="M330 1268l68 66.5l78 77.5l78 80.5t67 76.5h276q13 -32 33 -72l42.5 -81l44.5 -80t40 -68l-6 -27h-129l-42 40l-49 48l-49.5 50t-42.5 46l-61 -46l-69 -50l-68 -48l-58 -40h-159z" />-<glyph glyph-name="tilde" unicode="˜" horiz-adv-x="1182" d="M905 1436q26 0 45 9t32.5 24t22 34.5t13.5 40.5h123q-11 -49 -33.5 -102.5t-56 -98t-78 -73.5t-99.5 -29t-99 20t-81 44.5l-69.5 44.5t-65.5 20q-21 0 -40 -9t-34 -24t-25 -34.5t-14 -40.5h-122q9 46 32.5 99.5t59.5 98.5t82.5 75t101.5 30q54 0 96.5 -20t78 -44.5 l67 -44.5t63.5 -20z" />-<glyph glyph-name="endash" unicode="–" horiz-adv-x="1024" d="M1018 477h-1043l29 146h1045z" />-<glyph glyph-name="emdash" unicode="—" horiz-adv-x="2048" d="M2042 477h-2067l29 146h2069z" />-<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="573" d="M231 1028q0 78 28.5 148t85 127t141 98.5t196.5 62.5l-23 -108q-210 -50 -210 -170q0 -22 8.5 -37t21 -27.5t27.5 -24.5t27.5 -27.5t21 -36t8.5 -50.5q0 -33 -12.5 -59t-33.5 -44.5t-48.5 -28t-58.5 -9.5q-37 0 -69.5 12.5t-57 36t-38.5 58t-14 79.5z" />-<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="573" d="M629 1278q0 -78 -28.5 -148t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5z" />-<glyph glyph-name="quotesinglbase" unicode="‚" horiz-adv-x="602" d="M428 127q0 -78 -28.5 -148t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5z" />-<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="1001" d="M231 1028q0 78 28.5 148t85 127t141 98.5t196.5 62.5l-23 -108q-210 -50 -210 -170q0 -22 8.5 -37t21 -27.5t27.5 -24.5t27.5 -27.5t21 -36t8.5 -50.5q0 -33 -12.5 -59t-33.5 -44.5t-48.5 -28t-58.5 -9.5q-37 0 -69.5 12.5t-57 36t-38.5 58t-14 79.5zM659 1028 q0 78 28.5 148t85 127t141 98.5t196.5 62.5l-23 -108q-210 -50 -210 -170q0 -22 8.5 -37t21 -27.5t27.5 -24.5t27.5 -27.5t21 -36t8.5 -50.5q0 -33 -12.5 -59t-33.5 -44.5t-48.5 -28t-58.5 -9.5q-37 0 -69.5 12.5t-57 36t-38.5 58t-14 79.5z" />-<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="1001" d="M629 1278q0 -78 -28.5 -148t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5zM1055 1278q0 -78 -28.5 -148 t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5z" />-<glyph glyph-name="quotedblbase" unicode="„" horiz-adv-x="1001" d="M428 127q0 -78 -28.5 -148t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5zM854 127q0 -78 -28.5 -148 t-85 -127t-141 -98.5t-196.5 -62.5l23 108q211 50 211 170q0 21 -8.5 36.5t-21.5 28t-27.5 24.5t-27.5 27.5t-21.5 36t-8.5 50.5q0 33 12.5 59t33.5 44.5t49 28t59 9.5q37 0 69.5 -12.5t56.5 -36t38 -58t14 -79.5z" />-<glyph glyph-name="bullet" unicode="•" horiz-adv-x="819" d="M760 766q0 -101 -27.5 -169.5t-72 -111t-100 -61t-111.5 -18.5q-65 0 -118.5 17.5t-92 53t-59.5 89t-21 126.5q0 81 22 148t62.5 114t98 73t128.5 26q62 0 115.5 -17.5t92.5 -53t61 -89.5t22 -127z" />-<glyph glyph-name="ellipsis" unicode="…" horiz-adv-x="1874" d="M414 164q0 -51 -14.5 -85.5t-37.5 -56t-52 -31t-58 -9.5q-69 0 -111.5 35t-42.5 106q0 83 44 132.5t118 49.5q32 0 60 -9t49 -26.5t33 -44t12 -61.5zM1038 164q0 -51 -14.5 -85.5t-37.5 -56t-51.5 -31t-57.5 -9.5q-70 0 -112 35t-42 106q0 83 43.5 132.5t118.5 49.5 q32 0 60 -9t48.5 -26.5t32.5 -44t12 -61.5zM1661 166q0 -51 -14.5 -85.5t-37.5 -56t-52 -31t-58 -9.5q-69 0 -111 35t-42 106q0 84 43.5 133t117.5 49q32 0 60 -9t49 -26.5t33 -44t12 -61.5z" />-<glyph glyph-name="guilsinglleft" unicode="‹" horiz-adv-x="723" d="M147 623l385 340h144l-293 -410l119 -410h-144l-233 373z" />-<glyph glyph-name="guilsinglright" unicode="›" horiz-adv-x="723" d="M573 485l-385 -342h-143l295 410l-121 410h143l234 -371z" />-<glyph glyph-name="Euro" unicode="€" d="M707 133q51 0 92 13.5t74.5 36.5t60 53t49.5 63q12 -12 24.5 -31.5t12.5 -54.5q0 -36 -24.5 -77t-74 -75.5t-124 -57.5t-174.5 -23q-98 0 -182 27.5t-146 84.5t-97.5 144.5t-35.5 207.5q0 26 0.5 49.5t3.5 49.5h-121l27 127h106q3 20 10.5 54t18.5 73h-107l27 127h117 q54 160 125 266.5t155.5 170.5t180 91t196.5 27q89 0 155.5 -18t110 -48.5t65 -70.5t21.5 -85q0 -89 -70.5 -138.5t-201.5 -49.5q0 51 -5.5 101t-20.5 90t-41 65t-66 25q-41 0 -82 -20t-80.5 -69t-75.5 -131t-67 -206h377l-27 -127h-385q-11 -37 -18 -73.5t-9 -53.5h301 l-26 -127h-291q-3 -25 -3.5 -54t-0.5 -51q0 -145 63.5 -225t182.5 -80z" />-<glyph glyph-name="trademark" unicode="™" horiz-adv-x="1710" d="M1459 754v55q35 0 56 10t24 45v457l-232 -567h-71l-232 569v-451q0 -41 21 -52t61 -11v-55h-248v55h21q31 0 54.5 10t25.5 47v482q-1 19 -7.5 30.5t-17.5 17.5t-25.5 7.5t-29.5 1.5h-21v57h236l225 -567l232 567h231v-57h-22q-17 0 -31.5 -2t-25 -8t-16 -18.5t-5.5 -33.5 v-471q0 -21 5.5 -33t16 -19t25 -9t31.5 -2h22v-55h-303zM560 872q0 -21 6.5 -33t17 -19t25 -9t29.5 -2h32v-55h-348v55h35q15 0 29 2t24.5 8t16.5 17.5t6 29.5v531h-90q-22 -1 -37 -6.5t-24 -15.5t-14 -22.5t-7 -27.5l-8 -49h-60l6 186h598l7 -186h-60l-8 49q-4 29 -21 50 t-61 22h-94v-525z" />-</font>-</defs></svg>
− extra/fonts/DroidSerif-BoldItalic.ttf
binary file changed (43996 → absent bytes)
− extra/fonts/DroidSerif-BoldItalic.woff
binary file changed (28364 → absent bytes)
− extra/fonts/DroidSerif-Italic.eot
binary file changed (38050 → absent bytes)
− extra/fonts/DroidSerif-Italic.svg
@@ -1,223 +0,0 @@-<?xml version="1.0" standalone="no"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >-<svg xmlns="http://www.w3.org/2000/svg">-<defs>-<font id="DroidSerif-Italic" horiz-adv-x="1145" >-<font-face font-family="Droid Serif" font-weight="400" font-style="italic" font-stretch="normal" units-per-em="2048" panose-1="2 2 6 0 6 5 0 9 2 0" ascent="1638" descent="-410" x-height="1098" cap-height="1462" bbox="-332 -492 2306 1907" underline-thickness="102" underline-position="-103" slope="-12" unicode-range="U+0020-U+2122"/>-<missing-glyph horiz-adv-x="532" />-<glyph glyph-name=".notdef" horiz-adv-x="532" />-<glyph glyph-name=".null" horiz-adv-x="0" />-<glyph glyph-name="nonmarkingreturn" horiz-adv-x="682" />-<glyph glyph-name="space" unicode=" " horiz-adv-x="532" />-<glyph glyph-bame="tab" unicode="	" horiz-adv-x="532" />-<glyph glyph-bame="uni00A0" unicode=" " horiz-adv-x="532" />-<glyph glyph-name="exclam" unicode="!" horiz-adv-x="682" d="M410 1462h237l-295 -1050h-94zM250 -16q-127 0 -127 125q0 71 36.5 114t98.5 43q127 0 127 -125q0 -73 -36.5 -115t-98.5 -42z" />-<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="836" d="M694 1462h217l-163 -481h-95zM309 1462h217l-164 -481h-94z" />-<glyph glyph-name="numbersign" unicode="#" d="M1038 537l-14 -121h-258l-121 -416h-123l121 416h-285l-120 -416h-123l121 416h-168l14 121h190l119 401h-244l13 121h266l117 403h125l-119 -403h285l118 403h123l-119 -403h160l-12 -121h-182l-117 -401h233zM397 537h285l117 401h-285z" />-<glyph glyph-name="dollar" unicode="$" d="M412 76q-170 12 -266.5 88t-96.5 188q0 77 50.5 122.5t107.5 45.5q0 -135 60.5 -227.5t164.5 -114.5l107 502q-271 135 -271 350q0 167 111.5 264t314.5 107l33 155h102l-32 -155q295 -26 295 -205q0 -141 -166 -141q0 220 -150 254l-104 -492l22 -12q185 -101 235 -174 t50 -162q0 -168 -123.5 -275t-343.5 -120l-49 -236h-103zM580 864l94 447q-215 -36 -215 -252q0 -119 121 -195zM633 635l-98 -461q116 10 182.5 79t66.5 171q0 132 -151 211z" />-<glyph glyph-name="percent" unicode="%" horiz-adv-x="1835" d="M565 1481q273 0 273 -326q0 -207 -120.5 -393.5t-318.5 -186.5q-125 0 -194.5 83.5t-69.5 242.5q0 216 118 398t312 182zM297 870q0 -211 111 -211t185.5 177.5t74.5 351.5q0 211 -111 211t-185.5 -177t-74.5 -352zM494 0h-152l1028 1462h143zM1470 889q273 0 273 -326 q0 -207 -120.5 -393t-317.5 -186q-265 0 -265 325q0 216 118 398t312 182zM1202 279q0 -211 111 -211t185.5 176.5t74.5 351.5q0 211 -111 211t-185.5 -176.5t-74.5 -351.5z" />-<glyph glyph-name="ampersand" unicode="&" horiz-adv-x="1520" d="M1096 0l-123 170q-185 -190 -453 -190q-211 0 -329.5 104.5t-118.5 277.5q0 159 96 269t334 198q-99 167 -99 301q0 170 111.5 261.5t325.5 91.5q166 0 256 -72t90 -194q0 -133 -75 -215t-372 -189l287 -393q87 164 129 362l16 80h369l-18 -86h-19q-102 0 -148 -30.5 t-66.5 -59t-102.5 -199.5q-39 -81 -90 -161l112 -154q63 -86 201 -86h18l-18 -86h-313zM682 895q173 65 245 130.5t72 176.5q0 81 -47.5 130.5t-126.5 49.5q-225 0 -225 -237q0 -114 82 -250zM909 258l-348 483q-160 -73 -223.5 -155.5t-63.5 -218.5q0 -119 71.5 -196 t195.5 -77q212 0 368 164z" />-<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="451" d="M301 1462h217l-164 -481h-94z" />-<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="709" d="M469 -168l-20 -94q-363 159 -363 643q0 413 198.5 746t551.5 429l-21 -92q-283 -154 -409.5 -517.5t-126.5 -661.5q0 -321 190 -453z" />-<glyph glyph-name="parenright" unicode=")" horiz-adv-x="709" d="M266 1446l21 94q362 -158 362 -643q0 -415 -200 -748.5t-549 -427.5l20 93q284 153 410.5 519.5t126.5 659.5q0 320 -191 453z" />-<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="1024" d="M281 1354l104 143l266 -260l17 330l174 -37l-123 -305l350 123l37 -172l-361 -27l318 -170l-102 -139l-271 252l-12 -328l-174 37l119 305l-349 -125l-36 172l358 29z" />-<glyph glyph-name="plus" unicode="+" d="M649 672v-379h-123v379h-376v121h376v378h123v-378h379v-121h-379z" />-<glyph glyph-name="comma" unicode="," horiz-adv-x="512" d="M-57 -299l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 35 88t92 33q69 0 114 -45.5t45 -122.5q0 -150 -95 -253.5t-275 -139.5z" />-<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="635" d="M29 481l32 154h533l-33 -154h-532z" />-<glyph glyph-name="period" unicode="." horiz-adv-x="586" d="M217 -16q-127 0 -127 125q0 71 36.5 114t98.5 43q127 0 127 -125q0 -72 -36.5 -114.5t-98.5 -42.5z" />-<glyph glyph-name="slash" unicode="/" horiz-adv-x="590" d="M-61 -248h-129l841 1804h129z" />-<glyph glyph-name="zero" unicode="0" d="M696 1485q180 0 284.5 -123t104.5 -346q0 -394 -167 -716.5t-441 -322.5q-183 0 -289 131t-106 365q0 394 170 703t444 309zM494 90q178 0 285.5 295.5t107.5 669.5q0 319 -211 319q-179 0 -287 -297t-108 -663q0 -324 213 -324z" />-<glyph glyph-name="one" unicode="1" d="M872 1470l-264 -1245q-8 -38 -8 -57q0 -82 148 -82h110l-18 -86h-762l16 86h109q97 0 141 36.5t59 110.5l160 754q35 164 76 322h-8q-129 -127 -192 -170t-117 -43q-82 0 -82 110q140 34 335 158l166 106h131z" />-<glyph glyph-name="two" unicode="2" d="M-35 0l43 166l481 434q191 172 268 298t77 276q0 95 -51 150.5t-138 55.5q-236 0 -291 -309q-145 0 -145 131q0 114 123.5 197.5t322.5 83.5q185 0 286 -78t101 -221q0 -122 -87 -251.5t-339 -354.5l-460 -414h475q67 0 114.5 30.5t88.5 122.5l14 33h86l-82 -350h-887z " />-<glyph glyph-name="three" unicode="3" d="M362 705l21 104h66q174 0 286.5 107t112.5 278q0 186 -174 186q-228 0 -291 -305q-152 0 -152 131q0 119 127.5 198t323.5 79q174 0 275.5 -79t101.5 -214q0 -156 -110.5 -271t-301.5 -149q147 -15 227 -98.5t80 -210.5q0 -231 -159.5 -356t-403.5 -125q-197 0 -297 58.5 t-100 156.5q0 68 43 109.5t113 41.5q0 -112 67 -183t189 -71q146 0 239.5 93t93.5 253q0 127 -75.5 197t-212.5 70h-89z" />-<glyph glyph-name="four" unicode="4" d="M262 0l17 86h90q97 0 141 36.5t59 110.5l33 168h-631l19 84l839 977h197l-203 -946h254l-24 -115h-254l-35 -176q-8 -40 -8 -57q0 -82 147 -82h47l-18 -86h-670zM707 899q49 232 100 397q-85 -129 -180 -235l-465 -545h465z" />-<glyph glyph-name="five" unicode="5" d="M258 717l-70 14l220 731h684l-56 -309h-86q6 78 6 96q0 49 -94 49h-397l-135 -456q99 32 196 32q202 0 316 -100t114 -276q0 -228 -159.5 -373t-421.5 -145q-359 0 -359 204q0 127 154 127q7 -219 223 -219q165 0 257.5 103t92.5 288q0 132 -71.5 205.5t-190.5 73.5 q-110 0 -223 -45z" />-<glyph glyph-name="six" unicode="6" d="M360 782q152 107 302 107q162 0 254 -97.5t92 -261.5q0 -238 -134.5 -394t-365.5 -156q-173 0 -279 131.5t-106 363.5q0 413 198.5 710.5t501.5 297.5q146 0 230 -53t84 -132q0 -153 -179 -153q0 139 -35 189t-104 50q-308 0 -459 -602zM338 666q-29 -164 -29 -267 q0 -307 211 -307q124 0 204.5 120t80.5 306q0 266 -184 266q-137 0 -283 -118z" />-<glyph glyph-name="seven" unicode="7" d="M221 0l758 1298h-539q-112 0 -141 -104l-29 -102h-86l88 370h916l-12 -59l-801 -1403h-154z" />-<glyph glyph-name="eight" unicode="8" d="M426 748q-201 144 -201 339q0 187 126.5 291.5t363.5 104.5q174 0 275.5 -82.5t101.5 -216.5q0 -132 -80.5 -227.5t-276.5 -176.5q260 -151 260 -366q0 -209 -145 -321.5t-395 -112.5q-198 0 -316.5 98t-118.5 254q0 142 90 238t316 178zM637 829q272 116 272 340 q0 100 -56 155.5t-155 55.5q-125 0 -200.5 -74t-75.5 -196q0 -165 215 -281zM520 694q-303 -111 -303 -366q0 -115 71 -181.5t193 -66.5q144 0 232 76t88 209q0 106 -68 181.5t-213 147.5z" />-<glyph glyph-name="nine" unicode="9" d="M809 702q-134 -139 -313 -139q-159 0 -252.5 93t-93.5 247q0 250 157.5 415t382.5 165q173 0 274 -106t101 -298q0 -394 -188 -746.5t-519 -352.5q-286 0 -286 184q0 51 32 85t89 34q4 -93 52.5 -148t129.5 -55q142 0 243.5 145.5t190.5 476.5zM842 850q32 133 32 242 q0 278 -190 278q-135 0 -232.5 -144t-97.5 -329q0 -109 52.5 -165t140.5 -56q164 0 295 174z" />-<glyph glyph-name="colon" unicode=":" horiz-adv-x="588" d="M377 825q-127 0 -127 125q0 71 36.5 114.5t98.5 43.5q127 0 127 -125q0 -74 -36.5 -116t-98.5 -42zM193 -16q-127 0 -127 125q0 71 36.5 114t98.5 43q60 0 93.5 -34t33.5 -91q0 -73 -36.5 -115t-98.5 -42z" />-<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="586" d="M381 825q-127 0 -127 125q0 71 36.5 114.5t98.5 43.5q127 0 127 -125q0 -74 -36.5 -116t-98.5 -42zM37 -299l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 35 88t92 33q69 0 114.5 -46.5t45.5 -121.5q0 -151 -96.5 -254t-274.5 -139z" />-<glyph glyph-name="less" unicode="<" d="M150 696v72l878 473v-137l-688 -373l688 -369v-137z" />-<glyph glyph-name="equal" unicode="=" d="M1028 993v-121h-878v121h878zM1028 590v-121h-878v121h878z" />-<glyph glyph-name="greater" unicode=">" d="M150 225v137l688 369l-688 373v137l878 -473v-72z" />-<glyph glyph-name="question" unicode="?" horiz-adv-x="1024" d="M565 649l-51 -237h-125l64 303q415 154 415 444q0 100 -54 160.5t-144 60.5q-211 0 -254 -290q-148 0 -148 122q0 114 114.5 192.5t299.5 78.5q387 0 387 -340q0 -311 -504 -494zM406 -16q-127 0 -127 125q0 71 36.5 114t98.5 43q60 0 93.5 -34t33.5 -91 q0 -73 -36.5 -115t-98.5 -42z" />-<glyph glyph-name="at" unicode="@" horiz-adv-x="1886" d="M1135 344h-11q-97 -186 -276 -186q-139 0 -225 93t-86 257q0 218 141 396.5t381 178.5q114 0 192 -61l82 43h49l-104 -522q-14 -70 -14 -137q0 -63 33.5 -101.5t91.5 -38.5q101 0 182.5 152.5t81.5 390.5q0 255 -156 402t-424 147q-318 0 -548 -255.5t-230 -651.5 q0 -305 163 -470t447 -165q282 0 520 170l48 -74q-275 -203 -588 -203q-352 0 -552 194.5t-200 542.5q0 439 270 727.5t682 288.5q322 0 507.5 -179.5t185.5 -479.5q0 -278 -124.5 -461.5t-277.5 -183.5q-178 0 -241 186zM1182 938q-29 61 -115 61q-154 0 -247 -168 t-93 -352q0 -108 43.5 -160.5t112.5 -52.5q172 0 221 256z" />-<glyph glyph-name="A" unicode="A" horiz-adv-x="1444" d="M408 489l-123 -215q-39 -68 -39 -114q0 -74 114 -74h48l-17 -86h-506l17 86h39q55 0 92 28.5t98 131.5l713 1216h160l194 -1267q10 -64 35 -86.5t86 -22.5h27l-17 -86h-557l16 86h48q147 0 147 104q0 42 -4 70l-33 229h-538zM881 950q-31 218 -33 324q-47 -111 -160 -305 l-219 -377h463z" />-<glyph glyph-name="B" unicode="B" horiz-adv-x="1339" d="M-27 86h27q170 0 201 147l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h531q479 0 479 -307q0 -303 -334 -381l-2 -8q250 -50 250 -299q0 -225 -151 -346t-439 -121h-643zM530 817h158q365 0 365 311q0 232 -283 232h-123zM379 102h199q391 0 391 379q0 234 -287 234h-172 z" />-<glyph glyph-name="C" unicode="C" horiz-adv-x="1284" d="M1073 299q27 -19 27 -68q0 -98 -114 -174.5t-314 -76.5q-267 0 -416.5 143t-149.5 405q0 388 242 671.5t602 283.5q179 0 279 -61.5t100 -166.5q0 -73 -55 -116t-146 -43q0 278 -204 278q-253 0 -423.5 -275.5t-170.5 -602.5q0 -383 364 -383q237 0 379 186z" />-<glyph glyph-name="D" unicode="D" horiz-adv-x="1485" d="M-27 86h27q170 0 201 147l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h574q279 0 430 -144.5t151 -412.5q0 -392 -223 -648.5t-596 -256.5h-645zM557 104q296 0 468.5 227t172.5 597q0 432 -389 432h-162l-268 -1256h178z" />-<glyph glyph-name="E" unicode="E" horiz-adv-x="1276" d="M379 102h395q173 0 232 168l32 88h107l-90 -358h-1098l16 86h27q104 0 144.5 36.5t54.5 100.5l213 1006q6 28 6 49q0 48 -28 73t-116 25h-26l18 86h1032l-65 -358h-107l6 63q5 48 5 56q0 137 -146 137h-344l-117 -545h494l-20 -100h-494z" />-<glyph glyph-name="F" unicode="F" horiz-adv-x="1208" d="M-27 86h27q96 0 138 33t61 104l215 1014q8 38 8 57q0 82 -148 82h-26l18 86h1032l-65 -358h-107l4 36q1 19 3 36q4 34 4 47q0 137 -154 137h-336l-127 -592h494l-21 -100h-493l-92 -435q-7 -33 -7 -51q0 -96 142 -96h67l-16 -86h-637z" />-<glyph glyph-name="G" unicode="G" horiz-adv-x="1462" d="M1430 676l-19 -86h-8q-82 0 -120 -36.5t-54 -111.5l-78 -368q-217 -94 -463 -94q-280 0 -431 143.5t-151 404.5q0 407 250 681t631 274q204 0 318 -62t114 -159q0 -76 -61 -119t-156 -43q0 132 -67 203t-191 71q-253 0 -433.5 -261.5t-180.5 -616.5q0 -400 395 -400 q115 0 231 29l68 326q8 38 8 57q0 82 -147 82h-19l19 86h545z" />-<glyph glyph-name="H" unicode="H" horiz-adv-x="1624" d="M829 0l17 86h26q98 0 142 36.5t59 110.5l101 480h-666l-102 -488q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-596l16 86h27q99 0 142 37.5t59 109.5l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596l-18 -86h-27q-98 0 -141 -37t-58 -110l-88 -414h666l90 422q8 38 8 57 q0 82 -147 82h-27l19 86h596l-19 -86h-26q-98 0 -141 -37.5t-58 -109.5l-213 -1004q-8 -38 -8 -57q0 -82 147 -82h27l-19 -86h-596z" />-<glyph glyph-name="I" unicode="I" horiz-adv-x="752" d="M862 1462l-18 -86h-27q-98 0 -141 -37t-58 -110l-212 -1004q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-596l16 86h27q170 0 201 147l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596z" />-<glyph glyph-name="J" unicode="J" horiz-adv-x="731" d="M852 1462l-18 -86h-27q-98 0 -141 -37t-58 -110l-266 -1245q-54 -251 -171.5 -363.5t-320.5 -112.5q-91 0 -167 23l28 92q51 -18 133 -18q119 0 185 89t108 288l266 1255q9 42 9 57q0 82 -148 82h-26l18 86h596z" />-<glyph glyph-name="K" unicode="K" horiz-adv-x="1434" d="M-27 86h27q99 0 142 37.5t59 109.5l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596l-18 -86h-27q-98 0 -141 -37t-58 -110l-88 -414l-36 -151l528 485q154 141 154 184q0 45 -91 45l17 84h452l-16 -84q-53 0 -118 -35.5t-197 -156.5l-373 -338l248 -598 q68 -164 194 -164h6l-18 -86h-29q-162 0 -241 33.5t-127 156.5l-199 506l-211 -147l-67 -324q-9 -44 -9 -57q0 -82 148 -82h26l-18 -86h-596z" />-<glyph glyph-name="L" unicode="L" horiz-adv-x="1276" d="M-23 86h27q96 0 138 37.5t59 109.5l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596l-18 -86h-27q-97 0 -139 -34.5t-57 -104.5l-242 -1135h403q157 0 219 185l54 153h106l-106 -440h-1096z" />-<glyph glyph-name="M" unicode="M" horiz-adv-x="1921" d="M1178 0l18 86h6q87 0 122 32.5t52 96.5l234 1094l-748 -1309h-110l-199 1309l-229 -1084q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-512l18 86h27q102 0 141.5 36t53.5 101l215 1014q8 38 8 57q0 82 -148 82h-26l18 86h465l174 -1167l670 1167h457l-19 -86h-26 q-98 0 -141 -37.5t-58 -109.5l-213 -1004q-8 -38 -8 -57q0 -82 147 -82h27l-19 -86h-544z" />-<glyph glyph-name="N" unicode="N" horiz-adv-x="1563" d="M1327 1237q8 38 8 57q0 82 -147 82h-27l19 86h514l-19 -86h-26q-98 0 -140.5 -37.5t-58.5 -109.5l-260 -1229h-133l-527 1200l-206 -975q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-512l18 86h27q96 0 138 37.5t59 109.5l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h373 l496 -1130z" />-<glyph glyph-name="O" unicode="O" horiz-adv-x="1520" d="M926 1485q238 0 384 -148t146 -415q0 -351 -228 -648t-585 -297q-243 0 -390 153.5t-147 414.5q0 352 230 646t590 294zM655 90q255 0 415.5 282.5t160.5 604.5q0 191 -84.5 294t-237.5 103q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5z" />-<glyph glyph-name="P" unicode="P" horiz-adv-x="1270" d="M-41 0l18 86h27q96 0 139 37t58 110l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h525q222 0 344 -103t122 -292q0 -233 -156.5 -365.5t-469.5 -132.5h-152l-73 -344q-9 -42 -9 -57q0 -82 148 -82h67l-18 -86h-635zM500 666h108q432 0 432 399q0 299 -299 299h-94z" />-<glyph glyph-name="Q" unicode="Q" horiz-adv-x="1520" d="M752 -14q9 -183 61.5 -265.5t159.5 -82.5q74 0 139 18l14 -86q-103 -33 -202 -33q-377 0 -394 451q-199 34 -311.5 183t-112.5 374q0 352 230 646t590 294q238 0 384 -148t146 -415q0 -311 -191 -598.5t-513 -337.5zM655 90q255 0 415.5 282.5t160.5 604.5 q0 191 -84.5 294t-237.5 103q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5z" />-<glyph glyph-name="R" unicode="R" horiz-adv-x="1325" d="M461 645l-90 -420q-9 -42 -9 -57q0 -82 148 -82h68l-19 -86h-635l19 86h26q102 0 141.5 36t53.5 101l215 1014q8 38 8 57q0 82 -147 82h-27l18 86h537q469 0 469 -348q0 -338 -379 -428l148 -438q36 -105 73 -133.5t95 -28.5h16l-16 -86h-27q-176 0 -249 46.5t-116 193.5 l-118 405h-203zM481 741h158q183 0 282 93.5t99 267.5q0 136 -60.5 199t-207.5 63h-140z" />-<glyph glyph-name="S" unicode="S" horiz-adv-x="1114" d="M172 428q0 -157 83 -252.5t228 -95.5q143 0 227.5 71t84.5 193q0 97 -48.5 164t-209.5 158q-164 95 -227.5 195t-63.5 226q0 177 134 286.5t363 109.5q178 0 284 -62t106 -159q0 -142 -181 -142q0 120 -57 190t-168 70q-122 0 -200 -70t-78 -188q0 -87 41.5 -150.5 t211.5 -162.5q161 -94 232.5 -187t71.5 -212q0 -203 -142 -316.5t-395 -113.5q-209 0 -332 82.5t-123 209.5q0 71 44.5 113.5t113.5 42.5z" />-<glyph glyph-name="T" unicode="T" horiz-adv-x="1255" d="M657 225q-8 -38 -8 -57q0 -82 148 -82h47l-19 -86h-637l19 86h47q103 0 143 35.5t54 101.5l241 1137h-196q-146 0 -205 -168l-29 -88h-106l86 358h1153l-66 -358h-106q10 80 10 125q0 131 -135 131h-199z" />-<glyph glyph-name="U" unicode="U" horiz-adv-x="1495" d="M205 1376l18 86h596l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-153 -723q-25 -118 -25 -191q0 -213 295 -213q166 0 263 74t135 246l174 815q8 37 8 57q0 82 -148 82h-26l18 86h514l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-172 -811q-93 -438 -552 -438 q-226 0 -345.5 92t-119.5 262q0 83 22 182l152 721q8 38 8 57q0 82 -148 82h-26z" />-<glyph glyph-name="V" unicode="V" horiz-adv-x="1382" d="M639 201q76 177 166 336l364 651q39 70 39 115q0 73 -114 73h-47l16 86h506l-19 -86h-39q-69 0 -103.5 -35t-84.5 -124l-682 -1217h-149l-175 1268q-8 61 -33.5 84.5t-88.5 23.5h-27l18 86h557l-16 -86h-47q-66 0 -107 -27.5t-41 -76.5q0 -35 5 -70l81 -665 q21 -172 21 -336z" />-<glyph glyph-name="W" unicode="W" horiz-adv-x="2140" d="M1915 1188q39 78 39 115q0 73 -115 73h-49l16 86h500l-18 -86h-39q-66 0 -103.5 -32t-85.5 -127l-604 -1217h-188l-92 1135l-551 -1135h-187l-106 1268q-5 55 -30 81.5t-93 26.5h-27l19 86h557l-19 -86h-47q-147 0 -147 -104q0 -42 4 -70l49 -655q14 -187 14 -346 q86 202 168 368l430 879h148l67 -887q15 -201 11 -360q90 209 153 336z" />-<glyph glyph-name="X" unicode="X" horiz-adv-x="1352" d="M1458 1376h-18q-56 0 -100.5 -30t-131.5 -123l-387 -428l246 -600q45 -109 141 -109h27l-18 -86h-553l18 86h23q61 0 96 20.5t35 51.5q0 42 -39 141l-133 326l-306 -340q-82 -91 -82 -144q0 -55 121 -55h6l-18 -86h-485l18 86h8q67 0 119.5 35t122.5 112l453 494 l-220 545q-42 104 -159 104h-27l18 86h555l-18 -86h-47q-96 0 -96 -57q0 -29 37 -123l116 -299l256 295q78 90 78 133q0 51 -98 51h-6l18 86h449z" />-<glyph glyph-name="Y" unicode="Y" horiz-adv-x="1280" d="M729 1462l-18 -86h-103q-84 0 -84 -55q0 -40 27 -119l92 -274q49 -146 55 -246q20 38 154 215l195 260q75 100 75 166q0 53 -98 53h-76l19 86h506l-19 -86h-39q-39 0 -77.5 -31.5t-108.5 -123.5l-477 -625l-80 -371q-8 -37 -8 -57q0 -82 147 -82h47l-18 -86h-637l18 86 h47q103 0 143 35.5t54 101.5l80 377l-238 668q-23 65 -45.5 86.5t-77.5 21.5h-26l18 86h553z" />-<glyph glyph-name="Z" unicode="Z" horiz-adv-x="1239" d="M1276 1378l-1032 -1276h547q152 0 206 168l29 88h107l-86 -358h-1082l17 82l1030 1278h-477q-151 0 -205 -168l-29 -88h-106l86 358h1011z" />-<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="735" d="M10 -262l387 1818h457l-18 -86h-88q-96 0 -139.5 -36t-59.5 -111l-291 -1360q-8 -37 -8 -57q0 -82 147 -82h88l-18 -86h-457z" />-<glyph glyph-name="backslash" unicode="\" horiz-adv-x="590" d="M231 1556h119l88 -1804h-121z" />-<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="737" d="M-96 -262l18 86h88q96 0 139 37t58 110l291 1360q8 37 8 58q0 81 -148 81h-88l19 86h456l-387 -1818h-454z" />-<glyph glyph-name="asciicircum" unicode="^" d="M552 1462h72l431 -917h-137l-330 729l-330 -729h-137z" />-<glyph glyph-name="underscore" unicode="_" horiz-adv-x="940" d="M772 -291h-958l26 121h959z" />-<glyph glyph-name="grave" unicode="`" horiz-adv-x="1182" d="M829 1241q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="a" unicode="a" horiz-adv-x="1186" d="M748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523t434.5 241q139 0 240 -74l90 52h66l-140 -656q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74 q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330z" />-<glyph glyph-name="b" unicode="b" horiz-adv-x="1151" d="M213 53l-92 -59h-66l271 1272q18 84 18 108q0 96 -143 96h-17l19 86h387l-98 -460q-21 -99 -74 -271h10q151 293 375 293q122 0 191 -94t69 -276q0 -285 -176 -526.5t-434 -241.5q-147 0 -240 73zM285 145q62 -73 159 -73q178 0 294 227t116 451q0 239 -129 239 q-112 0 -218.5 -155.5t-133.5 -282.5z" />-<glyph glyph-name="c" unicode="c" horiz-adv-x="997" d="M821 256q21 -13 21 -51q0 -82 -96.5 -153.5t-258.5 -71.5q-179 0 -289 113t-110 310q0 268 173 491.5t437 223.5q141 0 220 -56t79 -140q0 -62 -49.5 -103t-132.5 -41q0 109 -42 175.5t-116 66.5q-143 0 -249.5 -214t-106.5 -419q0 -278 225 -278q179 0 295 147z" />-<glyph glyph-name="d" unicode="d" horiz-adv-x="1186" d="M748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523t434.5 241q115 0 201 -49q16 94 23 115l20 98q14 69 14 92q0 96 -143 96h-16l18 86h377l-238 -1116q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122 q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330z" />-<glyph glyph-name="e" unicode="e" horiz-adv-x="1010" d="M821 256q21 -13 21 -51q0 -82 -96.5 -153.5t-258.5 -71.5q-179 0 -289 113t-110 310q0 268 173 491.5t437 223.5q130 0 201.5 -62t71.5 -173q0 -166 -172.5 -289t-421.5 -123h-35q-18 0 -37 2q-4 -28 -4 -86q0 -278 225 -278q175 0 295 147zM324 567h20q181 0 298.5 88 t117.5 228q0 137 -119 137q-99 0 -185 -124.5t-132 -328.5z" />-<glyph glyph-name="f" unicode="f" horiz-adv-x="651" d="M719 981h-230l-213 -997q-53 -247 -155 -361.5t-289 -114.5q-58 0 -119 17l19 94q51 -14 94 -14q99 0 156 85t102 292l215 999h-186l12 74l197 43l22 112q72 367 389 367q131 0 197.5 -41.5t66.5 -110.5q0 -133 -170 -133q0 191 -104 191q-75 0 -116.5 -62t-65.5 -192 l-27 -131h227z" />-<glyph glyph-name="g" unicode="g" horiz-adv-x="1139" d="M901 1053q97 145 221 145q103 0 103 -94q0 -127 -121 -127q0 74 -57 74q-40 0 -101 -47q45 -64 45 -158q0 -172 -129 -315.5t-340 -143.5q-47 0 -65 4q-146 -59 -146 -129q0 -51 105 -61l196 -21q318 -34 318 -268q0 -191 -144 -297.5t-411 -106.5q-447 0 -447 267 q0 110 89.5 187.5t244.5 107.5q-98 48 -98 141q0 63 40.5 107t153.5 102q-143 67 -143 242q0 173 130.5 314.5t344.5 141.5q131 0 211 -65zM545 485q117 0 188.5 116.5t71.5 254.5q0 168 -141 168q-120 0 -190.5 -117.5t-70.5 -253.5q0 -168 142 -168zM561 6l-199 19 q-15 1 -88.5 -20t-126.5 -78t-53 -140q0 -178 289 -178q180 0 274.5 66.5t94.5 179.5q0 134 -191 151z" />-<glyph glyph-name="h" unicode="h" horiz-adv-x="1227" d="M471 840q170 276 379 276q219 0 219 -227q0 -65 -37 -225l-53 -242q-27 -123 -27 -215q0 -98 72 -98q59 0 131 47l37 -60q-134 -116 -250 -116q-85 0 -135.5 55t-50.5 149t39 277l47 212q30 124 30 191q0 121 -94 121q-114 0 -234.5 -155.5t-152.5 -305.5l-110 -524h-191 l266 1266q19 90 19 108q0 96 -144 96h-16l18 86h377l-80 -376q-36 -168 -81 -340h22z" />-<glyph glyph-name="i" unicode="i" horiz-adv-x="623" d="M459 1303q-115 0 -115 112q0 65 33.5 104.5t89.5 39.5q115 0 115 -113q0 -70 -34.5 -106.5t-88.5 -36.5zM127 1012l18 86h367l-139 -658q-31 -147 -31 -227q0 -104 68 -104q59 0 147 53l37 -60q-142 -122 -277 -122q-76 0 -123 55t-47 139q0 92 46 322l79 376q7 33 7 54 q0 86 -125 86h-27z" />-<glyph glyph-name="j" unicode="j" horiz-adv-x="596" d="M461 1303q-115 0 -115 112q0 65 33.5 104.5t89.5 39.5q115 0 115 -113q0 -70 -34.5 -106.5t-88.5 -36.5zM-287 -475l19 94q51 -14 94 -14q103 0 161.5 91.5t98.5 287.5l188 888q7 33 7 54q0 86 -125 86h-27l18 86h367l-235 -1114q-52 -244 -155.5 -360t-291.5 -116 q-58 0 -119 17z" />-<glyph glyph-name="k" unicode="k" horiz-adv-x="1165" d="M694 786q151 131 151 193q0 31 -91 31l18 86h453l-19 -86q-119 0 -329 -191l-185 -170l187 -405q79 -172 208 -172l-18 -86q-170 0 -250 39.5t-135 171.5l-133 327l-186 -118l-84 -406h-191l266 1266q19 90 19 108q0 96 -144 96h-16l18 86h377l-80 -376 q-110 -517 -159 -674z" />-<glyph glyph-name="l" unicode="l" horiz-adv-x="623" d="M207 1470l18 86h387l-237 -1116q-31 -146 -31 -227q0 -104 68 -104q59 0 147 53l37 -60q-142 -122 -277 -122q-74 0 -121.5 54t-47.5 140q0 97 45 322l167 786q13 61 13 92q0 96 -144 96h-24z" />-<glyph glyph-name="m" unicode="m" horiz-adv-x="1835" d="M920 0h-195q0 46 26 212.5t44 248.5l47 212q30 124 30 191q0 121 -94 121q-114 0 -234.5 -155.5t-152.5 -305.5l-110 -524h-191l172 823q12 57 12 92q0 97 -143 97h-16l18 86h379l-55 -258h20q166 276 373 276q219 0 219 -227q0 -25 -4 -49h20q167 276 373 276 q219 0 219 -227q0 -65 -37 -225l-53 -242q-26 -119 -26 -215q0 -98 71 -98q59 0 131 47l37 -60q-130 -116 -250 -116q-84 0 -135 55t-51 149t39 277l35 160q43 197 43 243q0 121 -95 121q-105 0 -217 -134.5t-157 -281.5l-33 -147q-13 -56 -36 -219t-23 -203z" />-<glyph glyph-name="n" unicode="n" horiz-adv-x="1227" d="M281 0h-191l172 823q12 57 12 92q0 97 -143 97h-16l18 86h379l-55 -258h20q166 276 373 276q219 0 219 -227q0 -65 -37 -225l-53 -242q-27 -123 -27 -215q0 -98 72 -98q59 0 131 47l37 -60q-134 -116 -250 -116q-85 0 -135.5 55t-50.5 149t39 277l47 212q30 124 30 191 q0 121 -94 121q-114 0 -233.5 -154t-153.5 -307z" />-<glyph glyph-name="o" unicode="o" horiz-adv-x="1176" d="M698 1118q181 0 285 -109t104 -315q0 -273 -167 -493.5t-439 -220.5q-185 0 -289 112t-104 311q0 276 168.5 495.5t441.5 219.5zM504 80q169 0 269.5 200.5t100.5 444.5q0 285 -200 285q-167 0 -270 -201t-103 -447q0 -282 203 -282z" />-<glyph glyph-name="p" unicode="p" horiz-adv-x="1182" d="M389 -406l-18 -86h-385l272 1299q18 86 18 108q0 97 -143 97h-16l18 86h363l-49 -273h10q148 293 375 293q125 0 192.5 -95t67.5 -275q0 -275 -171.5 -521.5t-439.5 -246.5q-117 0 -200 47q-9 -66 -17 -99l-28 -125q-19 -85 -19 -114q0 -95 143 -95h27zM315 145 q66 -73 162 -73q171 0 289.5 223.5t118.5 454.5q0 239 -129 239q-106 0 -214 -147.5t-143 -306.5z" />-<glyph glyph-name="q" unicode="q" horiz-adv-x="1147" d="M735 309q-149 -329 -383 -329q-124 0 -194 98.5t-70 275.5q0 282 175.5 523t434.5 241q128 0 228 -55l50 28q48 27 52 27h72l-283 -1335q-12 -57 -12 -92q0 -97 141 -97h17l-19 -86h-373l86 410q8 39 91 391h-13zM864 952q-45 74 -155 74q-177 0 -294.5 -226t-117.5 -456 q0 -235 129 -235q101 0 212 148.5t150 332.5z" />-<glyph glyph-name="r" unicode="r" horiz-adv-x="958" d="M799 821q0 162 -82 162q-95 0 -201.5 -187t-157.5 -423l-77 -373h-191l172 823q12 57 12 92q0 97 -163 97h-17l19 86h362l-43 -295h21q82 183 162 249t186 66q168 0 168 -141q0 -156 -170 -156z" />-<glyph glyph-name="s" unicode="s" horiz-adv-x="950" d="M741 795q0 103 -48.5 165t-135.5 62q-92 0 -145.5 -49.5t-53.5 -126.5q0 -68 51 -116t158 -95q246 -110 246 -318q0 -151 -116 -244t-308 -93q-155 0 -246.5 62.5t-91.5 168.5q0 66 36.5 100.5t92.5 34.5q0 -127 61.5 -197.5t172.5 -70.5q221 0 221 190q0 73 -47 123.5 t-160 102.5q-147 70 -197.5 144.5t-50.5 172.5q0 134 109.5 219.5t285.5 85.5q151 0 235.5 -56t84.5 -138q0 -127 -154 -127z" />-<glyph glyph-name="t" unicode="t" horiz-adv-x="754" d="M616 154l35 -76q-138 -98 -276 -98q-223 0 -223 239q0 77 20 172l125 590h-156l19 82q200 0 313 287h94l-53 -252h248l-25 -117h-248l-124 -584q-25 -118 -25 -176q0 -112 109 -112q83 0 167 45z" />-<glyph glyph-name="u" unicode="u" horiz-adv-x="1227" d="M135 1098h381l-135 -613q-41 -186 -41 -247q0 -125 100 -125q105 0 226.5 151.5t158.5 323.5l107 510h198l-141 -658q-31 -145 -31 -227q0 -104 68 -104q58 0 131 45l37 -60q-130 -114 -260 -114q-77 0 -124.5 55t-47.5 139q0 53 10 121h-16q-111 -183 -198.5 -248 t-197.5 -65q-219 0 -219 227q0 65 37 225l80 359q18 81 18 122q0 97 -143 97h-16z" />-<glyph glyph-name="v" unicode="v" horiz-adv-x="1102" d="M197 903q-17 109 -142 109h-20l16 86h307l95 -606q36 -232 47 -363h6q153 147 265 343.5t112 315.5q0 72 -35 114t-92 42q0 74 40 119t99 45q139 0 139 -190q0 -186 -141.5 -435.5t-368.5 -480.5l-184 -20z" />-<glyph glyph-name="w" unicode="w" horiz-adv-x="1677" d="M246 -18l-15 882q-1 72 -28.5 110t-106.5 38h-20l28 86h308q6 -432 6 -934h8q267 469 457 915l170 8q43 -539 43 -937h14q167 205 276 405.5t109 318.5q0 94 -88 123q18 121 121 121q108 0 108 -153q0 -295 -514 -963l-202 -22l-31 886q-93 -221 -432 -860z" />-<glyph glyph-name="x" unicode="x" horiz-adv-x="1118" d="M-41 0l23 86h26q56 0 97.5 25.5t115.5 115.5l262 318l-133 319q-39 95 -64.5 121.5t-82.5 26.5h-27l17 86h272l156 -414l272 414h262l-33 -86h-26q-60 0 -100.5 -29t-112.5 -119l-215 -276l141 -355q36 -92 61.5 -119.5t85.5 -27.5h27l-16 -86h-275l-166 451l-307 -451 h-260z" />-<glyph glyph-name="y" unicode="y" horiz-adv-x="1081" d="M164 903q-18 60 -49 84.5t-92 24.5h-21l16 86h299l160 -553q74 -257 86 -371h6q277 421 277 680q0 111 -101 111q0 69 40 110t94 41q139 0 139 -172q0 -247 -276 -694.5t-442.5 -594.5t-438.5 -147q-108 0 -193 37l31 103q72 -23 160 -23q293 0 575 373z" />-<glyph glyph-name="z" unicode="z" horiz-adv-x="1047" d="M616 117q49 0 89.5 31t85.5 137l20 47h86l-80 -332h-819l16 82l697 899h-260q-71 0 -109.5 -34t-83.5 -132l-4 -8h-86l82 291h717l-17 -84l-698 -897h364z" />-<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="877" d="M676 -262q-139 0 -217 77t-78 218v356q0 210 -242 217v86q242 5 242 215v357q0 292 295 292h135v-88h-61q-168 0 -168 -215v-350q0 -214 -228 -252v-2q228 -39 228 -254v-354q0 -215 168 -215h61v-88h-135z" />-<glyph glyph-name="bar" unicode="|" d="M649 -492h-123v2048h123v-2048z" />-<glyph glyph-name="braceright" unicode="}" horiz-adv-x="877" d="M129 -174h61q168 0 168 215v354q0 215 228 254v2q-228 38 -228 252v350q0 215 -168 215h-61v88h135q295 0 295 -292v-357q0 -210 242 -215v-86q-242 -7 -242 -217v-356q0 -141 -78 -218t-217 -77h-135v88z" />-<glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="1149" d="M250 551h-121q28 358 258 358q94 0 248 -135q107 -102 168 -102q57 0 84 62t41 175h123q-39 -358 -258 -358q-97 0 -238 129q-118 108 -176 108q-60 0 -89 -58.5t-40 -178.5z" />-<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="682" d="M420 1112q127 0 127 -125q0 -71 -36.5 -114.5t-98.5 -43.5q-127 0 -127 125q0 74 36.5 116t98.5 42zM260 -367h-237l294 1051h95z" />-<glyph glyph-name="cent" unicode="¢" d="M496 182q-156 26 -240 136t-84 282q0 249 155 468.5t406 244.5l33 149h102l-32 -151q116 -11 180.5 -64.5t64.5 -128.5q0 -62 -49.5 -102.5t-132.5 -40.5q0 166 -88 221l-188 -891q169 6 282 148q21 -15 21 -52q0 -79 -88 -149t-242 -76l-37 -176h-102zM524 319l189 893 q-138 -25 -233 -232t-95 -396q0 -214 139 -265z" />-<glyph glyph-name="sterling" unicode="£" d="M530 690q7 -44 7 -108q0 -237 -258 -389l2 -9q84 37 157 37q60 0 179 -39q118 -39 159 -39q114 0 205 93l55 -68q-185 -188 -348 -188q-65 0 -189 46t-198 46q-114 0 -238 -60l-28 -14l-37 82l72 41q295 168 295 442q0 50 -15 127h-227l22 103h189q-27 126 -27 206 q0 226 135.5 355t364.5 129q155 0 247.5 -56t92.5 -145q0 -162 -170 -162q0 260 -201 260q-139 0 -214 -96.5t-75 -271.5q0 -80 29 -219h348l-22 -103h-312z" />-<glyph glyph-name="currency" unicode="¤" d="M283 952l-136 135l86 87l134 -136q99 72 221 72q116 0 217 -72l137 138l86 -89l-135 -135q72 -99 72 -219t-72 -219l135 -135l-84 -86l-137 135q-104 -70 -219 -70q-124 0 -219 70l-136 -135l-86 86l134 135q-68 99 -68 219q0 124 70 219zM588 471q108 0 185 77.5 t77 184.5q0 110 -76 187t-186 77q-108 0 -184 -77t-76 -187q0 -107 76.5 -184.5t183.5 -77.5z" />-<glyph glyph-name="yen" unicode="¥" horiz-adv-x="1104" d="M582 225q-9 -44 -9 -57q0 -82 148 -82h47l-18 -86h-629l18 86h47q104 0 144 36t53 101l29 139h-287l20 97h287l31 143h-287l21 96h247l-157 570q-16 58 -39 83t-84 25h-6l18 86h479l-18 -86h-4q-69 0 -105 -13t-36 -56t24 -131l53 -220q35 -146 43 -249q22 39 107 167 l170 250q92 135 92 193q0 59 -111 59h-6l19 86h417l-18 -86h-18q-46 0 -78 -23.5t-111 -135.5l-360 -519h254l-21 -96h-286l-31 -143h287l-21 -97h-287z" />-<glyph glyph-name="brokenbar" unicode="¦" d="M649 737h-123v819h123v-819zM649 -492h-123v820h123v-820z" />-<glyph glyph-name="section" unicode="§" horiz-adv-x="1114" d="M170 131q0 -120 67 -193t183 -73q125 0 202.5 66.5t77.5 174.5q0 65 -51.5 125t-240.5 162q-228 124 -228 330q0 166 180 278q-49 83 -49 185q0 168 123 269t314 101q143 0 233 -60t90 -144q0 -74 -37 -108t-129 -34q0 115 -49.5 182.5t-144.5 67.5q-100 0 -171 -56 t-71 -153q0 -80 41.5 -133.5t228.5 -154.5q250 -134 250 -318q0 -172 -178 -309q41 -76 41 -152q0 -183 -127 -301.5t-336 -118.5q-157 0 -252.5 63.5t-95.5 168.5q0 65 36.5 100t92.5 35zM406 944q-82 -60 -82 -145q0 -76 50 -130t187 -130q121 -67 199 -138q76 83 76 156 q0 123 -211 238q-145 79 -219 149z" />-<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1182" d="M514 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM903 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="copyright" unicode="©" horiz-adv-x="1731" d="M881 1485q309 0 531 -221.5t222 -532.5q0 -309 -221 -530t-532 -221q-312 0 -532 221t-220 530q0 311 221 532.5t531 221.5zM881 92q264 0 452.5 188t188.5 451q0 264 -188.5 452.5t-452.5 188.5q-265 0 -452 -189t-187 -452q0 -262 187 -450.5t452 -188.5zM1169 504 q29 -21 29 -64q0 -64 -83.5 -114t-223.5 -50q-194 0 -302 120t-108 337q0 210 117 331.5t322 121.5q132 0 206 -40t74 -106q0 -43 -39 -69.5t-100 -26.5q0 156 -146 156q-266 0 -266 -367q0 -177 69 -272.5t200 -95.5q170 0 251 139z" />-<glyph glyph-name="ordfeminine" unicode="ª" horiz-adv-x="805" d="M573 995h-8q-107 -213 -262 -213q-86 0 -133 60t-47 166q0 166 119.5 312t300.5 146q98 0 164 -43l63 29h45l-96 -379q-21 -83 -21 -131q0 -61 41 -61q35 0 88 32l23 -39q-93 -92 -178 -92q-113 0 -113 103q0 57 14 110zM629 1350q-29 41 -90 41q-102 0 -170 -125.5 t-68 -253.5q0 -133 70 -133q54 0 115.5 85.5t88.5 182.5z" />-<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="1053" d="M139 586l389 356h103l-295 -399l129 -379h-103l-237 356zM510 586l389 356h102l-294 -399l129 -379h-103l-237 356z" />-<glyph glyph-name="logicalnot" unicode="¬" d="M1028 793v-541h-123v420h-755v121h878z" />-<glyph glyph-name="uni00AD" unicode="­" horiz-adv-x="635" d="M29 481l32 154h533l-33 -154h-532z" />-<glyph glyph-name="registered" unicode="®" horiz-adv-x="1731" d="M881 1485q309 0 531 -221.5t222 -532.5q0 -309 -221 -530t-532 -221q-312 0 -532 221t-220 530q0 311 221 532.5t531 221.5zM881 92q264 0 452.5 188t188.5 451q0 264 -188.5 452.5t-452.5 188.5q-265 0 -452 -189t-187 -452q0 -262 187 -450.5t452 -188.5zM494 358h26 q101 0 101 72v600q0 72 -101 72h-26v72h368q352 0 352 -244q0 -164 -186 -225l182 -293q20 -33 40.5 -43.5t74.5 -10.5v-69h-217l-225 381h-109v-240q0 -72 100 -72h29v-69h-409v69zM774 748h86q103 0 148 40t45 140q0 91 -46 128.5t-153 37.5h-80v-346z" />-<glyph glyph-name="macron" unicode="¯" horiz-adv-x="940" d="M950 1556h-960v121h960v-121z" />-<glyph glyph-name="degree" unicode="°" horiz-adv-x="819" d="M481 1462q128 0 220 -91t92 -220q0 -127 -91 -218t-221 -91q-128 0 -218.5 90.5t-90.5 218.5q0 130 91.5 220.5t217.5 90.5zM481 963q79 0 134 55t55 133q0 80 -55.5 135t-133.5 55q-75 0 -130.5 -54.5t-55.5 -135.5q0 -78 55.5 -133t130.5 -55z" />-<glyph glyph-name="plusminus" unicode="±" d="M649 672v-379h-123v379h-376v121h376v378h123v-378h379v-121h-379zM1028 0h-878v121h878v-121z" />-<glyph glyph-name="uni00B2" unicode="²" horiz-adv-x="819" d="M41 586l10 61l318 262q111 91 166 175.5t55 197.5q0 119 -103 119q-62 0 -107.5 -53.5t-57.5 -141.5q-62 0 -97 27.5t-35 71.5q0 77 84.5 127.5t227.5 50.5q124 0 196 -54t72 -141q0 -97 -62.5 -181t-220.5 -210l-245 -195h282q77 0 109 84l16 43h70l-57 -243h-621z" />-<glyph glyph-name="uni00B3" unicode="³" horiz-adv-x="819" d="M197 842q0 -75 45 -125.5t120 -50.5q195 0 195 182q0 69 -49 111t-137 42h-68l16 84h68q97 0 162 62t65 158t-94 96q-136 0 -172 -178q-135 0 -135 86q0 73 84.5 123.5t228.5 50.5q131 0 204 -51t73 -136q0 -189 -262 -241l-2 -11q206 -27 206 -188q0 -133 -107.5 -208 t-289.5 -75q-130 0 -199 43t-69 115q0 111 117 111z" />-<glyph glyph-name="acute" unicode="´" horiz-adv-x="1182" d="M508 1268q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="uni00B5" unicode="µ" horiz-adv-x="1237" d="M223 100q-33 -170 -33 -247q0 -149 113 -166q-19 -179 -174 -179q-133 0 -133 148q0 91 61 310q87 314 125 495l135 637h193l-135 -641q-23 -109 -23 -189q0 -157 150 -157q106 0 188 90t113 241l139 656h193l-164 -766q-25 -117 -25 -158q0 -65 60 -65q44 0 112 34 l35 -69q-136 -94 -238 -94q-145 0 -153 196h-10q-133 -196 -297 -196q-169 0 -232 120z" />-<glyph glyph-name="paragraph" unicode="¶" horiz-adv-x="1264" d="M877 1452h-195v-1679h-320v86h27q99 0 133.5 38t34.5 109v785h-145q-314 0 -314 401q0 364 318 364h780v-86h-27q-98 0 -133 -37.5t-35 -109.5v-1317q0 -72 35 -109.5t133 -37.5h27v-86h-319v1679z" />-<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="586" d="M315 588q-127 0 -127 125q0 71 36.5 114t98.5 43q127 0 127 -125q0 -73 -36.5 -115t-98.5 -42z" />-<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="682" d="M387 -70q74 -10 119 -58t45 -112q0 -119 -86.5 -185.5t-239.5 -66.5q-79 0 -153 23l22 104q70 -16 137 -16q152 0 152 125q0 102 -131 115l78 159h96z" />-<glyph glyph-name="uni00B9" unicode="¹" horiz-adv-x="819" d="M135 588l15 69h94q85 0 100 78l125 590h-190l14 70h102q143 0 187 78h102l-143 -678q-15 -71 -15 -86q0 -52 72 -52h94l-14 -69h-543z" />-<glyph glyph-name="ordmasculine" unicode="º" horiz-adv-x="813" d="M420 780q-133 0 -208 68.5t-75 187.5q0 162 117 297t303 135q130 0 204.5 -66.5t74.5 -184.5q0 -164 -115 -300.5t-301 -136.5zM543 1386q-98 0 -162 -119t-64 -253q0 -152 103 -152q99 0 161 118.5t62 260.5q0 145 -100 145z" />-<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="1053" d="M911 520l-389 -356h-102l299 399l-133 379h102l238 -356zM541 520l-389 -356h-103l299 399l-133 379h102l238 -356z" />-<glyph glyph-name="onequarter" unicode="¼" horiz-adv-x="1720" d="M1323 572q26 116 41 160l-43 -59l-291 -324h243zM1437 261l-18 -84q-8 -37 -8 -55q0 -52 71 -52h41l-14 -69h-451l15 69h57q85 0 100 78l25 113h-363l11 70l501 555h164l-112 -537h196l-18 -88h-197zM420 0h-143l1032 1462h139zM27 588l15 69h94q85 0 100 78l125 590 h-190l14 70h102q143 0 187 78h102l-143 -678q-15 -71 -15 -86q0 -52 72 -52h94l-14 -69h-543z" />-<glyph glyph-name="onehalf" unicode="½" horiz-adv-x="1720" d="M399 0h-143l1032 1462h139zM27 588l15 69h94q85 0 100 78l125 590h-190l14 70h102q143 0 187 78h102l-143 -678q-15 -71 -15 -86q0 -52 72 -52h94l-14 -69h-543zM922 1l10 61l318 262q111 91 166 175.5t55 197.5q0 119 -103 119q-62 0 -107.5 -53.5t-57.5 -141.5 q-62 0 -97 27.5t-35 71.5q0 77 84.5 127.5t227.5 50.5q124 0 196 -54t72 -141q0 -97 -62.5 -181t-220.5 -210l-245 -195h282q77 0 109 84l16 43h70l-57 -243h-621z" />-<glyph glyph-name="threequarters" unicode="¾" horiz-adv-x="1720" d="M1344 572q26 116 41 160l-43 -59l-291 -324h243zM1458 261l-18 -84q-8 -37 -8 -55q0 -52 71 -52h41l-14 -69h-451l15 69h57q85 0 100 78l25 113h-363l11 70l501 555h164l-112 -537h196l-18 -88h-197zM475 0h-143l1032 1462h139zM155 842q0 -75 45 -125.5t120 -50.5 q195 0 195 182q0 69 -49 111t-137 42h-68l16 84h68q97 0 162 62t65 158t-94 96q-136 0 -172 -178q-135 0 -135 86q0 73 84.5 123.5t228.5 50.5q131 0 204 -51t73 -136q0 -189 -262 -241l-2 -11q206 -27 206 -188q0 -133 -107.5 -208t-289.5 -75q-130 0 -199 43t-69 115 q0 111 117 111z" />-<glyph glyph-name="questiondown" unicode="¿" horiz-adv-x="1024" d="M666 1110q127 0 127 -125q0 -71 -37 -114.5t-99 -43.5q-60 0 -93.5 34.5t-33.5 90.5q0 75 37 116.5t99 41.5zM506 444l51 238h125l-64 -303q-415 -152 -415 -445q0 -100 54 -160.5t144 -60.5q212 0 254 291q148 0 148 -123q0 -113 -114.5 -191.5t-299.5 -78.5 q-387 0 -387 340q0 311 504 493z" />-<glyph glyph-name="Agrave" unicode="À" horiz-adv-x="1444" d="M408 489l-123 -215q-39 -68 -39 -114q0 -74 114 -74h48l-17 -86h-506l17 86h39q55 0 92 28.5t98 131.5l713 1216h160l194 -1267q10 -64 35 -86.5t86 -22.5h27l-17 -86h-557l16 86h48q147 0 147 104q0 42 -4 70l-33 229h-538zM881 950q-31 218 -33 324q-47 -111 -160 -305 l-219 -377h463zM923 1579q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="Aacute" unicode="Á" horiz-adv-x="1444" d="M408 489l-123 -215q-39 -68 -39 -114q0 -74 114 -74h48l-17 -86h-506l17 86h39q55 0 92 28.5t98 131.5l713 1216h160l194 -1267q10 -64 35 -86.5t86 -22.5h27l-17 -86h-557l16 86h48q147 0 147 104q0 42 -4 70l-33 229h-538zM881 950q-31 218 -33 324q-47 -111 -160 -305 l-219 -377h463zM838 1606q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="Acircumflex" unicode="Â" horiz-adv-x="1444" d="M408 489l-123 -215q-39 -68 -39 -114q0 -74 114 -74h48l-17 -86h-506l17 86h39q55 0 92 28.5t98 131.5l713 1216h160l194 -1267q10 -64 35 -86.5t86 -22.5h27l-17 -86h-557l16 86h48q147 0 147 104q0 42 -4 70l-33 229h-538zM881 950q-31 218 -33 324q-47 -111 -160 -305 l-219 -377h463zM617 1606q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="Atilde" unicode="Ã" horiz-adv-x="1444" d="M408 489l-123 -215q-39 -68 -39 -114q0 -74 114 -74h48l-17 -86h-506l17 86h39q55 0 92 28.5t98 131.5l713 1216h160l194 -1267q10 -64 35 -86.5t86 -22.5h27l-17 -86h-557l16 86h48q147 0 147 104q0 42 -4 70l-33 229h-538zM881 950q-31 218 -33 324q-47 -111 -160 -305 l-219 -377h463zM1229 1821h92q-72 -242 -266 -242q-81 0 -169 65q-89 64 -126 64q-88 0 -123 -108h-92q72 241 268 241q82 0 169 -64q87 -65 124 -65q89 0 123 109z" />-<glyph glyph-name="Adieresis" unicode="Ä" horiz-adv-x="1444" d="M408 489l-123 -215q-39 -68 -39 -114q0 -74 114 -74h48l-17 -86h-506l17 86h39q55 0 92 28.5t98 131.5l713 1216h160l194 -1267q10 -64 35 -86.5t86 -22.5h27l-17 -86h-557l16 86h48q147 0 147 104q0 42 -4 70l-33 229h-538zM881 950q-31 218 -33 324q-47 -111 -160 -305 l-219 -377h463zM756 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM1145 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="Aring" unicode="Å" horiz-adv-x="1444" d="M914 1708q-135 0 -135 -123t135 -123t135 123t-135 123zM914 1362q-107 0 -176.5 59t-69.5 164q0 104 69 163.5t177 59.5t177 -59.5t69 -163.5q0 -105 -69.5 -164t-176.5 -59zM408 489l-123 -215q-39 -68 -39 -114q0 -74 114 -74h48l-17 -86h-506l17 86h39q55 0 92 28.5 t98 131.5l713 1216h160l194 -1267q10 -64 35 -86.5t86 -22.5h27l-17 -86h-557l16 86h48q147 0 147 104q0 42 -4 70l-33 229h-538zM881 950q-31 218 -33 324q-47 -111 -160 -305l-219 -377h463z" />-<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="1948" d="M-127 0l29 86h39q54 0 94.5 28t116.5 132l815 1118l-174 12l18 86h1159l-65 -358h-107q10 70 10 119q0 137 -145 137h-344l-117 -545h494l-21 -100h-493l-131 -613h395q172 0 231 168l33 88h107l-91 -358h-1097l16 86h27q103 0 144 35.5t54 101.5l56 266h-463l-154 -215 q-55 -77 -55 -120q0 -68 104 -68h48l-29 -86h-504zM1110 1360h-39q-97 -168 -260 -391l-272 -377h409z" />-<glyph glyph-name="Ccedilla" unicode="Ç" horiz-adv-x="1284" d="M1073 299q27 -19 27 -68q0 -98 -114 -174.5t-314 -76.5q-267 0 -416.5 143t-149.5 405q0 388 242 671.5t602 283.5q179 0 279 -61.5t100 -166.5q0 -73 -55 -116t-146 -43q0 278 -204 278q-253 0 -423.5 -275.5t-170.5 -602.5q0 -383 364 -383q237 0 379 186zM649 -70 q74 -10 119 -58t45 -112q0 -119 -86.5 -185.5t-239.5 -66.5q-79 0 -153 23l22 104q70 -16 137 -16q152 0 152 125q0 102 -131 115l78 159h96z" />-<glyph glyph-name="Egrave" unicode="È" horiz-adv-x="1276" d="M379 102h395q173 0 232 168l32 88h107l-90 -358h-1098l16 86h27q104 0 144.5 36.5t54.5 100.5l213 1006q6 28 6 49q0 48 -28 73t-116 25h-26l18 86h1032l-65 -358h-107l6 63q5 48 5 56q0 137 -146 137h-344l-117 -545h494l-20 -100h-494zM849 1579q-154 150 -264 307 l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="Eacute" unicode="É" horiz-adv-x="1276" d="M379 102h395q173 0 232 168l32 88h107l-90 -358h-1098l16 86h27q104 0 144.5 36.5t54.5 100.5l213 1006q6 28 6 49q0 48 -28 73t-116 25h-26l18 86h1032l-65 -358h-107l6 63q5 48 5 56q0 137 -146 137h-344l-117 -545h494l-20 -100h-494zM725 1606q117 135 219 301h219 l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="Ecircumflex" unicode="Ê" horiz-adv-x="1276" d="M379 102h395q173 0 232 168l32 88h107l-90 -358h-1098l16 86h27q104 0 144.5 36.5t54.5 100.5l213 1006q6 28 6 49q0 48 -28 73t-116 25h-26l18 86h1032l-65 -358h-107l6 63q5 48 5 56q0 137 -146 137h-344l-117 -545h494l-20 -100h-494zM551 1606q186 183 270 301h195 q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="Edieresis" unicode="Ë" horiz-adv-x="1276" d="M379 102h395q173 0 232 168l32 88h107l-90 -358h-1098l16 86h27q104 0 144.5 36.5t54.5 100.5l213 1006q6 28 6 49q0 48 -28 73t-116 25h-26l18 86h1032l-65 -358h-107l6 63q5 48 5 56q0 137 -146 137h-344l-117 -545h494l-20 -100h-494zM643 1632q-102 0 -102 103 q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM1032 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="Igrave" unicode="Ì" horiz-adv-x="752" d="M862 1462l-18 -86h-27q-98 0 -141 -37t-58 -110l-212 -1004q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-596l16 86h27q170 0 201 147l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596zM607 1579q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="752" d="M862 1462l-18 -86h-27q-98 0 -141 -37t-58 -110l-212 -1004q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-596l16 86h27q170 0 201 147l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596zM476 1606q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="752" d="M862 1462l-18 -86h-27q-98 0 -141 -37t-58 -110l-212 -1004q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-596l16 86h27q170 0 201 147l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596zM280 1606q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184 q-150 -127 -262 -184h-88z" />-<glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="752" d="M862 1462l-18 -86h-27q-98 0 -141 -37t-58 -110l-212 -1004q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-596l16 86h27q170 0 201 147l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h596zM404 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM793 1632 q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="1530" d="M-27 86h27q170 0 201 147l102 482h-199l23 100h197l90 422q8 38 8 57q0 82 -148 82h-26l18 86h615q279 0 430 -144.5t151 -412.5q0 -392 -223 -648.5t-596 -256.5h-686zM598 104q294 0 467.5 226t173.5 598q0 432 -389 432h-203l-117 -545h388l-23 -100h-387l-129 -611 h219z" />-<glyph glyph-name="Ntilde" unicode="Ñ" horiz-adv-x="1563" d="M1327 1237q8 38 8 57q0 82 -147 82h-27l19 86h514l-19 -86h-26q-98 0 -140.5 -37.5t-58.5 -109.5l-260 -1229h-133l-527 1200l-206 -975q-9 -43 -9 -57q0 -82 148 -82h26l-18 -86h-512l18 86h27q96 0 138 37.5t59 109.5l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h373 l496 -1130zM1347 1821h92q-72 -242 -266 -242q-81 0 -169 65q-89 64 -126 64q-88 0 -123 -108h-92q72 241 268 241q82 0 169 -64q87 -65 124 -65q89 0 123 109z" />-<glyph glyph-name="Ograve" unicode="Ò" horiz-adv-x="1520" d="M926 1485q238 0 384 -148t146 -415q0 -351 -228 -648t-585 -297q-243 0 -390 153.5t-147 414.5q0 352 230 646t590 294zM655 90q255 0 415.5 282.5t160.5 604.5q0 191 -84.5 294t-237.5 103q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5zM1022 1579 q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="Oacute" unicode="Ó" horiz-adv-x="1520" d="M926 1485q238 0 384 -148t146 -415q0 -351 -228 -648t-585 -297q-243 0 -390 153.5t-147 414.5q0 352 230 646t590 294zM655 90q255 0 415.5 282.5t160.5 604.5q0 191 -84.5 294t-237.5 103q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5zM827 1606 q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="Ocircumflex" unicode="Ô" horiz-adv-x="1520" d="M926 1485q238 0 384 -148t146 -415q0 -351 -228 -648t-585 -297q-243 0 -390 153.5t-147 414.5q0 352 230 646t590 294zM655 90q255 0 415.5 282.5t160.5 604.5q0 191 -84.5 294t-237.5 103q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5zM639 1606 q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="Otilde" unicode="Õ" horiz-adv-x="1520" d="M926 1485q238 0 384 -148t146 -415q0 -351 -228 -648t-585 -297q-243 0 -390 153.5t-147 414.5q0 352 230 646t590 294zM655 90q255 0 415.5 282.5t160.5 604.5q0 191 -84.5 294t-237.5 103q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5zM1272 1821 h92q-72 -242 -266 -242q-81 0 -169 65q-89 64 -126 64q-88 0 -123 -108h-92q72 241 268 241q82 0 169 -64q87 -65 124 -65q89 0 123 109z" />-<glyph glyph-name="Odieresis" unicode="Ö" horiz-adv-x="1520" d="M926 1485q238 0 384 -148t146 -415q0 -351 -228 -648t-585 -297q-243 0 -390 153.5t-147 414.5q0 352 230 646t590 294zM655 90q255 0 415.5 282.5t160.5 604.5q0 191 -84.5 294t-237.5 103q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5zM780 1632 q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM1169 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="multiply" unicode="×" d="M571 647l-340 -340l-86 88l340 340l-340 338l86 86l340 -340l340 342l86 -88l-340 -340l340 -340l-86 -86z" />-<glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1520" d="M1217 1409l106 137h119l-150 -194q164 -152 164 -430q0 -351 -228 -648t-585 -297q-165 0 -289 74l-96 -133h-121l137 191q-168 156 -168 436q0 352 230 646t590 294q165 0 291 -76zM379 250l751 1038q-84 86 -221 86q-256 0 -417.5 -283.5t-161.5 -603.5q0 -139 49 -237 zM1188 1204l-750 -1036q86 -78 217 -78q255 0 415.5 282.5t160.5 604.5q0 129 -43 227z" />-<glyph glyph-name="Ugrave" unicode="Ù" horiz-adv-x="1495" d="M205 1376l18 86h596l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-153 -723q-25 -118 -25 -191q0 -213 295 -213q166 0 263 74t135 246l174 815q8 37 8 57q0 82 -148 82h-26l18 86h514l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-172 -811q-93 -438 -552 -438 q-226 0 -345.5 92t-119.5 262q0 83 22 182l152 721q8 38 8 57q0 82 -148 82h-26zM981 1579q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="Uacute" unicode="Ú" horiz-adv-x="1495" d="M205 1376l18 86h596l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-153 -723q-25 -118 -25 -191q0 -213 295 -213q166 0 263 74t135 246l174 815q8 37 8 57q0 82 -148 82h-26l18 86h514l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-172 -811q-93 -438 -552 -438 q-226 0 -345.5 92t-119.5 262q0 83 22 182l152 721q8 38 8 57q0 82 -148 82h-26zM864 1606q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="Ucircumflex" unicode="Û" horiz-adv-x="1495" d="M205 1376l18 86h596l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-153 -723q-25 -118 -25 -191q0 -213 295 -213q166 0 263 74t135 246l174 815q8 37 8 57q0 82 -148 82h-26l18 86h514l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-172 -811q-93 -438 -552 -438 q-226 0 -345.5 92t-119.5 262q0 83 22 182l152 721q8 38 8 57q0 82 -148 82h-26zM680 1606q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="Udieresis" unicode="Ü" horiz-adv-x="1495" d="M205 1376l18 86h596l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-153 -723q-25 -118 -25 -191q0 -213 295 -213q166 0 263 74t135 246l174 815q8 37 8 57q0 82 -148 82h-26l18 86h514l-16 -86h-27q-96 0 -140 -36.5t-61 -110.5l-172 -811q-93 -438 -552 -438 q-226 0 -345.5 92t-119.5 262q0 83 22 182l152 721q8 38 8 57q0 82 -148 82h-26zM774 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM1163 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="Yacute" unicode="Ý" horiz-adv-x="1280" d="M729 1462l-18 -86h-103q-84 0 -84 -55q0 -40 27 -119l92 -274q49 -146 55 -246q20 38 154 215l195 260q75 100 75 166q0 53 -98 53h-76l19 86h506l-19 -86h-39q-39 0 -77.5 -31.5t-108.5 -123.5l-477 -625l-80 -371q-8 -37 -8 -57q0 -82 147 -82h47l-18 -86h-637l18 86 h47q103 0 143 35.5t54 101.5l80 377l-238 668q-23 65 -45.5 86.5t-77.5 21.5h-26l18 86h553zM770 1606q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="Thorn" unicode="Þ" horiz-adv-x="1237" d="M-41 0l18 86h27q96 0 139 37t58 110l213 1004q8 38 8 57q0 82 -148 82h-26l18 86h617l-19 -86h-47q-103 0 -144 -38.5t-55 -108.5l-4 -21h121q222 0 344.5 -103t122.5 -292q0 -233 -157.5 -365.5t-469.5 -132.5h-151l-18 -90q-9 -45 -9 -57q0 -82 148 -82h47l-19 -86 h-614zM444 412h109q432 0 432 399q0 299 -299 299h-94z" />-<glyph glyph-name="germandbls" unicode="ß" horiz-adv-x="1284" d="M-279 -475l19 94q51 -14 94 -14q102 0 159 87.5t99 289.5l217 1019h-166l21 97h166l14 61q94 408 512 408q373 0 373 -314q0 -109 -29 -247h-176q-225 0 -225 -168q0 -70 44.5 -117t125.5 -94q192 -113 192 -308q0 -162 -101.5 -250.5t-293.5 -88.5q-145 0 -228 55.5 t-83 152.5q0 60 43.5 97t109.5 37q0 -244 172 -244q91 0 146 52.5t55 141.5q0 138 -156 230q-204 126 -204 293q0 307 407 307q23 103 23 170q0 203 -201 203q-243 0 -307 -287l-258 -1204q-54 -250 -156.5 -363t-288.5 -113q-58 0 -119 17z" />-<glyph glyph-name="agrave" unicode="à" horiz-adv-x="1186" d="M748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523t434.5 241q139 0 240 -74l90 52h66l-140 -656q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74 q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330zM705 1241q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="aacute" unicode="á" horiz-adv-x="1186" d="M748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523t434.5 241q139 0 240 -74l90 52h66l-140 -656q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74 q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330zM637 1268q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="acircumflex" unicode="â" horiz-adv-x="1186" d="M748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523t434.5 241q139 0 240 -74l90 52h66l-140 -656q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74 q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330zM410 1268q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="atilde" unicode="ã" horiz-adv-x="1186" d="M748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523t434.5 241q139 0 240 -74l90 52h66l-140 -656q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74 q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330zM1025 1483h92q-72 -242 -266 -242q-81 0 -169 65q-89 64 -126 64q-88 0 -123 -108h-92q72 241 268 241q82 0 169 -64q87 -65 124 -65q89 0 123 109z" />-<glyph glyph-name="adieresis" unicode="ä" horiz-adv-x="1186" d="M748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523t434.5 241q139 0 240 -74l90 52h66l-140 -656q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74 q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330zM505 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM894 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="aring" unicode="å" horiz-adv-x="1186" d="M737 1567q-135 0 -135 -123t135 -123t135 123t-135 123zM737 1221q-107 0 -176.5 59t-69.5 164q0 104 69 163.5t177 59.5t177 -59.5t69 -163.5q0 -105 -69.5 -164t-176.5 -59zM748 309h-13q-147 -329 -383 -329q-125 0 -194.5 98.5t-69.5 275.5q0 282 175.5 523 t434.5 241q139 0 240 -74l90 52h66l-140 -656q-30 -141 -30 -227q0 -104 67 -104q58 0 148 53l37 -60q-147 -122 -289 -122q-160 0 -160 170q0 65 21 159zM864 952q-47 74 -155 74q-175 0 -293.5 -222.5t-118.5 -457.5q0 -237 129 -237q102 0 214 151t148 330z" />-<glyph glyph-name="ae" unicode="æ" horiz-adv-x="1665" d="M1477 256q20 -14 20 -51q0 -84 -96.5 -154.5t-257.5 -70.5q-141 0 -243 75t-136 219q-116 -294 -367 -294q-140 0 -224.5 108t-84.5 299q0 278 164.5 504.5t433.5 226.5q161 0 313 -127q153 127 355 127q130 0 201 -62t71 -173q0 -166 -172.5 -289t-421.5 -123h-35 q-18 0 -36 2q-5 -25 -5 -86q0 -278 226 -278q171 0 295 147zM905 893q-97 133 -209 133q-173 0 -286 -217t-113 -444q0 -122 45.5 -189t126.5 -67q102 0 177 99t104 267q38 233 155 418zM979 567h20q181 0 298.5 88t117.5 228q0 137 -119 137q-100 0 -186.5 -127.5 t-130.5 -325.5z" />-<glyph glyph-name="ccedilla" unicode="ç" horiz-adv-x="997" d="M821 256q21 -13 21 -51q0 -82 -96.5 -153.5t-258.5 -71.5q-179 0 -289 113t-110 310q0 268 173 491.5t437 223.5q141 0 220 -56t79 -140q0 -62 -49.5 -103t-132.5 -41q0 109 -42 175.5t-116 66.5q-143 0 -249.5 -214t-106.5 -419q0 -278 225 -278q179 0 295 147zM487 -70 q74 -10 119 -58t45 -112q0 -119 -86.5 -185.5t-239.5 -66.5q-79 0 -153 23l22 104q70 -16 137 -16q152 0 152 125q0 102 -131 115l78 159h96z" />-<glyph glyph-name="egrave" unicode="è" horiz-adv-x="1010" d="M821 256q21 -13 21 -51q0 -82 -96.5 -153.5t-258.5 -71.5q-179 0 -289 113t-110 310q0 268 173 491.5t437 223.5q130 0 201.5 -62t71.5 -173q0 -166 -172.5 -289t-421.5 -123h-35q-18 0 -37 2q-4 -28 -4 -86q0 -278 225 -278q175 0 295 147zM324 567h20q181 0 298.5 88 t117.5 228q0 137 -119 137q-99 0 -185 -124.5t-132 -328.5zM721 1241q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="eacute" unicode="é" horiz-adv-x="1010" d="M821 256q21 -13 21 -51q0 -82 -96.5 -153.5t-258.5 -71.5q-179 0 -289 113t-110 310q0 268 173 491.5t437 223.5q130 0 201.5 -62t71.5 -173q0 -166 -172.5 -289t-421.5 -123h-35q-18 0 -37 2q-4 -28 -4 -86q0 -278 225 -278q175 0 295 147zM324 567h20q181 0 298.5 88 t117.5 228q0 137 -119 137q-99 0 -185 -124.5t-132 -328.5zM614 1268q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="1010" d="M821 256q21 -13 21 -51q0 -82 -96.5 -153.5t-258.5 -71.5q-179 0 -289 113t-110 310q0 268 173 491.5t437 223.5q130 0 201.5 -62t71.5 -173q0 -166 -172.5 -289t-421.5 -123h-35q-18 0 -37 2q-4 -28 -4 -86q0 -278 225 -278q175 0 295 147zM324 567h20q181 0 298.5 88 t117.5 228q0 137 -119 137q-99 0 -185 -124.5t-132 -328.5zM387 1268q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="edieresis" unicode="ë" horiz-adv-x="1010" d="M821 256q21 -13 21 -51q0 -82 -96.5 -153.5t-258.5 -71.5q-179 0 -289 113t-110 310q0 268 173 491.5t437 223.5q130 0 201.5 -62t71.5 -173q0 -166 -172.5 -289t-421.5 -123h-35q-18 0 -37 2q-4 -28 -4 -86q0 -278 225 -278q175 0 295 147zM324 567h20q181 0 298.5 88 t117.5 228q0 137 -119 137q-99 0 -185 -124.5t-132 -328.5zM509 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM898 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="igrave" unicode="ì" horiz-adv-x="623" d="M127 1012l18 86h367l-139 -658q-31 -147 -31 -227q0 -104 68 -104q59 0 147 53l37 -60q-142 -122 -277 -122q-76 0 -123 55t-47 139q0 92 46 322l79 376q7 33 7 54q0 86 -125 86h-27zM455 1241q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="iacute" unicode="í" horiz-adv-x="623" d="M127 1012l18 86h367l-139 -658q-31 -147 -31 -227q0 -104 68 -104q59 0 147 53l37 -60q-142 -122 -277 -122q-76 0 -123 55t-47 139q0 92 46 322l79 376q7 33 7 54q0 86 -125 86h-27zM333 1268q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="623" d="M127 1012l18 86h367l-139 -658q-31 -147 -31 -227q0 -104 68 -104q59 0 147 53l37 -60q-142 -122 -277 -122q-76 0 -123 55t-47 139q0 92 46 322l79 376q7 33 7 54q0 86 -125 86h-27zM79 1268q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184 q-150 -127 -262 -184h-88z" />-<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="623" d="M127 1012l18 86h367l-139 -658q-31 -147 -31 -227q0 -104 68 -104q59 0 147 53l37 -60q-142 -122 -277 -122q-76 0 -123 55t-47 139q0 92 46 322l79 376q7 33 7 54q0 86 -125 86h-27zM208 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM597 1294 q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="eth" unicode="ð" horiz-adv-x="1182" d="M877 983q-45 185 -144 291l-293 -150l25 115l199 102q-89 68 -226 115l35 103q184 -47 324 -152l297 154l-27 -117l-201 -103q102 -101 161.5 -262t59.5 -338q0 -348 -161.5 -561t-444.5 -213q-180 0 -286.5 106.5t-106.5 295.5q0 254 168 461.5t442 207.5q109 0 179 -55 zM504 68q169 0 269.5 186.5t100.5 409.5q0 268 -200 268q-168 0 -270.5 -186.5t-102.5 -409.5q0 -268 203 -268z" />-<glyph glyph-name="ntilde" unicode="ñ" horiz-adv-x="1227" d="M281 0h-191l172 823q12 57 12 92q0 97 -143 97h-16l18 86h379l-55 -258h20q166 276 373 276q219 0 219 -227q0 -65 -37 -225l-53 -242q-27 -123 -27 -215q0 -98 72 -98q59 0 131 47l37 -60q-134 -116 -250 -116q-85 0 -135.5 55t-50.5 149t39 277l47 212q30 124 30 191 q0 121 -94 121q-114 0 -233.5 -154t-153.5 -307zM1046 1483h92q-72 -242 -266 -242q-81 0 -169 65q-89 64 -126 64q-88 0 -123 -108h-92q72 241 268 241q82 0 169 -64q87 -65 124 -65q89 0 123 109z" />-<glyph glyph-name="ograve" unicode="ò" horiz-adv-x="1176" d="M698 1118q181 0 285 -109t104 -315q0 -273 -167 -493.5t-439 -220.5q-185 0 -289 112t-104 311q0 276 168.5 495.5t441.5 219.5zM504 80q169 0 269.5 200.5t100.5 444.5q0 285 -200 285q-167 0 -270 -201t-103 -447q0 -282 203 -282zM734 1241q-154 150 -264 307l6 21 h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="oacute" unicode="ó" horiz-adv-x="1176" d="M698 1118q181 0 285 -109t104 -315q0 -273 -167 -493.5t-439 -220.5q-185 0 -289 112t-104 311q0 276 168.5 495.5t441.5 219.5zM504 80q169 0 269.5 200.5t100.5 444.5q0 285 -200 285q-167 0 -270 -201t-103 -447q0 -282 203 -282zM629 1268q117 135 219 301h219 l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="ocircumflex" unicode="ô" horiz-adv-x="1176" d="M698 1118q181 0 285 -109t104 -315q0 -273 -167 -493.5t-439 -220.5q-185 0 -289 112t-104 311q0 276 168.5 495.5t441.5 219.5zM504 80q169 0 269.5 200.5t100.5 444.5q0 285 -200 285q-167 0 -270 -201t-103 -447q0 -282 203 -282zM399 1268q186 183 270 301h195 q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="otilde" unicode="õ" horiz-adv-x="1176" d="M698 1118q181 0 285 -109t104 -315q0 -273 -167 -493.5t-439 -220.5q-185 0 -289 112t-104 311q0 276 168.5 495.5t441.5 219.5zM504 80q169 0 269.5 200.5t100.5 444.5q0 285 -200 285q-167 0 -270 -201t-103 -447q0 -282 203 -282zM1023 1483h92q-72 -242 -266 -242 q-81 0 -169 65q-89 64 -126 64q-88 0 -123 -108h-92q72 241 268 241q82 0 169 -64q87 -65 124 -65q89 0 123 109z" />-<glyph glyph-name="odieresis" unicode="ö" horiz-adv-x="1176" d="M698 1118q181 0 285 -109t104 -315q0 -273 -167 -493.5t-439 -220.5q-185 0 -289 112t-104 311q0 276 168.5 495.5t441.5 219.5zM504 80q169 0 269.5 200.5t100.5 444.5q0 285 -200 285q-167 0 -270 -201t-103 -447q0 -282 203 -282zM518 1294q-102 0 -102 103 q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM907 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="divide" unicode="÷" d="M590 1233q104 0 104 -113q0 -112 -104 -112q-105 0 -105 112q0 113 105 113zM1028 672h-878v121h878v-121zM590 457q104 0 104 -113t-104 -113q-105 0 -105 113t105 113z" />-<glyph glyph-name="oslash" unicode="ø" horiz-adv-x="1182" d="M942 1044l115 136h119l-166 -203q77 -106 77 -283q0 -275 -167 -497t-439 -222q-141 0 -243 72l-107 -129h-121l162 195q-84 110 -84 290q0 276 168.5 495.5t441.5 219.5q149 0 244 -74zM305 274l533 644q-49 92 -164 92q-167 0 -270 -201t-103 -447q0 -65 4 -88z M868 809l-530 -641q46 -92 166 -92q168 0 269 201.5t101 447.5q0 44 -6 84z" />-<glyph glyph-name="ugrave" unicode="ù" horiz-adv-x="1227" d="M135 1098h381l-135 -613q-41 -186 -41 -247q0 -125 100 -125q105 0 226.5 151.5t158.5 323.5l107 510h198l-141 -658q-31 -145 -31 -227q0 -104 68 -104q58 0 131 45l37 -60q-130 -114 -260 -114q-77 0 -124.5 55t-47.5 139q0 53 10 121h-16q-111 -183 -198.5 -248 t-197.5 -65q-219 0 -219 227q0 65 37 225l80 359q18 81 18 122q0 97 -143 97h-16zM750 1241q-154 150 -264 307l6 21h205q60 -155 137 -301l-6 -27h-78z" />-<glyph glyph-name="uacute" unicode="ú" horiz-adv-x="1227" d="M135 1098h381l-135 -613q-41 -186 -41 -247q0 -125 100 -125q105 0 226.5 151.5t158.5 323.5l107 510h198l-141 -658q-31 -145 -31 -227q0 -104 68 -104q58 0 131 45l37 -60q-130 -114 -260 -114q-77 0 -124.5 55t-47.5 139q0 53 10 121h-16q-111 -183 -198.5 -248 t-197.5 -65q-219 0 -219 227q0 65 37 225l80 359q18 81 18 122q0 97 -143 97h-16zM647 1268q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="ucircumflex" unicode="û" horiz-adv-x="1227" d="M135 1098h381l-135 -613q-41 -186 -41 -247q0 -125 100 -125q105 0 226.5 151.5t158.5 323.5l107 510h198l-141 -658q-31 -145 -31 -227q0 -104 68 -104q58 0 131 45l37 -60q-130 -114 -260 -114q-77 0 -124.5 55t-47.5 139q0 53 10 121h-16q-111 -183 -198.5 -248 t-197.5 -65q-219 0 -219 227q0 65 37 225l80 359q18 81 18 122q0 97 -143 97h-16zM434 1268q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="udieresis" unicode="ü" horiz-adv-x="1227" d="M135 1098h381l-135 -613q-41 -186 -41 -247q0 -125 100 -125q105 0 226.5 151.5t158.5 323.5l107 510h198l-141 -658q-31 -145 -31 -227q0 -104 68 -104q58 0 131 45l37 -60q-130 -114 -260 -114q-77 0 -124.5 55t-47.5 139q0 53 10 121h-16q-111 -183 -198.5 -248 t-197.5 -65q-219 0 -219 227q0 65 37 225l80 359q18 81 18 122q0 97 -143 97h-16zM571 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM960 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="yacute" unicode="ý" horiz-adv-x="1081" d="M164 903q-18 60 -49 84.5t-92 24.5h-21l16 86h299l160 -553q74 -257 86 -371h6q277 421 277 680q0 111 -101 111q0 69 40 110t94 41q139 0 139 -172q0 -247 -276 -694.5t-442.5 -594.5t-438.5 -147q-108 0 -193 37l31 103q72 -23 160 -23q293 0 575 373zM535 1268 q117 135 219 301h219l-6 -21q-157 -183 -356 -307h-82z" />-<glyph glyph-name="thorn" unicode="þ" horiz-adv-x="1151" d="M248 27q-9 -78 -15 -99l-31 -151q-14 -58 -14 -94q0 -89 144 -89h26l-18 -86h-389l373 1758q18 85 18 108q0 96 -143 96h-17l19 86h377l-105 -491q-17 -79 -61 -240h12q148 293 375 293q125 0 194.5 -95t69.5 -275q0 -275 -173 -521.5t-439 -246.5q-120 0 -203 47z M281 145q65 -73 163 -73q171 0 290.5 223t119.5 455q0 113 -35.5 176t-97.5 63q-107 0 -216 -150.5t-140 -303.5z" />-<glyph glyph-name="ydieresis" unicode="ÿ" horiz-adv-x="1081" d="M164 903q-18 60 -49 84.5t-92 24.5h-21l16 86h299l160 -553q74 -257 86 -371h6q277 421 277 680q0 111 -101 111q0 69 40 110t94 41q139 0 139 -172q0 -247 -276 -694.5t-442.5 -594.5t-438.5 -147q-108 0 -193 37l31 103q72 -23 160 -23q293 0 575 373zM413 1294 q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM802 1294q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="1970" d="M1073 102h395q173 0 232 168l33 88h106l-90 -358h-881l-69 -12q-80 -11 -156 -11q-243 0 -390 153.5t-147 414.5q0 352 230 646t590 294q102 0 217 -23h850l-66 -358h-106q10 70 10 119q0 133 -145 137h-345l-116 -545h493l-20 -100h-494zM872 125l256 1208 q-113 41 -219 41q-256 0 -417.5 -283.5t-161.5 -603.5q0 -192 87 -294.5t238 -102.5q135 0 217 35z" />-<glyph glyph-name="oe" unicode="œ" horiz-adv-x="1767" d="M1579 256q20 -14 20 -51q0 -84 -96.5 -154.5t-257.5 -70.5q-239 0 -344 186q-169 -199 -420 -199q-182 0 -287.5 117t-105.5 319q0 277 168.5 501t441.5 224q248 0 344 -204q173 194 414 194q130 0 201.5 -62t71.5 -173q0 -92 -61 -181t-170.5 -145.5t-194 -70 t-240.5 -13.5q-6 -46 -6 -86q0 -278 227 -278q175 0 295 147zM504 68q168 0 269 205t101 452q0 295 -200 295q-167 0 -270 -205.5t-103 -452.5q0 -294 203 -294zM1081 567h21q181 0 298.5 89t117.5 227q0 137 -119 137q-100 0 -186.5 -126.5t-131.5 -326.5z" />-<glyph glyph-name="Ydieresis" unicode="Ÿ" horiz-adv-x="1280" d="M729 1462l-18 -86h-103q-84 0 -84 -55q0 -40 27 -119l92 -274q49 -146 55 -246q20 38 154 215l195 260q75 100 75 166q0 53 -98 53h-76l19 86h506l-19 -86h-39q-39 0 -77.5 -31.5t-108.5 -123.5l-477 -625l-80 -371q-8 -37 -8 -57q0 -82 147 -82h47l-18 -86h-637l18 86 h47q103 0 143 35.5t54 101.5l80 377l-238 668q-23 65 -45.5 86.5t-77.5 21.5h-26l18 86h553zM684 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129zM1073 1632q-102 0 -102 103q0 129 110 129q103 0 103 -103q0 -129 -111 -129z" />-<glyph glyph-name="circumflex" unicode="ˆ" horiz-adv-x="1182" d="M381 1268q186 183 270 301h195q29 -117 139 -301l-6 -27h-72q-95 65 -182 184q-150 -127 -262 -184h-88z" />-<glyph glyph-name="tilde" unicode="˜" horiz-adv-x="1182" d="M1028 1483h92q-72 -242 -266 -242q-81 0 -169 65q-89 64 -126 64q-88 0 -123 -108h-92q72 241 268 241q82 0 169 -64q87 -65 124 -65q89 0 123 109z" />-<glyph glyph-name="endash" unicode="–" horiz-adv-x="1024" d="M1036 489h-1042l24 121h1045z" />-<glyph glyph-name="emdash" unicode="—" horiz-adv-x="2048" d="M2060 489h-2066l24 121h2069z" />-<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="512" d="M586 1462l-8 -86q-209 -46 -209 -172q0 -36 67 -78q66 -42 66 -104q0 -55 -35 -88t-92 -33q-67 0 -113.5 46.5t-46.5 121.5q0 148 95 252t276 141z" />-<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="512" d="M168 901l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 35 88t92 33q69 0 114.5 -46.5t45.5 -121.5q0 -151 -96.5 -254t-274.5 -139z" />-<glyph glyph-name="quotesinglbase" unicode="‚" horiz-adv-x="512" d="M-57 -299l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 35 88t92 33q69 0 114 -45.5t45 -122.5q0 -150 -95 -253.5t-275 -139.5z" />-<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="922" d="M586 1462l-8 -86q-209 -46 -209 -172q0 -36 67 -78q66 -42 66 -104q0 -55 -35 -88t-92 -33q-67 0 -113.5 46.5t-46.5 121.5q0 148 95 252t276 141zM995 1462l-8 -86q-209 -47 -209 -172q0 -36 67 -78q66 -42 66 -104q0 -55 -34.5 -88t-92.5 -33q-68 0 -113.5 46.5 t-45.5 121.5q0 150 95 253.5t275 139.5z" />-<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="922" d="M168 901l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 35 88t92 33q69 0 114.5 -46.5t45.5 -121.5q0 -151 -96.5 -254t-274.5 -139zM578 901l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 34 88t92 33q69 0 114.5 -46.5t45.5 -121.5q0 -152 -96.5 -255 t-273.5 -138z" />-<glyph glyph-name="quotedblbase" unicode="„" horiz-adv-x="922" d="M-57 -299l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 35 88t92 33q69 0 114 -45.5t45 -122.5q0 -150 -95 -253.5t-275 -139.5zM350 -299l8 86q209 47 209 172q0 36 -66 78q-67 42 -67 104q0 55 35 88t92 33q69 0 114.5 -46.5t45.5 -121.5q0 -151 -96.5 -254 t-274.5 -139z" />-<glyph glyph-name="bullet" unicode="•" horiz-adv-x="741" d="M387 1026q270 0 270 -297t-270 -297t-270 297t270 297z" />-<glyph glyph-name="ellipsis" unicode="…" horiz-adv-x="1757" d="M217 -16q-127 0 -127 125q0 71 36.5 114t98.5 43q127 0 127 -125q0 -72 -36.5 -114.5t-98.5 -42.5zM1391 -16q-127 0 -127 125q0 71 36.5 114t98.5 43q60 0 93.5 -34t33.5 -91q0 -73 -36.5 -115t-98.5 -42zM799 -16q-127 0 -127 125q0 71 36.5 114t98.5 43 q127 0 127 -125q0 -73 -36.5 -115t-98.5 -42z" />-<glyph glyph-name="guilsinglleft" unicode="‹" horiz-adv-x="682" d="M139 586l389 356h103l-295 -397l129 -381h-103l-237 356z" />-<glyph glyph-name="guilsinglright" unicode="›" horiz-adv-x="682" d="M543 520l-389 -356h-103l299 397l-133 381h102l238 -356z" />-<glyph glyph-name="Euro" unicode="€" d="M936 223q25 -17 25 -49q0 -67 -95 -130.5t-254 -63.5q-197 0 -305 119t-108 345q0 72 4 103h-150l21 96h141q11 82 27 143h-140l21 97h145q178 596 637 596q141 0 224 -53t83 -138q0 -149 -180 -149q0 239 -166 239q-261 0 -401 -495h430l-21 -97h-434q-17 -63 -26 -143 h350l-21 -96h-342q-4 -31 -4 -117q0 -158 65 -244t187 -86q167 0 287 123z" />-<glyph glyph-name="trademark" unicode="™" horiz-adv-x="1710" d="M1479 754v55q74 0 80 55v457l-232 -567h-72l-231 569v-451q0 -41 21 -52t61 -11v-55h-248v55h21q76 0 79 57v482q0 57 -79 57h-21v57h236l225 -567l231 567h232v-57h-23q-78 0 -78 -62v-471q0 -63 78 -63h23v-55h-303zM580 872q0 -63 77 -63h33v-55h-348v55h35 q76 0 76 57v531h-91q-71 0 -81 -72l-9 -49h-59l6 186h598l6 -186h-59l-8 49q-11 70 -82 72h-94v-525z" />-</font>-</defs></svg>
− extra/fonts/DroidSerif-Italic.ttf
binary file changed (37848 → absent bytes)
− extra/fonts/DroidSerif-Italic.woff
binary file changed (25432 → absent bytes)
− extra/fonts/DroidSerif-Regular.eot
binary file changed (42054 → absent bytes)
− extra/fonts/DroidSerif-Regular.svg
@@ -1,223 +0,0 @@-<?xml version="1.0" standalone="no"?>-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >-<svg xmlns="http://www.w3.org/2000/svg">-<defs>-<font id="DroidSerif" horiz-adv-x="1145" >-<font-face font-family="Droid Serif" font-weight="400" font-stretch="normal" units-per-em="2048" panose-1="2 2 6 0 6 5 0 2 2 0" ascent="1638" descent="-410" x-height="1098" cap-height="1462" bbox="-25 -492 2126 1907" underline-thickness="102" underline-position="-103" unicode-range="U+0020-U+2122"/>-<missing-glyph horiz-adv-x="532" />-<glyph glyph-name=".notdef" horiz-adv-x="532" />-<glyph glyph-name=".null" horiz-adv-x="0" />-<glyph glyph-name="nonmarkingreturn" horiz-adv-x="682" />-<glyph glyph-name="space" unicode=" " horiz-adv-x="532" />-<glyph glyph-bame="tab" unicode="	" horiz-adv-x="532" />-<glyph glyph-bame="uni00A0" unicode=" " horiz-adv-x="532" />-<glyph glyph-name="exclam" unicode="!" horiz-adv-x="682" d="M221 1462h238l-72 -1050h-94zM211 125q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5q0 -39 -10.5 -66t-28 -43t-41 -23t-49.5 -7q-27 0 -50.5 7t-41 23t-27.5 43t-10 66z" />-<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="836" d="M502 1462h217l-62 -481h-94zM117 1462h217l-62 -481h-94z" />-<glyph glyph-name="numbersign" unicode="#" d="M397 537h285l76 401h-285zM1038 537v-121h-258l-78 -416h-122l77 416h-284l-78 -416h-123l78 416h-168v121h190l78 401h-244v121h267l73 403h125l-75 -403h284l76 403h123l-76 -403h160v-121h-182l-76 -401h233z" />-<glyph glyph-name="dollar" unicode="$" d="M621 1401q92 -2 156.5 -20.5t105.5 -49t59.5 -71.5t18.5 -89q0 -66 -44 -99.5t-118 -33.5q0 45 -7.5 90.5t-27 83t-54.5 63.5t-89 32v-478q92 -40 163 -80t119 -86.5t73 -103t25 -129.5q0 -154 -99 -239.5t-281 -104.5v-248h-103v244q-51 0 -103 4.5t-101.5 15t-95 26.5 t-83.5 38v315h86q0 -57 21.5 -110.5t61 -96t94 -70t120.5 -32.5v506q-96 43 -162.5 85t-107.5 88.5t-59.5 100.5t-18.5 121q0 69 24.5 125t69.5 97.5t109.5 67t144.5 34.5v159h103v-155zM813 399q0 41 -10 73.5t-33 60.5t-59.5 52t-89.5 48v-455q92 16 142 74.5t50 146.5z M354 1090q0 -43 10.5 -75.5t31.5 -57.5t51.5 -45t70.5 -38v429q-40 -9 -71 -28.5t-51.5 -47t-31 -62.5t-10.5 -75z" />-<glyph glyph-name="percent" unicode="%" horiz-adv-x="1835" d="M764 1030q0 -103 -21 -187t-63 -144t-105 -93t-147 -33q-88 0 -151.5 33t-104.5 93t-60.5 144t-19.5 187t19.5 186.5t60.5 143t105 91.5t153 32q84 0 146.5 -32t104 -91.5t62.5 -143t21 -186.5zM276 1030q0 -88 8 -157.5t26 -117.5t47 -73t71 -25t71 25t46.5 73t25 117.5 t7.5 157.5q0 87 -7.5 155t-25 115.5t-45.5 72t-70 24.5t-71.5 -24.5t-48 -72t-26.5 -115.5t-8 -155zM1743 436q0 -103 -21 -187t-63 -144t-105 -92.5t-147 -32.5q-88 0 -152 32.5t-104.5 92.5t-60 144t-19.5 187t19.5 186.5t60.5 143t105 91.5t153 32q84 0 146.5 -32 t104 -91.5t62.5 -143t21 -186.5zM1255 436q0 -88 8 -157.5t26 -117.5t47 -73t71 -25t71 25t46 73t24.5 117.5t7.5 157.5q0 87 -7.5 155t-24.5 115.5t-45 72t-70 24.5t-71.5 -24.5t-48 -72t-26.5 -115.5t-8 -155zM616 0h-135l731 1462h134z" />-<glyph glyph-name="ampersand" unicode="&" horiz-adv-x="1520" d="M1174 0l-170 180q-37 -42 -81.5 -78.5t-98.5 -63.5t-119.5 -42.5t-143.5 -15.5q-123 0 -214.5 31t-152 87.5t-90.5 135.5t-30 176q0 87 23.5 151.5t66 113.5t103 86t134.5 68q-39 46 -68.5 88.5t-49 84.5t-29.5 86t-10 94q0 68 22 123t69 95t120.5 61.5t175.5 21.5 q98 0 167 -23t112.5 -63t63 -93t19.5 -112q0 -66 -19 -117t-60.5 -94t-107 -81.5t-159.5 -78.5l373 -395q14 46 23 93.5t14.5 93t7.5 89t2 80.5v80h369v-86h-19q-34 0 -67 -4t-61.5 -18.5t-51 -42t-35.5 -74.5q-18 -66 -41.5 -143t-58.5 -154l190 -203q15 -15 31 -25 t37.5 -16t51 -8t71.5 -2h18v-86h-327zM580 94q60 0 111.5 12.5t94.5 34.5t79 52.5t65 66.5l-453 485q-47 -26 -84.5 -57.5t-64 -73t-40.5 -93.5t-14 -118q0 -75 22 -132.5t62.5 -97t96.5 -59.5t125 -20zM813 1190q0 41 -10 76t-32.5 60.5t-59 40.5t-88.5 15q-91 0 -140 -53 t-49 -141q0 -39 8 -73t25.5 -67.5t44.5 -69.5t66 -79q60 26 104.5 55t73.5 63.5t43 76.5t14 96z" />-<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="451" d="M117 1462h217l-62 -481h-94z" />-<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="709" d="M330 649q0 -122 9.5 -241t41.5 -225.5t94.5 -196.5t167.5 -154v-94q-141 56 -241 136t-163.5 190.5t-92.5 255t-29 329.5t29 328.5t92.5 253.5t163.5 189.5t241 135.5v-92q-105 -64 -167.5 -153.5t-94.5 -195.5t-41.5 -225t-9.5 -241z" />-<glyph glyph-name="parenright" unicode=")" horiz-adv-x="709" d="M379 649q0 122 -9.5 241t-42 225t-94.5 195.5t-167 153.5v92q141 -56 241 -135.5t163 -189.5t92.5 -253.5t29.5 -328.5t-29.5 -329.5t-92.5 -255t-163 -190.5t-241 -136v94q105 64 167 154t94.5 196.5t42 225.5t9.5 241z" />-<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="1024" d="M84 1268l72 162l315 -199l-53 325h178l-57 -323l317 192l72 -159l-346 -101l346 -100l-72 -158l-317 191l57 -324h-178l51 324l-313 -195l-72 160l344 102z" />-<glyph glyph-name="plus" unicode="+" d="M633 672v-379h-123v379h-377v121h377v378h123v-378h379v-121h-379z" />-<glyph glyph-name="comma" unicode="," horiz-adv-x="512" d="M397 86q0 -65 -18 -126t-58.5 -113t-104 -93.5t-155.5 -68.5v86q101 32 148 78t47 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38.5 90t95.5 31q32 0 60 -11.5t50 -34t34.5 -56t12.5 -76.5z" />-<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="635" d="M51 481v154h533v-154h-533z" />-<glyph glyph-name="period" unicode="." horiz-adv-x="586" d="M164 125q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5q0 -39 -10.5 -66t-28 -43t-41 -23t-49.5 -7q-27 0 -50.5 7t-41 23t-27.5 43t-10 66z" />-<glyph glyph-name="slash" unicode="/" horiz-adv-x="590" d="M121 -248h-121l471 1804h119z" />-<glyph glyph-name="zero" unicode="0" d="M1053 733q0 -169 -29.5 -308t-89.5 -238t-150 -153t-211 -54q-126 0 -217 54t-149.5 153t-86.5 238.5t-28 309.5t28 308t86.5 236t150 151t218.5 53q120 0 209.5 -53t149.5 -151t89.5 -236.5t29.5 -309.5zM305 733q0 -152 14 -271.5t45.5 -202t83 -126t125.5 -43.5 q75 0 126 43.5t82.5 126t45 202t13.5 271.5t-13.5 271t-45 201t-82 124.5t-124.5 42.5q-75 0 -126.5 -42.5t-83.5 -124.5t-46 -201t-14 -271z" />-<glyph glyph-name="one" unicode="1" d="M197 0v86h137q35 0 65.5 5t53 20.5t36 44.5t13.5 77v1076q-39 -48 -74 -87t-67 -67t-62.5 -43.5t-60.5 -15.5q-45 0 -74 30.5t-29 79.5q31 8 62.5 19.5t67 30t77 45t92.5 63.5l144 106h131v-1237q0 -48 13 -77t36 -44.5t53.5 -20.5t65.5 -5h100v-86h-780z" />-<glyph glyph-name="two" unicode="2" d="M944 1141q0 -72 -23 -140t-67 -139.5t-107.5 -148.5t-144.5 -166l-346 -383h473q46 0 76 13t49 34t29.5 48.5t17.5 57.5l8 37h86l-10 -354h-881v150l342 395q82 95 137.5 170t89.5 141.5t49 130t15 133.5q0 59 -12.5 106.5t-38 82t-65 53t-93.5 18.5q-70 0 -113.5 -25 t-68.5 -67t-34 -97t-9 -116q-37 0 -69 6t-56 21.5t-37.5 41t-13.5 64.5q0 59 25.5 109.5t76 87.5t125.5 57.5t174 20.5q97 0 174 -24.5t131 -69t82.5 -107.5t28.5 -141z" />-<glyph glyph-name="three" unicode="3" d="M508 90q61 0 116 17t97 56t67 102t25 155q0 65 -25.5 117.5t-73.5 89.5t-117 57.5t-155 20.5h-65v104h65q68 0 126.5 22.5t102 63.5t68.5 99.5t25 131.5q0 60 -12 107t-38.5 80t-68 50t-100.5 17q-70 0 -114 -25t-69 -67t-34 -97t-9 -116q-37 0 -69 6t-56 21.5t-37.5 41 t-13.5 64.5q0 59 25.5 109.5t76.5 87.5t126 57.5t174 20.5q97 0 176 -22t135.5 -63.5t87.5 -102t31 -138.5q0 -69 -24.5 -130t-68.5 -110.5t-104 -84.5t-131 -52q38 -4 81 -13.5t85 -27.5t80.5 -45t68 -66t47 -90.5t17.5 -119.5q0 -82 -22 -147t-60.5 -113.5t-89.5 -82.5 t-109 -55t-119 -30.5t-120 -9.5q-101 0 -174 18.5t-120.5 49.5t-70 72.5t-22.5 86.5q0 62 35 96.5t94 34.5q0 -54 17.5 -99.5t50.5 -78.5t81.5 -51.5t110.5 -18.5z" />-<glyph glyph-name="four" unicode="4" d="M862 401v-168q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-617v86h58q35 0 65.5 5t53 20.5t36 44.5t13.5 77v168h-631v84l633 977h194v-946h254v-115h-254zM666 895q0 45 1 99t2.5 110t4 111.5t6.5 103.5q-7 -14 -20 -37.5l-29.5 -52.5l-35 -61l-37 -62.5 l-34.5 -57t-28 -44.5l-314 -488h484v379z" />-<glyph glyph-name="five" unicode="5" d="M489 100q63 0 116.5 17.5t93 58t61.5 107t22 163.5q0 81 -22 141t-63 100t-98 59.5t-128 19.5q-53 0 -91.5 -4t-68 -10.5t-51.5 -14.5t-41 -16l-49 14l66 725h684l10 -309h-86l-8 61q-3 22 -8.5 37.5t-17.5 26t-32.5 15.5t-52.5 5h-397l-39 -450q31 11 89.5 22t149.5 11 q99 0 184.5 -27t148.5 -81t98.5 -135.5t35.5 -189.5q0 -104 -33.5 -190t-97 -147.5t-155.5 -95t-209 -33.5q-114 0 -188.5 19.5t-118.5 49.5t-62 66.5t-18 70.5q0 57 31.5 89t97.5 32q0 -44 15.5 -82t46 -65.5t77 -43.5t108.5 -16z" />-<glyph glyph-name="six" unicode="6" d="M659 1384q-154 0 -233 -151.5t-90 -450.5q25 21 55.5 40.5t66.5 34t78.5 23.5t92.5 9q94 0 170 -29t129.5 -83t82.5 -132t29 -176q0 -108 -29.5 -198t-86 -154.5t-138 -100.5t-186.5 -36q-102 0 -189 42.5t-150.5 134t-99.5 235t-36 345.5q0 97 14.5 190t43.5 176t73 153 t103.5 120.5t134.5 78.5t165 28q86 0 149.5 -18t105.5 -48t62.5 -69t20.5 -80q0 -59 -40 -91t-117 -32q0 50 -9.5 93.5t-31.5 76t-56 51t-84 18.5zM588 784q-40 0 -77 -10.5t-69.5 -27t-59.5 -38t-48 -42.5q2 -154 21.5 -263t54.5 -178t85 -101t111 -32q110 0 167.5 85.5 t57.5 271.5q0 175 -62.5 255t-180.5 80z" />-<glyph glyph-name="seven" unicode="7" d="M389 0l483 1296h-538q-110 0 -119 -104l-8 -102h-86l10 370h916v-59l-504 -1401h-154z" />-<glyph glyph-name="eight" unicode="8" d="M94 367q0 74 23.5 129.5t65.5 99t99 78.5t124 67q-58 33 -107 71.5t-84 84.5t-54.5 100.5t-19.5 118.5q0 71 25 137t78 117t137.5 82t202.5 31q96 0 171 -26.5t126.5 -73.5t78.5 -111.5t27 -141.5q0 -67 -20 -118t-56 -91.5t-87 -73t-113 -63.5q76 -36 138.5 -77 t107.5 -89t69.5 -104t24.5 -123q0 -97 -35 -173.5t-99 -129.5t-155 -80.5t-203 -27.5q-115 0 -202 30t-145.5 82.5t-88 123t-29.5 151.5zM569 74q67 0 121.5 20.5t93 56.5t59.5 86t21 109q0 52 -19 96.5t-62 86t-111.5 81t-167.5 82.5q-97 -52 -154 -135t-57 -199 q0 -64 17.5 -116t52 -89.5t86.5 -58t120 -20.5zM805 1135q0 47 -12.5 92t-40 80.5t-72 57t-109.5 21.5q-57 0 -101.5 -18.5t-74.5 -51t-45.5 -77.5t-15.5 -98q0 -55 17.5 -99t52 -80t86.5 -67.5t120 -63.5q58 29 95.5 59.5t59.5 67t31 80t9 97.5z" />-<glyph glyph-name="nine" unicode="9" d="M467 90q170 0 251 152t91 460q-22 -27 -51.5 -52t-67 -44.5t-83 -31t-99.5 -11.5q-89 0 -163.5 26t-128 78t-83 130t-29.5 182q0 111 30 203.5t86.5 159t138 104t184.5 37.5q104 0 191 -40t151 -124t99.5 -214t35.5 -310q0 -107 -13.5 -209.5t-42 -193.5t-73 -167 t-106 -131.5t-141.5 -86t-179 -30.5q-87 0 -144.5 15.5t-91 40.5t-47.5 57t-14 64q0 38 19 64t42 34q14 -32 34.5 -61.5t50 -52t67.5 -35.5t86 -13zM553 684q50 1 91.5 14.5t73.5 36t55.5 52.5t37.5 63v4q-2 135 -22 232.5t-55 160.5t-83.5 93t-107.5 30q-109 0 -168.5 -95 t-59.5 -276q0 -84 15 -144t45 -98t74.5 -55.5t103.5 -17.5z" />-<glyph glyph-name="colon" unicode=":" horiz-adv-x="588" d="M166 125q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5q0 -39 -10.5 -66t-28 -43t-41 -23t-49.5 -7q-27 0 -50.5 7t-41 23t-27.5 43t-10 66zM166 969q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5 q0 -39 -10.5 -66t-28 -43.5t-41 -23.5t-49.5 -7q-27 0 -50.5 7t-41 23.5t-27.5 43.5t-10 66z" />-<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="512" d="M397 86q0 -65 -18 -126t-58.5 -113t-104 -93.5t-155.5 -68.5v86q101 32 148 78t47 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38.5 90t95.5 31q32 0 60 -11.5t50 -34t34.5 -56t12.5 -76.5zM129 969q0 40 10 66.5t27.5 42.5t41 23t50.5 7 q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5q0 -39 -10.5 -66t-28 -43.5t-41 -23.5t-49.5 -7q-27 0 -50.5 7t-41 23.5t-27.5 43.5t-10 66z" />-<glyph glyph-name="less" unicode="<" d="M133 696v72l879 473v-137l-688 -373l688 -369v-137z" />-<glyph glyph-name="equal" unicode="=" d="M1012 590v-121h-879v121h879zM1012 993v-121h-879v121h879z" />-<glyph glyph-name="greater" unicode=">" d="M133 225v137l688 369l-688 373v137l879 -473v-72z" />-<glyph glyph-name="question" unicode="?" horiz-adv-x="1024" d="M522 412h-125v311q89 36 149.5 83.5t97 103t52 116t15.5 121.5q0 53 -13 96.5t-40 74t-69.5 47.5t-101.5 17q-64 0 -107.5 -21t-70.5 -57t-39 -83.5t-12 -100.5q-37 0 -68 8.5t-53.5 25t-35.5 41.5t-13 58q0 49 22.5 91t70 73t119.5 48.5t171 17.5q97 0 179 -25 t142 -72.5t94 -116.5t34 -157q0 -84 -26.5 -153t-77.5 -126t-125 -104t-169 -86v-231zM328 125q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5q0 -39 -10.5 -66t-28 -43t-41 -23t-49.5 -7q-27 0 -50.5 7t-41 23t-27.5 43t-10 66z" />-<glyph glyph-name="at" unicode="@" horiz-adv-x="1886" d="M1778 803q0 -148 -36 -267.5t-94 -203.5t-129.5 -129t-142.5 -45q-91 0 -151.5 49t-89.5 137h-11q-21 -40 -47.5 -74t-60 -59t-75 -39t-93.5 -14q-62 0 -118.5 21t-99 64t-68 109t-25.5 156q0 55 12.5 119t39 127.5t68 123t99.5 105t133.5 73t169.5 27.5q66 0 113.5 -18 t78.5 -43l82 43h49l-104 -522q-3 -24 -7 -48q-3 -20 -5 -44t-2 -45q0 -36 10.5 -62.5t27.5 -44t39.5 -25.5t47.5 -8q45 0 92 36t85 105.5t62.5 170.5t24.5 231q0 134 -43 236.5t-119.5 172t-183 105t-234.5 35.5q-100 0 -196.5 -28t-182.5 -82.5t-159.5 -133t-126.5 -179 t-83 -222.5t-30 -262q0 -171 49 -291.5t132.5 -197t194 -111.5t234.5 -35q84 0 159 14.5t140.5 38.5t121 54.5t99.5 62.5l48 -74q-51 -38 -114 -74.5t-136.5 -65t-158 -46t-179.5 -17.5q-165 0 -303 45.5t-237.5 137.5t-155.5 230t-56 324q0 145 31.5 276.5t91 244.5 t144 204.5t190.5 156t230.5 99.5t264.5 35q172 0 302 -51t217 -139.5t130.5 -209t43.5 -259.5zM727 479q0 -108 43.5 -160.5t112.5 -52.5q52 0 90 22.5t64 58.5t42 82t25 93l78 416q-13 29 -45.5 45t-69.5 16q-61 0 -110.5 -26.5t-87 -69.5t-64.5 -98.5t-44.5 -113.5 t-25.5 -113t-8 -99z" />-<glyph glyph-name="A" unicode="A" horiz-adv-x="1444" d="M414 489l-78 -215q-9 -24 -14 -47.5t-5 -40.5q0 -52 33.5 -76t102.5 -24h47v-86h-500v86h39q30 0 51 6.5t38 24.5t32.5 49t34.5 80l454 1216h160l463 -1267q12 -32 24.5 -53t29.5 -33.5t39 -17.5t52 -5h27v-86h-563v86h47q123 0 123 98q0 17 -4.5 35t-12.5 41l-82 229 h-538zM788 950l-58.5 170.5t-43.5 153.5q-7 -37 -16.5 -71.5t-20.5 -70.5t-25 -75.5l-32 -87.5l-139 -377h462z" />-<glyph glyph-name="B" unicode="B" horiz-adv-x="1339" d="M1153 1096q0 -69 -19.5 -121t-53.5 -91t-80.5 -65.5t-100.5 -44.5v-8q70 -12 128 -41t99.5 -75.5t64.5 -110t23 -144.5q0 -198 -130 -296.5t-396 -98.5h-610v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v1004q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86 h549q266 0 396 -88.5t130 -277.5zM479 102h199q87 0 147 16t98 51.5t55 92.5t17 139q0 80 -15 139t-51.5 98t-96.5 58t-150 19h-203v-613zM479 817h142q90 0 150 16t96 49.5t51.5 86.5t15.5 127q0 75 -17 125.5t-55 81.5t-98.5 44t-147.5 13h-137v-543z" />-<glyph glyph-name="C" unicode="C" horiz-adv-x="1257" d="M774 1483q105 0 182.5 -17.5t129 -48.5t77 -73t25.5 -91q0 -33 -13.5 -59.5t-37.5 -45t-56.5 -28.5t-70.5 -10q0 48 -12.5 95t-41 84.5t-74 61t-112.5 23.5q-116 0 -197 -42.5t-132 -124t-74 -201t-23 -273.5q0 -137 24 -251t76 -195.5t132.5 -126.5t193.5 -45 q75 0 132.5 14.5t101.5 38.5t77.5 55.5t59.5 65.5q17 -11 28 -30t11 -50q0 -39 -26.5 -79.5t-80.5 -73.5t-137 -54.5t-197 -21.5q-153 0 -269 54t-194.5 153t-118.5 238t-40 308q0 166 42 304t124.5 237t205.5 154t285 55z" />-<glyph glyph-name="D" unicode="D" horiz-adv-x="1489" d="M1372 733q0 -168 -42 -303.5t-125 -231t-208 -147t-292 -51.5h-627v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v1004q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h627q158 0 282 -48.5t209.5 -141.5t130.5 -229t45 -310zM657 104q122 0 213.5 41.5 t152.5 121.5t91.5 197t30.5 269q0 305 -121.5 466t-364.5 161h-180v-1256h178z" />-<glyph glyph-name="E" unicode="E" horiz-adv-x="1276" d="M479 102h395q49 0 83.5 13.5t57.5 36.5t36 53.5t18 64.5l14 88h107l-14 -358h-1098v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1006q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h1032l10 -358h-106l-10 88q-4 34 -15.5 64.5t-33 53.5t-54 36.5t-78.5 13.5 h-344v-545h494v-100h-494v-613z" />-<glyph glyph-name="F" unicode="F" horiz-adv-x="1208" d="M479 1360v-592h494v-100h-494v-435q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h68v-86h-637v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1014q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h1032l10 -358h-106l-10 88q-4 35 -16 65.5t-34.5 53 t-56.5 36t-82 13.5h-336z" />-<glyph glyph-name="G" unicode="G" horiz-adv-x="1462" d="M821 -20q-178 0 -310.5 54t-220 153t-130.5 238t-43 308q0 166 45.5 304t136 237t224.5 154t311 55q114 0 198.5 -17.5t141 -48.5t84.5 -73t28 -91q0 -33 -15 -59.5t-40.5 -45t-60 -28.5t-74.5 -10q0 48 -14 95t-46 84.5t-84 61t-127 23.5q-130 0 -221.5 -42.5 t-149.5 -124t-84 -201t-26 -273.5q0 -153 27 -272t88 -200t158 -123t237 -42q59 0 114.5 6t98.5 19v330q0 45 -13.5 72.5t-36.5 42t-53.5 19.5t-64.5 5h-8v86h532v-86h-8q-29 0 -55 -5t-45 -20.5t-30 -45t-11 -77.5v-368q-103 -48 -212 -71t-241 -23z" />-<glyph glyph-name="H" unicode="H" horiz-adv-x="1624" d="M950 0v86h27q35 0 65.5 5t53 20.5t36 44.5t13.5 77v480h-666v-480q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-596v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v1004q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5 t-53.5 -20.5t-36 -44.5t-13.5 -77v-414h666v414q0 48 -13.5 77t-36 44.5t-53 20.5t-65.5 5h-27v86h596v-86h-26q-35 0 -65.5 -5t-53.5 -20.5t-36 -44.5t-13 -77v-1006q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h26v-86h-596z" />-<glyph glyph-name="I" unicode="I" horiz-adv-x="752" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v996q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-996q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-596z" />-<glyph glyph-name="J" unicode="J" horiz-adv-x="731" d="M-23 -395h19q66 0 117.5 18.5t86.5 62t53.5 116t18.5 180.5v1255q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-1245q0 -138 -36 -229.5t-99 -146t-148.5 -77.5t-183.5 -23h-35v97z" />-<glyph glyph-name="K" unicode="K" horiz-adv-x="1434" d="M903 1137q33 38 55 67.5t34.5 53.5t18 42t5.5 33q0 26 -25 35.5t-76 9.5v84h453v-84q-35 0 -67.5 -13.5t-65 -38t-67 -60l-74.5 -80.5l-297 -334l432 -602q59 -81 113.5 -122.5t111.5 -41.5h4v-86h-22q-103 0 -169 8t-111 29t-78.5 56.5t-71.5 90.5l-353 506l-174 -141 v-316q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-596v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1014q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-578z" />-<glyph glyph-name="L" unicode="L" horiz-adv-x="1276" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v996q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h596v-86h-27q-34 0 -64.5 -4.5t-53.5 -19.5t-36.5 -42.5t-13.5 -72.5v-1135h404q46 0 78.5 16.5t53.5 43t32.5 59.5t15.5 66l20 153h107l-14 -440h-1098z" />-<glyph glyph-name="M" unicode="M" horiz-adv-x="1921" d="M1298 0v86h7q33 0 59.5 4.5t45 18t29.5 39t13 67.5v1094l-469 -1309h-111l-475 1305v-1072q0 -48 10 -77t29.5 -44.5t47 -20.5t61.5 -5h6v-86h-473v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1014q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h467 l424 -1171l420 1171h454v-86h-26q-35 0 -65.5 -5t-53.5 -20.5t-36 -44.5t-13 -77v-996q0 -48 13 -77t36 -44.5t53.5 -20.5t65.5 -5h26v-86h-545z" />-<glyph glyph-name="N" unicode="N" horiz-adv-x="1563" d="M1165 0l-768 1180v-947q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-514v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v1004q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h375l733 -1132v907q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-27v86 h514v-86h-26q-35 0 -65.5 -5t-53.5 -20.5t-36 -44.5t-13 -77v-1229h-146z" />-<glyph glyph-name="O" unicode="O" horiz-adv-x="1520" d="M1403 733q0 -169 -42 -308t-124 -238t-202 -153t-275 -54q-163 0 -284 54t-201 153t-120 238.5t-40 309.5t40 308.5t120 236.5t202 151.5t285 53.5q155 0 274 -53.5t201 -152t124 -237t42 -309.5zM342 733q0 -152 22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5 t193.5 43.5t129 126t71.5 202t22 271.5t-22 271.5t-71.5 201.5t-128 125t-192.5 43t-194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5z" />-<glyph glyph-name="P" unicode="P" horiz-adv-x="1237" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v1004q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h575q129 0 224 -29.5t157 -85t92.5 -134.5t30.5 -179q0 -91 -28.5 -175t-93.5 -148.5t-170 -103t-257 -38.5h-129v-346q0 -45 13.5 -72.5t36.5 -41.5 t53.5 -18.5t64.5 -4.5h68v-86h-637zM479 666h109q93 0 159 19.5t108 63t61.5 112t19.5 165.5q0 86 -17 149.5t-55 105.5t-98.5 62.5t-147.5 20.5h-139v-698z" />-<glyph glyph-name="Q" unicode="Q" horiz-adv-x="1520" d="M1403 733q0 -150 -33 -276t-97.5 -222t-159 -158.5t-216.5 -84.5q9 -105 34 -175.5t64 -113t91 -60.5t114 -18h33v-96h-88q-81 0 -161.5 21.5t-146.5 74t-110.5 140t-54.5 219.5q-141 15 -245.5 74.5t-173.5 157t-103.5 229t-34.5 290.5q0 170 40 308.5t120 236.5 t202 151.5t285 53.5q155 0 274 -53.5t201 -152t124 -237t42 -309.5zM342 733q0 -152 22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5t193.5 43.5t129 126t71.5 202t22 271.5t-22 271.5t-71.5 201.5t-128 125t-192.5 43t-194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5z" />-<glyph glyph-name="R" unicode="R" horiz-adv-x="1343" d="M1135 250q52 -82 101 -123t114 -41h6v-86h-29q-96 0 -157.5 7t-104.5 27t-73.5 56t-65.5 94l-277 461h-170v-422q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h27v-86h-596v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1014q0 45 -13.5 72.5t-36.5 42.5 t-53.5 19.5t-64.5 4.5h-26v86h551q266 0 396 -98.5t130 -296.5q0 -82 -26.5 -143.5t-69.5 -106.5t-97 -75t-108 -48zM479 741h144q90 0 150 20t96 60t51.5 100t15.5 140q0 82 -17 139.5t-55 94t-98.5 53t-147.5 16.5h-139v-623z" />-<glyph glyph-name="S" unicode="S" horiz-adv-x="1114" d="M506 -20q-100 0 -176.5 21t-128 58.5t-77.5 91t-26 117.5q0 62 38.5 100t109.5 38q3 -64 19.5 -123t49.5 -104t84 -72t123 -27q138 0 215.5 66.5t77.5 191.5q0 56 -16 99t-53 79.5t-97.5 70t-150.5 70.5q-95 39 -166 83.5t-118 99t-70 121.5t-23 151q0 88 33.5 157 t93.5 116.5t142 72.5t179 25q92 0 163 -19t120 -51t74.5 -73.5t25.5 -86.5q0 -66 -43.5 -99.5t-117.5 -33.5q0 48 -11.5 94.5t-38.5 83t-71 59.5t-109 23q-59 0 -105.5 -16.5t-78.5 -47t-49 -73.5t-17 -96q0 -61 16 -107.5t53.5 -84t98.5 -71t150 -69.5q90 -37 160.5 -78 t119.5 -91.5t75 -113t26 -141.5q0 -97 -35.5 -173.5t-101.5 -129.5t-159 -80.5t-208 -27.5z" />-<glyph glyph-name="T" unicode="T" horiz-adv-x="1255" d="M729 233q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h47v-86h-637v86h47q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1137h-196q-45 0 -75.5 -13.5t-50 -36.5t-29 -53.5t-13.5 -64.5l-11 -88h-106l10 358h1153l10 -358h-106l-10 88q-4 34 -14 64.5t-29 53.5t-50 36.5 t-77 13.5h-199v-1127z" />-<glyph glyph-name="U" unicode="U" horiz-adv-x="1468" d="M741 -20q-121 0 -217 25.5t-162.5 81t-101.5 143t-35 212.5v795q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-799q0 -89 25.5 -151.5t71 -101.5t108 -57t137.5 -18q89 0 153.5 24t107 66.5 t63 101t20.5 128.5v815q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h514v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-811q0 -102 -32.5 -183.5t-96 -138t-157.5 -86.5t-216 -30z" />-<glyph glyph-name="V" unicode="V" horiz-adv-x="1382" d="M614 0l-442 1268q-11 32 -24 53t-30 33t-39 17t-52 5h-27v86h563v-86h-47q-62 0 -92.5 -23.5t-30.5 -74.5q0 -17 4.5 -35t12.5 -41l225 -665q31 -91 53 -176.5t39 -159.5q16 74 38 157t56 179l226 651q8 25 13 48t5 40q0 53 -33.5 76.5t-101.5 23.5h-47v86h499v-86h-39 q-30 0 -51.5 -6t-39 -23.5t-32.5 -48.5t-32 -81l-424 -1217h-150z" />-<glyph glyph-name="W" unicode="W" horiz-adv-x="2144" d="M1180 1448l256 -887q29 -102 51.5 -195.5t36.5 -164.5q15 74 34.5 155.5t47.5 180.5l180 632l7 27t7 30l5.5 28t2.5 22q0 53 -33.5 76.5t-101.5 23.5h-47v86h500v-86h-39q-30 0 -52.5 -6t-40.5 -23t-33 -48t-30 -82l-346 -1217h-184l-334 1147l-313 -1147h-189l-375 1268 q-10 32 -22.5 53t-29.5 33t-40 17t-53 5h-27v86h564v-86h-47q-62 0 -92.5 -23.5t-30.5 -74.5q0 -17 5 -35l11 -41l188 -655l49 -182.5t40 -163.5q15 80 35.5 174.5t47.5 193.5l244 879h148z" />-<glyph glyph-name="X" unicode="X" horiz-adv-x="1352" d="M954 1317q0 18 -8.5 29.5t-23 18t-34.5 9t-44 2.5h-6v86h448v-86h-18q-30 0 -54.5 -7t-47.5 -24.5t-47.5 -45.5t-53.5 -70l-297 -428l377 -606q45 -60 85 -84.5t79 -24.5h26v-86h-553v86h11q122 0 122 68q0 11 -2.5 22t-9.5 26t-20.5 37l-34.5 56l-203 326l-227 -336 q-9 -13 -18 -29.5t-17 -34.5t-13 -36.5t-5 -34.5q0 -35 32.5 -49.5t100.5 -14.5h6v-86h-488v86h13q37 0 64.5 7.5t51 24.5t46.5 44t51 67l342 490l-338 549q-37 59 -83.5 83.5t-92.5 24.5h-27v86h555v-86h-6q-35 0 -58 -4.5t-36 -12.5t-18 -19t-5 -23q0 -11 1.5 -21 t6.5 -23.5t14.5 -31.5t26.5 -45l185 -299l194 295q23 35 37 66t14 59z" />-<glyph glyph-name="Y" unicode="Y" horiz-adv-x="1280" d="M326 0v86h47q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v387l-379 658q-17 29 -32 49.5t-31.5 33.5t-36.5 19t-46 6h-26v86h563v-86h-76q-28 0 -45.5 -5t-27.5 -14t-13.5 -21t-3.5 -25q0 -29 12.5 -58t24.5 -51l151 -274q36 -63 61 -124.5t42 -109.5q9 22 22.5 49 l30 57.5l34.5 63l36 64.5l131 235q20 35 28.5 66.5t8.5 56.5q0 45 -32 67.5t-91 22.5h-60v86h500v-86h-24q-22 0 -41.5 -7.5t-39.5 -26t-41.5 -49t-47.5 -76.5l-344 -607v-377q0 -48 13 -77t36 -44.5t53.5 -20.5t64.5 -5h48v-86h-637z" />-<glyph glyph-name="Z" unicode="Z" horiz-adv-x="1212" d="M1094 1378l-770 -1276h516q46 0 77 13.5t50 36.5t29 53.5t14 64.5l10 88h106l-10 -358h-1042v82l768 1278h-445q-45 0 -75.5 -13.5t-49.5 -36.5t-29 -53.5t-14 -64.5l-10 -88h-106l10 358h971v-84z" />-<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="735" d="M205 -262v1818h457v-86h-89q-34 0 -64.5 -5t-53.5 -20.5t-36 -44.5t-13 -77v-1352q0 -48 13 -77t36 -44.5t53.5 -20.5t64.5 -5h89v-86h-457z" />-<glyph glyph-name="backslash" unicode="\" horiz-adv-x="590" d="M0 1556h119l471 -1804h-121z" />-<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="737" d="M76 -262v86h88q35 0 65.5 5t53 20.5t36 44.5t13.5 77v1352q0 48 -13.5 77t-36 44.5t-53 20.5t-65.5 5h-88v86h456v-1818h-456z" />-<glyph glyph-name="asciicircum" unicode="^" d="M535 1462h71l432 -917h-137l-332 729l-327 -729h-138z" />-<glyph glyph-name="underscore" unicode="_" horiz-adv-x="940" d="M950 -291h-960v121h960v-121z" />-<glyph glyph-name="grave" unicode="`" horiz-adv-x="1182" d="M791 1241h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="a" unicode="a" horiz-adv-x="1153" d="M301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v166l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM549 1016q-59 0 -95.5 -16.5t-57 -46.5t-27.5 -71t-7 -89q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5 t143 11q94 0 164 -18.5t117 -60.5t70.5 -109.5t23.5 -165.5v-531q0 -43 7 -71t22 -45t39.5 -24t58.5 -7h6v-86h-277l-32 176h-17q-32 -43 -62 -79t-66 -62t-81.5 -40.5t-109.5 -14.5q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123 q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5z" />-<glyph glyph-name="b" unicode="b" horiz-adv-x="1257" d="M1145 551q0 -148 -27.5 -256t-80.5 -178t-131 -103.5t-179 -33.5q-59 0 -107 13t-86.5 37t-68 57t-51.5 73h-13l-36 -160h-328v86h16q35 0 65.5 5t53 20.5t36 44.5t13.5 77v1098q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-16v86h377v-376q0 -35 -1 -80.5 t-3 -87.5l-4 -99h8q23 47 52 85t67 64.5t86 41t108 14.5q101 0 179 -33.5t131 -103t80.5 -176.5t27.5 -254zM692 987q-80 0 -133.5 -26.5t-85.5 -80.5t-45.5 -136t-13.5 -193q0 -107 13.5 -189t46 -138t86 -84.5t134.5 -28.5q68 0 115.5 28.5t78 84.5t44.5 138.5t14 190.5 q0 109 -14 190.5t-44.5 135.5t-79 81t-116.5 27z" />-<glyph glyph-name="c" unicode="c" horiz-adv-x="1008" d="M580 -20q-102 0 -188 31.5t-148 99.5t-96.5 174.5t-34.5 257.5q0 164 34.5 274.5t96 177.5t145 95t180.5 28q64 0 127.5 -12.5t114.5 -38.5t83 -65.5t32 -92.5q0 -71 -46 -100t-137 -29q0 48 -8 91t-27.5 75.5t-53 51t-85.5 18.5q-59 0 -106.5 -22t-81.5 -76t-52 -145 t-18 -228q0 -218 72.5 -325t237.5 -107q95 0 166 40t106 103q15 -12 25 -32t10 -48q0 -35 -22 -70t-65.5 -63t-108.5 -45.5t-152 -17.5z" />-<glyph glyph-name="d" unicode="d" horiz-adv-x="1257" d="M1036 225q0 -45 13.5 -72.5t36.5 -42.5t53.5 -19.5t64.5 -4.5h17v-86h-347l-22 184h-8q-23 -47 -52.5 -84.5t-67.5 -64t-86 -41t-108 -14.5q-101 0 -179 33.5t-131 103t-80 176.5t-27 254q0 148 27 256t80 178t131 103.5t179 33.5q59 0 107 -13t86.5 -37t68.5 -57t52 -73 h12q-3 50 -6 94l-4 75.5t-2 55.5v168q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-17v86h377v-1331zM565 111q80 0 133.5 26.5t86 80.5t46 136t13.5 193q0 107 -13.5 189t-46 137.5t-86.5 84.5t-135 29q-67 0 -115 -29t-78.5 -85t-44.5 -138.5t-14 -189.5 q0 -218 59 -326t195 -108z" />-<glyph glyph-name="e" unicode="e" horiz-adv-x="1096" d="M563 1008q-114 0 -175.5 -92.5t-72.5 -270.5h471q0 81 -12 148t-38 115t-68.5 74t-104.5 26zM588 -20q-111 0 -199.5 37.5t-149.5 109.5t-93.5 176.5t-32.5 237.5q0 287 118 432t336 145q99 0 178 -31t134 -92.5t84.5 -153t29.5 -212.5v-94h-682q2 -112 22.5 -192.5 t59 -132.5t94.5 -76.5t129 -24.5q53 0 98.5 12t82.5 32t65.5 45.5t46.5 53.5q14 -6 26.5 -25t12.5 -45q0 -31 -22 -66.5t-67 -65.5t-112.5 -50t-158.5 -20z" />-<glyph glyph-name="f" unicode="f" horiz-adv-x="756" d="M688 86v-86h-633v86h27q35 0 65.5 5t53 20.5t36 44.5t13.5 77v768h-187v97h187v102q0 92 25 162t72 118t114 72.5t151 24.5q80 0 135 -10.5t88.5 -29.5t48.5 -45t15 -58q0 -28 -12.5 -49.5t-35 -36t-53 -22t-67.5 -7.5q0 31 -6.5 60.5t-22 52.5t-41.5 37t-65 14 q-44 0 -73.5 -17t-47.5 -50.5t-25.5 -82.5t-7.5 -114v-121h289v-97h-289v-768q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h78z" />-<glyph glyph-name="g" unicode="g" horiz-adv-x="1102" d="M1077 1055q0 -22 -6.5 -41.5t-19.5 -34t-33.5 -23t-48.5 -8.5q0 12 -3 24t-10.5 22.5t-20.5 17t-34 6.5q-26 0 -47 -6t-41 -19q35 -43 57.5 -101.5t22.5 -146.5q0 -76 -23 -140.5t-68.5 -111.5t-115 -73.5t-162.5 -26.5q-12 0 -27 0.5l-30 1t-28 2l-21 2.5 q-20 -10 -38 -22t-31.5 -27t-21.5 -34t-8 -42q0 -25 9.5 -40t26.5 -23.5t40.5 -11t50.5 -2.5h232q92 0 156 -23t104.5 -63.5t59 -97t18.5 -122.5q0 -88 -32.5 -159t-99.5 -120.5t-169.5 -76.5t-241.5 -27q-214 0 -320 79t-106 220q0 60 21 105t56.5 77t81.5 52t97 29 q-21 9 -41 24t-36 36t-26 48t-10 60q0 61 32 105.5t102 86.5q-44 18 -78.5 49.5t-58 72t-36 88.5t-12.5 99q0 89 24 159t72 119t120 75t169 26q37 0 73 -5.5t66.5 -15t55 -21.5t39.5 -25q15 16 35 35.5t45 36t54.5 27.5t63.5 11q31 0 53.5 -8.5t37.5 -23t22.5 -34t7.5 -40.5 zM213 -180q0 -45 12 -84t42 -67t81 -44t129 -16q110 0 181.5 18.5t113.5 51.5t59 78.5t17 99.5q0 47 -13.5 77.5t-40 48t-65.5 24.5t-90 7h-201q-43 0 -83.5 -7.5t-72 -28.5t-50.5 -59t-19 -99zM332 745q0 -131 43.5 -192t142.5 -61q50 0 84.5 15t56.5 46t31.5 79.5 t9.5 115.5q0 138 -42 204t-142 66q-99 0 -141.5 -67.5t-42.5 -205.5z" />-<glyph glyph-name="h" unicode="h" horiz-adv-x="1300" d="M588 86v-86h-551v86h16q35 0 65.5 5t53 20.5t36 44.5t13.5 77v1098q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-16v86h377v-450q0 -28 -1 -58.5t-3 -56.5l-4 -59h10q92 186 301 186q87 0 154.5 -23.5t113.5 -72t70 -124.5t24 -181v-484q0 -48 12 -77t33 -44.5 t50 -20.5t63 -5h6v-86h-356v707q0 67 -12 119t-38.5 88t-69.5 54.5t-105 18.5q-64 0 -110.5 -23.5t-77 -67t-45.5 -105t-15 -136.5v-432q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6z" />-<glyph glyph-name="i" unicode="i" horiz-adv-x="655" d="M74 86q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v649q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h366v-865q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-582v86h27zM213 1430q0 36 9 60t25 39t37 21t46 6q24 0 45 -6t36.5 -21t25 -39t9.5 -60 t-9.5 -60t-25 -39t-36.5 -21.5t-45 -6.5q-25 0 -46 6.5t-37 21.5t-25 39t-9 60z" />-<glyph glyph-name="j" unicode="j" horiz-adv-x="614" d="M414 1098v-1114q0 -138 -30 -229.5t-84 -146t-128.5 -77.5t-163.5 -23h-33v97h15q55 0 98 18.5t72.5 62t45 116t15.5 180.5v890q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h367zM193 1430q0 36 9 60t24.5 39t37 21t45.5 6t45.5 -6t37 -21t25 -39t9.5 -60 t-9.5 -60t-25 -39t-37 -21.5t-45.5 -6.5t-45.5 6.5t-37 21.5t-24.5 39t-9 60z" />-<glyph glyph-name="k" unicode="k" horiz-adv-x="1198" d="M694 659l273 -405q53 -82 105.5 -125t121.5 -43h6v-86h-29q-89 0 -146.5 5.5t-99.5 26t-77 60t-78 107.5l-205 321l-151 -112v-185q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6v-86h-551v86h16q35 0 65.5 5t53 20.5t36 44.5t13.5 77v1098q0 45 -13.5 72.5 t-36.5 42.5t-53.5 19.5t-64.5 4.5h-16v86h377v-790q0 -28 -1 -71.5t-3 -85.5l-4 -101l256 280q33 37 54.5 65t34.5 49t18 37.5t5 31.5q0 26 -24.5 33.5t-75.5 7.5v86h452v-86q-71 0 -139.5 -50t-148.5 -141z" />-<glyph glyph-name="l" unicode="l" horiz-adv-x="635" d="M53 86q35 0 65.5 5t53 20.5t36 44.5t13.5 77v1098q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h387v-1323q0 -48 13 -77t36 -44.5t53.5 -20.5t65.5 -5h26v-86h-581v86h26z" />-<glyph glyph-name="m" unicode="m" horiz-adv-x="1935" d="M608 86v-86h-551v86h27q35 0 64 5t50 20.5t32.5 44.5t11.5 77v639q0 45 -12 72.5t-33 42.5t-50 20t-63 5h-6v86h321l27 -166h10q31 57 65 93.5t72.5 57t81 28t90.5 7.5q50 0 95 -10t83.5 -32t69 -57.5t49.5 -86.5h17q31 57 67 93.5t76.5 57t85 28t92.5 7.5 q78 0 140 -23.5t105 -72t66 -124.5t23 -181v-484q0 -48 12 -77t33 -44.5t50 -20.5t63 -5h6v-86h-356v707q0 67 -11.5 119t-37 88t-66.5 54.5t-100 18.5q-64 0 -107.5 -24.5t-70.5 -66.5t-38.5 -97t-11.5 -117v-449q0 -48 12 -77t33 -44.5t50 -20.5t63 -5h6v-86h-356v707 q0 67 -11.5 119t-37 88t-66.5 54.5t-100 18.5q-67 0 -112.5 -27t-73.5 -73t-40 -106t-12 -126v-432q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6z" />-<glyph glyph-name="n" unicode="n" horiz-adv-x="1321" d="M608 86v-86h-551v86h17q35 0 65.5 5t53 20.5t36 44.5t13.5 77v639q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h331l27 -166h10q32 57 67.5 93.5t75 57t84 28t93.5 7.5q81 0 144.5 -23.5t108 -72t68 -124.5t23.5 -181v-484q0 -48 11.5 -77t32.5 -44.5t50 -20.5 t63 -5h7v-86h-357v707q0 67 -12 119t-38.5 88t-69.5 54.5t-105 18.5q-70 0 -117.5 -27t-76.5 -73t-41.5 -106t-12.5 -126v-432q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6z" />-<glyph glyph-name="o" unicode="o" horiz-adv-x="1182" d="M1069 551q0 -289 -122.5 -430t-358.5 -141q-111 0 -199 35t-149.5 106t-94 178.5t-32.5 251.5q0 287 121.5 427t359.5 140q111 0 199 -34.5t149.5 -105t94 -177t32.5 -250.5zM311 551q0 -114 15 -201t48.5 -145.5t87 -88.5t130.5 -30t130 30t86 88.5t47.5 145.5t14.5 201 t-15 200t-48 143.5t-86.5 86.5t-130.5 29t-130 -29t-86 -86.5t-48 -143.5t-15 -200z" />-<glyph glyph-name="p" unicode="p" horiz-adv-x="1257" d="M692 987q-80 0 -133.5 -26.5t-85.5 -80.5t-45.5 -136t-13.5 -193q0 -107 13.5 -189t46 -138t86 -84.5t134.5 -28.5q68 0 115.5 28.5t78 84.5t44.5 138.5t14 190.5q0 109 -14 190.5t-44.5 135.5t-79 81t-116.5 27zM1145 551q0 -148 -27.5 -256t-80.5 -178t-131 -103.5 t-179 -33.5q-59 0 -107 13t-86.5 37t-68 57t-51.5 73h-8q2 -53 4 -99q1 -19 1.5 -39.5t1 -38.5t1 -32.5t0.5 -22.5v-196q0 -45 13.5 -72.5t36.5 -42t53.5 -19t64.5 -4.5h6v-86h-551v86h16q35 0 65.5 5t53 20.5t36 45t13.5 77.5v1130q0 45 -13.5 72.5t-36.5 42.5t-53.5 20 t-64.5 5h-26v86h358l21 -185h8q23 47 52 85t67 64.5t86 41t108 14.5q101 0 179 -33.5t131 -103t80.5 -176.5t27.5 -254z" />-<glyph glyph-name="q" unicode="q" horiz-adv-x="1257" d="M1221 -492h-613v86h68q35 0 65.5 5t53 20.5t36 45t13.5 77.5v176q0 35 1 80.5t3 87.5l4 98h-8q-23 -47 -52.5 -84.5t-67.5 -64t-86 -41t-108 -14.5q-101 0 -179 33.5t-131 103t-80 176.5t-27 254q0 148 27 256t80 178t131 103.5t179 33.5q59 0 107 -13t86.5 -37t68.5 -57 t52 -73h12l37 160h328v-86h-17q-34 0 -65 -5t-53.5 -20.5t-36 -45t-13.5 -77.5v-1130q0 -45 13.5 -72.5t36.5 -42.5t53.5 -20t64.5 -5h17v-86zM565 111q80 0 133.5 26.5t86 80.5t46 136t13.5 193q0 107 -13.5 189t-46 137.5t-86.5 84.5t-135 29q-67 0 -115 -29t-78.5 -85 t-44.5 -138.5t-14 -189.5q0 -218 59 -326t195 -108z" />-<glyph glyph-name="r" unicode="r" horiz-adv-x="965" d="M659 0h-591v86h6q35 0 65.5 5t53 20.5t36 44.5t13.5 77v639q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h315l39 -203h10q20 46 41 86.5t51.5 71t75.5 48t113 17.5q112 0 166.5 -39t54.5 -110q0 -32 -10.5 -59t-33.5 -46.5t-59 -30t-88 -10.5q0 85 -24 122.5 t-84 37.5q-38 0 -68 -21.5t-52.5 -57t-38 -81.5t-25 -94.5t-13.5 -96.5t-4 -87v-322q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h57v-86z" />-<glyph glyph-name="s" unicode="s" horiz-adv-x="924" d="M430 -20q-77 0 -139.5 13.5t-106.5 41t-68 68t-24 94.5q0 41 13.5 68.5t33 43.5t42 22.5t40.5 6.5q0 -54 11 -101t37 -82.5t68.5 -56t104.5 -20.5q55 0 97 13.5t70.5 38t43.5 59t15 75.5q0 38 -11.5 65.5t-40 51.5t-77.5 49t-123 57q-79 35 -137.5 67.5t-96.5 70.5 t-57 86.5t-19 115.5q0 70 27.5 124t78.5 90.5t122 55.5t158 19q73 0 129 -15t94 -40.5t57 -60t19 -72.5q0 -56 -38.5 -89.5t-109.5 -33.5q0 103 -42.5 160t-133.5 57q-52 0 -89 -12t-60.5 -34t-34.5 -52t-11 -66q0 -39 14 -67.5t44.5 -52.5t79 -46.5t116.5 -50.5 q81 -34 139 -67t95.5 -72t55.5 -88t18 -113q0 -80 -29 -140t-82 -100.5t-127.5 -60.5t-165.5 -20z" />-<glyph glyph-name="t" unicode="t" horiz-adv-x="721" d="M543 88q37 0 68 4t63 10v-90q-13 -6 -34 -12t-45.5 -10.5t-51.5 -7t-51 -2.5q-78 0 -134 16.5t-92 53.5t-53.5 98t-17.5 149v684h-156v82q37 0 81.5 15t78.5 50q35 38 56.5 90.5t37.5 131.5h94v-252h268v-117h-268v-690q0 -105 42.5 -154t113.5 -49z" />-<glyph glyph-name="u" unicode="u" horiz-adv-x="1300" d="M1079 223q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6v-86h-325l-27 166h-10q-31 -58 -68.5 -94t-79.5 -56.5t-88 -28t-96 -7.5q-81 0 -144 23t-106 72t-65.5 125t-22.5 181v491q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h367v-707q0 -67 10.5 -119 t35 -88t66 -54.5t103.5 -18.5q68 0 116.5 24t80 67.5t46.5 104.5t15 135v422q0 48 -13.5 77.5t-36 45t-53 20.5t-65.5 5h-6v86h366v-875z" />-<glyph glyph-name="v" unicode="v" horiz-adv-x="1186" d="M8 1012v86h512v-86h-26q-62 0 -92.5 -24t-30.5 -75q0 -17 4 -34.5t12 -40.5l139 -387q13 -36 27 -79.5l26.5 -85.5t22.5 -79.5t14 -63.5h7q5 22 16.5 54.5l26 71l30 78.5l29.5 77l147 399q10 25 14.5 48t4.5 40q0 53 -33.5 77t-101.5 24h-15v86h439v-86h-25 q-30 0 -51 -6.5t-38 -24.5t-32.5 -49t-34.5 -80l-323 -852h-187l-329 903q-12 32 -25 53t-30 33.5t-39 17.5t-52 5h-6z" />-<glyph glyph-name="w" unicode="w" horiz-adv-x="1765" d="M975 1092l205 -607l25.5 -79.5l25.5 -84l22 -78.5t15 -63h6q9 51 29 125.5t51 173.5l102 330q8 26 13.5 55.5t5.5 46.5q0 53 -33.5 77t-102.5 24h-14v86h438v-86h-26q-30 0 -52 -6t-39.5 -23.5t-32.5 -48.5t-30 -82l-264 -852h-164l-244 721l-37 135l-290 -856h-162 l-268 903q-12 32 -25 53t-30 33.5t-39 17.5t-52 5h-6v86h506v-86h-27q-61 0 -92 -18t-31 -68q0 -17 5.5 -41t11.5 -47l96 -344l21 -81t20.5 -87.5l17.5 -81.5t13 -64h6q5 26 13.5 60.5t20 74l24.5 80.5t26 78l213 619h129z" />-<glyph glyph-name="x" unicode="x" horiz-adv-x="1184" d="M786 952q0 37 -31.5 48.5t-78.5 11.5h-6v86h448v-86h-18q-30 0 -54.5 -5t-48 -19t-48.5 -40t-56 -67l-211 -281l301 -405q45 -60 85.5 -84.5t78.5 -24.5h27v-86h-529v86h10q123 0 123 68q0 11 -3 22.5t-12 27t-24 37.5t-39 54l-137 184l-143 -200q-9 -12 -19 -28t-18 -33 t-13 -34.5t-5 -33.5q0 -35 29 -49.5t98 -14.5h6v-86h-488v86h19q37 0 65 6t53 21t50 40.5t55 63.5l258 334l-258 352q-45 53 -87.5 81t-88.5 28h-27v86h520v-86h-6q-35 0 -58 -4.5t-36 -13t-18 -19.5t-5 -23q0 -21 12.5 -41.5t35.5 -52.5l135 -184l106 153q23 35 37 66 t14 59z" />-<glyph glyph-name="y" unicode="y" horiz-adv-x="1157" d="M1157 1098v-86h-6q-30 0 -51.5 -6.5t-39 -24.5t-32.5 -49t-33 -80l-311 -860q-36 -99 -68 -174t-67 -128.5t-76.5 -88.5t-94.5 -56t-122 -29t-160 -8h-18v97q104 0 179 31t129.5 85t91 127.5t61.5 159.5l-379 895q-14 32 -27 52.5t-29.5 33.5t-38 18t-51.5 5h-6v86h492 v-86h-6q-62 0 -92.5 -24t-30.5 -75q0 -17 3.5 -34.5t12.5 -40.5l150 -365l29.5 -76.5t29 -82l24.5 -76.5t15 -62h6q11 45 30.5 109.5t45.5 138.5l137 399q9 25 13.5 48t4.5 40q0 53 -33.5 77t-101.5 24h-6v86h426z" />-<glyph glyph-name="z" unicode="z" horiz-adv-x="1047" d="M696 117q36 0 59.5 14t39 37t25 53.5t16.5 63.5l10 47h86l-10 -332h-836v82l594 899h-320q-40 0 -66 -10.5t-42.5 -31.5t-27 -52t-21.5 -72l-2 -8h-86l20 291h785v-84l-596 -897h372z" />-<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="877" d="M639 -262q-72 0 -127.5 21t-92.5 59t-56 92.5t-19 122.5v356q0 63 -18.5 104t-51.5 65.5t-77 35t-95 12.5v86q51 2 95 12t77 34.5t51.5 65.5t18.5 103v357q0 140 74.5 216t220.5 76h135v-88h-61q-91 0 -129.5 -54t-38.5 -161v-350q0 -100 -56.5 -166.5t-171.5 -85.5v-2 q118 -20 173 -86t55 -168v-354q0 -105 38.5 -160t129.5 -55h61v-88h-135z" />-<glyph glyph-name="bar" unicode="|" d="M633 -492h-123v2048h123v-2048z" />-<glyph glyph-name="braceright" unicode="}" horiz-adv-x="877" d="M102 -174h62q91 0 129.5 55t38.5 160v354q0 102 54.5 168t172.5 86v2q-114 19 -170.5 85.5t-56.5 166.5v350q0 107 -38.5 161t-129.5 54h-62v88h136q145 0 219.5 -76t74.5 -216v-357q0 -62 19 -103t51.5 -65.5t76.5 -34.5t95 -12v-86q-51 -2 -95 -12.5t-76.5 -35 t-51.5 -65.5t-19 -104v-356q0 -68 -19 -122.5t-56 -92.5t-92 -59t-127 -21h-136v88z" />-<glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="1149" d="M776 551q-30 0 -62 12.5t-63.5 31.5t-60 41.5t-51.5 43.5l-45 40.5t-43.5 34.5t-43.5 24t-45 9q-60 0 -89 -58t-40 -179h-120q6 64 18.5 128t40.5 115t75.5 83t123.5 32q34 0 68 -13t66 -33t60.5 -44l52.5 -45l43 -38.5t41.5 -32.5t41.5 -22.5t42 -8.5q57 0 84 61.5 t41 175.5h123q-7 -64 -21 -128t-42.5 -115t-75 -83t-119.5 -32z" />-<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="682" d="M459 -367h-238l72 1051h94zM469 971q0 -40 -10 -67t-27.5 -43t-41 -23t-50.5 -7q-26 0 -49.5 7t-41 23t-28 43t-10.5 67q0 39 10.5 65.5t28 43t41 23.5t49.5 7q27 0 50.5 -7t41 -23.5t27.5 -43t10 -65.5z" />-<glyph glyph-name="cent" unicode="¢" d="M584 180q-93 10 -170.5 45.5t-133.5 102t-87 168t-31 243.5q0 152 33 258t90 173.5t134 101t165 41.5v149h102v-149q59 -5 118 -19.5t106 -40t76.5 -62.5t29.5 -85q0 -71 -45.5 -100t-136.5 -29q0 42 -9 80.5t-27 69t-46 51.5t-66 28v-909q42 0 84.5 6t81.5 15.5t73 21 t58 22.5v-112q-53 -28 -129.5 -50t-167.5 -24v-176h-102v180zM360 741q0 -183 54.5 -292t169.5 -140v897q-49 -9 -90 -37.5t-71 -83t-46.5 -139t-16.5 -205.5z" />-<glyph glyph-name="sterling" unicode="£" d="M500 690q15 -51 28 -104t13 -115q0 -88 -49.5 -155.5t-131.5 -122.5l5 -9q42 20 78.5 28.5t70.5 8.5q41 0 90 -12t97.5 -27t93 -27t75.5 -12q36 0 66.5 10.5t57.5 27.5t49.5 38.5t41.5 44.5v-133q-18 -25 -43 -52t-58 -49t-74.5 -36t-92.5 -14t-100 14.5t-99 31.5 t-101.5 31.5t-106.5 14.5q-68 0 -127 -19.5t-125 -50.5l-27 -12v108l37 23q38 23 75.5 55.5t67.5 75t49 94.5t19 113q0 60 -15 117.5t-36 113.5h-228v96h189q-14 32 -28 71t-25 81.5t-18 87t-7 86.5q0 88 29 157t83 116.5t131.5 72.5t174.5 25q99 0 168 -17.5t112 -48.5 t62.5 -73t19.5 -91q0 -66 -43.5 -99.5t-118.5 -33.5q0 48 -8.5 94.5t-31 83t-63 59.5t-105.5 23q-119 0 -174.5 -68t-55.5 -196q0 -48 8 -94t20 -88.5t26 -80l26 -67.5h348v-96h-319z" />-<glyph glyph-name="currency" unicode="¤" d="M197 733q0 62 17.5 117.5t51.5 101.5l-135 135l86 87l133 -136q47 34 102.5 53t118.5 19q60 0 115.5 -19t101.5 -53l138 138l86 -89l-135 -135q34 -46 52.5 -101.5t18.5 -117.5t-18.5 -117.5t-52.5 -101.5l135 -135l-84 -86l-137 135q-47 -32 -102.5 -51t-117.5 -19 t-117 18t-102 52l-135 -135l-86 86l133 135q-32 46 -49.5 101.5t-17.5 117.5zM311 733q0 -54 20.5 -101.5t56 -83t82.5 -56.5t101 -21q56 0 104 21t83 56.5t55.5 83t20.5 101.5q0 56 -20.5 104t-55.5 83.5t-83 56t-104 20.5q-54 0 -101 -20.5t-82.5 -56t-56 -83.5 t-20.5 -104z" />-<glyph glyph-name="yen" unicode="¥" d="M264 0v86h47q34 0 64 4.5t52.5 18.5t36 41.5t15.5 72.5v139h-286v97h286v143h-286v96h247l-278 570q-15 30 -28 50.5t-29.5 33.5t-37.5 18.5t-51 5.5h-6v86h498v-86h-14q-62 0 -89.5 -19t-27.5 -61q0 -24 8 -54.5t25 -65.5l98 -218q15 -32 29 -69l26.5 -73l22.5 -67 l16 -51q4 11 13 32.5l20.5 47l24 52l22.5 47.5l117 249q24 54 36.5 99.5t12.5 68.5q0 42 -28.5 62t-96.5 20h-6v86h418v-86h-19q-26 0 -45 -7t-35.5 -25t-34 -49t-40.5 -78l-250 -519h254v-96h-287v-143h287v-97h-287v-129q0 -48 13.5 -77t36 -44.5t53 -20.5t65.5 -5h47v-86 h-629z" />-<glyph glyph-name="brokenbar" unicode="¦" d="M633 737h-123v819h123v-819zM633 -492h-123v820h123v-820z" />-<glyph glyph-name="section" unicode="§" horiz-adv-x="1114" d="M598 795q-74 35 -138.5 69t-117.5 76q-22 -20 -36.5 -48t-14.5 -69t14 -73.5t48 -64t91.5 -64.5t145.5 -76l122 -62.5t109 -74.5q17 24 28 53t11 63q0 35 -10 66t-38.5 63t-80 66.5t-133.5 75.5zM571 -133q126 0 188 55.5t62 149.5q0 45 -11 78.5t-48.5 67t-109 74 t-191.5 99.5q-81 40 -138.5 81.5t-93.5 87.5t-52.5 98.5t-16.5 113.5q0 77 34 134.5t87 94.5q-38 45 -57 100.5t-19 129.5q0 78 28.5 138.5t78.5 102t119.5 63t150.5 21.5q84 0 146.5 -17.5t104 -48t62 -72.5t20.5 -91q0 -66 -39.5 -95.5t-105.5 -29.5q0 48 -10 93 t-33.5 80.5t-61 57t-92.5 21.5q-102 0 -158.5 -51t-56.5 -148q0 -54 20.5 -90.5t61 -66t99.5 -57.5l137 -66q87 -42 150 -84t104 -87.5t60.5 -96.5t19.5 -111q0 -37 -10.5 -73.5t-27.5 -70t-39 -63t-46 -53.5q29 -40 46 -90t17 -113q0 -81 -22.5 -148t-70 -115.5t-122 -75.5 t-178.5 -27q-79 0 -143.5 15.5t-110.5 45.5t-71 74t-25 102q0 42 13.5 69.5t33 44t42 23t40.5 6.5q0 -54 13.5 -104.5t42 -89.5t73 -62.5t106.5 -23.5z" />-<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="1182" d="M291 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM680 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20 t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="copyright" unicode="©" horiz-adv-x="1731" d="M901 365q47 0 87 12t72 32t55.5 45t37.5 50q12 -9 20.5 -25.5t8.5 -38.5q0 -28 -19.5 -57t-58 -53t-96 -39t-134.5 -15q-102 0 -178.5 33t-128 93t-77 144t-25.5 187q0 100 28 183t83.5 143t137 93.5t189.5 33.5q71 0 123.5 -11.5t87.5 -31t52.5 -46t17.5 -57.5 q0 -22 -11 -40t-30 -30.5t-44.5 -19t-54.5 -6.5q0 29 -7.5 56.5t-24.5 50t-44.5 36t-68.5 13.5q-72 0 -122.5 -24t-82.5 -71t-46.5 -115t-14.5 -157q0 -177 69 -272.5t199 -95.5zM113 731q0 104 27 200.5t75.5 180t117 152.5t152 118t179.5 76t200 27t200.5 -27t180 -76 t152.5 -118t118 -152.5t76 -180t27 -200.5t-27 -200t-76 -179.5t-118 -152t-152.5 -117.5t-180 -75.5t-200.5 -26.5t-200 26.5t-179.5 75.5t-152 117.5t-117 152t-75.5 179.5t-27 200zM225 731q0 -88 23 -169.5t64.5 -152.5t100 -129.5t129.5 -100t152.5 -64.5t169.5 -23 q89 0 171 23t153 64.5t129.5 100t100 129.5t64.5 152.5t23 169.5t-23 170t-64.5 153.5t-100 130t-129.5 100t-153 64.5t-171 23q-88 0 -169.5 -23t-152.5 -64.5t-129.5 -100t-100 -130t-64.5 -153t-23 -170.5z" />-<glyph glyph-name="ordfeminine" unicode="ª" horiz-adv-x="782" d="M250 985q0 -64 27 -88.5t67 -24.5q34 0 61 12t45.5 34t28.5 52t10 66v97l-63 -3q-50 -1 -83.5 -11.5t-54 -29t-29.5 -44.5t-9 -60zM387 1397q-31 0 -50 -11t-29.5 -30t-14.5 -44.5t-4 -54.5q-78 0 -120 20.5t-42 68.5q0 35 21 59t57 39t84 22t102 7q68 0 118 -12 t83.5 -38.5t50 -68.5t16.5 -103v-311q0 -46 19.5 -63t69.5 -17v-69h-199l-37 94h-10q-18 -20 -39.5 -39.5t-48 -34.5t-58.5 -24t-71 -9q-99 0 -156 53t-57 156q0 102 81 150.5t248 56.5l88 4v59q0 31 -3.5 56.5t-14 44t-30.5 29t-54 10.5z" />-<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="1053" d="M133 586l313 356h103l-207 -389l207 -389h-103l-313 356v66zM504 586l313 356h103l-207 -389l207 -389h-103l-313 356v66z" />-<glyph glyph-name="logicalnot" unicode="¬" d="M1012 793v-541h-123v420h-756v121h879z" />-<glyph glyph-name="uni00AD" unicode="­" horiz-adv-x="635" d="M51 481v154h533v-154h-533z" />-<glyph glyph-name="registered" unicode="®" horiz-adv-x="1731" d="M477 358h27q20 0 38 2.5t31.5 10t21.5 21.5t9 38v600q-1 24 -9 38.5t-21.5 22t-31.5 9.5t-38 2h-27v72h369q352 0 352 -244q0 -49 -16 -86t-42 -64t-59.5 -45.5t-68.5 -29.5l182 -293q10 -17 19.5 -27.5t22.5 -16.5t30.5 -8t42.5 -2v-69h-217l-226 381h-108v-240 q2 -24 10 -38t21.5 -21.5t31 -10t37.5 -2.5h29v-69h-410v69zM758 748h86q55 0 92 11t59 33t31.5 56t9.5 80q0 45 -11 77t-34.5 51.5t-61 28.5t-91.5 9h-80v-346zM113 731q0 104 27 200.5t75.5 180t117 152.5t152 118t179.5 76t200 27t200.5 -27t180 -76t152.5 -118 t118 -152.5t76 -180t27 -200.5t-27 -200t-76 -179.5t-118 -152t-152.5 -117.5t-180 -75.5t-200.5 -26.5t-200 26.5t-179.5 75.5t-152 117.5t-117 152t-75.5 179.5t-27 200zM225 731q0 -88 23 -169.5t64.5 -152.5t100 -129.5t129.5 -100t152.5 -64.5t169.5 -23q89 0 171 23 t153 64.5t129.5 100t100 129.5t64.5 152.5t23 169.5t-23 170t-64.5 153.5t-100 130t-129.5 100t-153 64.5t-171 23q-88 0 -169.5 -23t-152.5 -64.5t-129.5 -100t-100 -130t-64.5 -153t-23 -170.5z" />-<glyph glyph-name="macron" unicode="¯" horiz-adv-x="940" d="M950 1556h-960v121h960v-121z" />-<glyph glyph-name="degree" unicode="°" horiz-adv-x="819" d="M98 1151q0 65 24.5 121.5t66.5 98.5t98.5 66.5t120.5 24.5q65 0 121.5 -24.5t98.5 -66.5t66.5 -98.5t24.5 -121.5q0 -64 -24.5 -120.5t-66.5 -98.5t-98.5 -66t-121.5 -24q-64 0 -120.5 24t-98.5 66t-66.5 98.5t-24.5 120.5zM221 1151q0 -38 14.5 -72.5t40 -60t59.5 -40.5 t73 -15q40 0 74 15t59.5 40.5t40 60t14.5 72.5q0 40 -14.5 74.5t-40 60t-59.5 40.5t-74 15q-39 0 -73 -15t-59.5 -40.5t-40 -60t-14.5 -74.5z" />-<glyph glyph-name="plusminus" unicode="±" d="M633 672v-379h-123v379h-377v121h377v378h123v-378h379v-121h-379zM1012 0h-879v121h879v-121z" />-<glyph glyph-name="uni00B2" unicode="²" horiz-adv-x="819" d="M690 1262q0 -48 -11 -90t-37 -84t-68.5 -87t-106.5 -100l-217 -186h297q47 0 65.5 25t24.5 59l8 43h70l-6 -256h-623v92l260 233q45 41 76 83t49.5 84.5t26.5 84.5t8 82q0 34 -6.5 62.5t-21 49.5t-37.5 32.5t-56 11.5q-37 0 -63 -14.5t-42 -39t-23 -57t-7 -67.5 q-69 0 -108.5 17t-39.5 71q0 37 18 68.5t53.5 54.5t88.5 36t123 13q143 0 224 -56.5t81 -164.5z" />-<glyph glyph-name="uni00B3" unicode="³" horiz-adv-x="819" d="M356 573q-134 0 -204 46.5t-70 121.5q0 45 25.5 73t68.5 28q0 -32 10.5 -63.5t32 -56.5t54 -40.5t77.5 -15.5q85 0 133.5 41.5t48.5 136.5q0 72 -52 114.5t-165 42.5h-67v84h67q39 0 72 12.5t58 35.5t39 55.5t14 73.5q0 68 -27 103.5t-90 35.5q-39 0 -65 -14.5t-41.5 -39 t-22 -57t-6.5 -67.5q-35 0 -63.5 3.5t-48 13.5t-30 27t-10.5 44q0 37 18.5 68.5t55 54.5t90 36t123.5 13q68 0 124 -14t96 -40t61.5 -63.5t21.5 -85.5q0 -45 -17 -80.5t-45.5 -62.5t-66.5 -46.5t-80 -31.5v-10q41 -7 84 -19.5t78.5 -35.5t58.5 -59.5t23 -92.5 q0 -75 -33.5 -126.5t-86.5 -83t-117 -45.5t-126 -14z" />-<glyph glyph-name="acute" unicode="´" horiz-adv-x="1182" d="M391 1268q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="uni00B5" unicode="µ" horiz-adv-x="1260" d="M569 -20q-86 0 -147.5 31.5t-102.5 88.5q2 -85 7 -157t21.5 -126t48.5 -87.5t89 -42.5q0 -39 -8.5 -71.5t-26 -56.5t-44.5 -37.5t-64 -13.5q-32 0 -62 12t-53 40.5t-37 75.5t-14 116q0 61 3.5 131.5l7.5 156l8.5 189.5t5.5 232v637h192v-688q0 -67 10 -122t33.5 -94.5 t63 -61t98.5 -21.5q57 0 103 24t78 67.5t49.5 104.5t17.5 135v656h192v-834q0 -45 12 -78.5t30.5 -55.5t41.5 -33t45 -11h7v-86h-111q-84 0 -132 41.5t-67 122.5h-8q-24 -41 -51.5 -75t-62 -58t-77 -37.5t-96.5 -13.5z" />-<glyph glyph-name="paragraph" unicode="¶" horiz-adv-x="1264" d="M860 1452h-194v-1679h-320v86h27q35 0 65.5 5t53 20.5t36 44.5t13.5 77v785h-146q-90 0 -150 32.5t-96 88t-51.5 128t-15.5 152.5q0 82 17 149t55 115t98 74t147 26h781v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-1317q0 -48 13.5 -77t36 -44.5t53.5 -20.5 t65 -5h27v-86h-320v1679z" />-<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="586" d="M166 729q0 40 10 67t27.5 43t41 22.5t50.5 6.5q26 0 49.5 -6.5t41 -22.5t28 -43t10.5 -67q0 -39 -10.5 -65.5t-28 -43t-41 -23.5t-49.5 -7q-27 0 -50.5 7t-41 23.5t-27.5 43t-10 65.5z" />-<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="682" d="M551 -258q0 -109 -69.5 -171.5t-200.5 -62.5q-16 0 -36 1.5t-41 4.5t-42 7.5t-39 9.5v104q37 -8 74 -12t65 -4q59 0 92 31t33 84q0 60 -43.5 90t-110.5 35l43 159h97l-21 -88q100 -8 149.5 -57.5t49.5 -130.5z" />-<glyph glyph-name="uni00B9" unicode="¹" horiz-adv-x="819" d="M145 588v69h95q18 0 33 2.5t26.5 10.5t18 23.5t6.5 41.5v590h-191v70h103q23 0 49 3t50 12t43 24t28 39h102v-738q0 -26 7 -41.5t18.5 -23.5t27 -10.5t33.5 -2.5h94v-69h-543z" />-<glyph glyph-name="ordmasculine" unicode="º" horiz-adv-x="813" d="M250 1126q0 -133 35 -199.5t123 -66.5q86 0 121.5 66.5t35.5 199.5q0 131 -36.5 195.5t-122.5 64.5t-121 -64.5t-35 -195.5zM741 1126q0 -176 -85 -262t-250 -86q-158 0 -246 86.5t-88 261.5q0 176 85 261.5t253 85.5q77 0 138 -21.5t104 -64.5t66 -108t23 -153z" />-<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="1053" d="M920 520l-314 -356h-102l207 389l-207 389h102l314 -356v-66zM549 520l-313 -356h-103l207 389l-207 389h103l313 -356v-66z" />-<glyph glyph-name="onequarter" unicode="¼" horiz-adv-x="1720" d="M1294 580q0 32 3 73t8 79q-8 -17 -17 -34t-14 -25l-223 -324h243v231zM1477 261v-113q0 -26 7 -41.5t19 -23.5t27.5 -10.5t32.5 -2.5h41v-69h-451v69h57q17 0 32 2.5t26.5 10.5t18.5 23.5t7 41.5v113h-364v61l383 564h164v-537h196v-88h-196zM566 0h-136l731 1462h134z M60 588v69h95q18 0 33 2.5t26.5 10.5t18 23.5t6.5 41.5v590h-191v70h103q23 0 49 3t50 12t43 24t28 39h102v-738q0 -26 7 -41.5t18.5 -23.5t27 -10.5t33.5 -2.5h94v-69h-543z" />-<glyph glyph-name="onehalf" unicode="½" horiz-adv-x="1720" d="M525 0h-136l731 1462h134zM60 588v69h95q18 0 33 2.5t26.5 10.5t18 23.5t6.5 41.5v590h-191v70h103q23 0 49 3t50 12t43 24t28 39h102v-738q0 -26 7 -41.5t18.5 -23.5t27 -10.5t33.5 -2.5h94v-69h-543zM1620 677q0 -48 -11 -90t-37 -84t-68.5 -87t-106.5 -100l-217 -186 h297q47 0 65.5 25t24.5 59l8 43h70l-6 -256h-623v92l260 233q45 41 76 83t49.5 84.5t26.5 84.5t8 82q0 34 -6.5 62.5t-21 49.5t-37.5 32.5t-56 11.5q-37 0 -63 -14.5t-42 -39t-23 -57t-7 -67.5q-69 0 -108.5 17t-39.5 71q0 37 18 68.5t53.5 54.5t88.5 36t123 13 q143 0 224 -56.5t81 -164.5z" />-<glyph glyph-name="threequarters" unicode="¾" horiz-adv-x="1720" d="M1294 580q0 32 3 73t8 79q-8 -17 -17 -34t-14 -25l-223 -324h243v231zM1477 261v-113q0 -26 7 -41.5t19 -23.5t27.5 -10.5t32.5 -2.5h41v-69h-451v69h57q17 0 32 2.5t26.5 10.5t18.5 23.5t7 41.5v113h-364v61l383 564h164v-537h196v-88h-196zM607 0h-136l731 1462h134z M356 573q-134 0 -204 46.5t-70 121.5q0 45 25.5 73t68.5 28q0 -32 10.5 -63.5t32 -56.5t54 -40.5t77.5 -15.5q85 0 133.5 41.5t48.5 136.5q0 72 -52 114.5t-165 42.5h-67v84h67q39 0 72 12.5t58 35.5t39 55.5t14 73.5q0 68 -27 103.5t-90 35.5q-39 0 -65 -14.5t-41.5 -39 t-22 -57t-6.5 -67.5q-35 0 -63.5 3.5t-48 13.5t-30 27t-10.5 44q0 37 18.5 68.5t55 54.5t90 36t123.5 13q68 0 124 -14t96 -40t61.5 -63.5t21.5 -85.5q0 -45 -17 -80.5t-45.5 -62.5t-66.5 -46.5t-80 -31.5v-10q41 -7 84 -19.5t78.5 -35.5t58.5 -59.5t23 -92.5 q0 -75 -33.5 -126.5t-86.5 -83t-117 -45.5t-126 -14z" />-<glyph glyph-name="questiondown" unicode="¿" horiz-adv-x="1024" d="M502 682h125v-311q-89 -36 -149.5 -84t-97 -103t-52 -115t-15.5 -122q0 -53 13 -96.5t40 -74.5t69.5 -48t101.5 -17q64 0 107.5 21t70.5 57t39 83.5t12 100.5q37 0 68 -8.5t53.5 -25t35.5 -41.5t13 -58q0 -49 -22.5 -91t-70 -72.5t-119.5 -48t-171 -17.5q-97 0 -179 25 t-142 72.5t-94 116.5t-34 157q0 84 26.5 153.5t77.5 126.5t125 103.5t169 85.5v231zM696 969q0 -40 -10 -67t-27.5 -43t-41 -23t-50.5 -7q-26 0 -49.5 7t-41 23t-28 43t-10.5 67q0 39 10.5 65.5t28 43t41 23.5t49.5 7q27 0 50.5 -7t41 -23.5t27.5 -43t10 -65.5z" />-<glyph glyph-name="Agrave" unicode="À" horiz-adv-x="1444" d="M414 489l-78 -215q-9 -24 -14 -47.5t-5 -40.5q0 -52 33.5 -76t102.5 -24h47v-86h-500v86h39q30 0 51 6.5t38 24.5t32.5 49t34.5 80l454 1216h160l463 -1267q12 -32 24.5 -53t29.5 -33.5t39 -17.5t52 -5h27v-86h-563v86h47q123 0 123 98q0 17 -4.5 35t-12.5 41l-82 229 h-538zM788 950l-58.5 170.5t-43.5 153.5q-7 -37 -16.5 -71.5t-20.5 -70.5t-25 -75.5l-32 -87.5l-139 -377h462zM805 1579h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="Aacute" unicode="Á" horiz-adv-x="1444" d="M414 489l-78 -215q-9 -24 -14 -47.5t-5 -40.5q0 -52 33.5 -76t102.5 -24h47v-86h-500v86h39q30 0 51 6.5t38 24.5t32.5 49t34.5 80l454 1216h160l463 -1267q12 -32 24.5 -53t29.5 -33.5t39 -17.5t52 -5h27v-86h-563v86h47q123 0 123 98q0 17 -4.5 35t-12.5 41l-82 229 h-538zM788 950l-58.5 170.5t-43.5 153.5q-7 -37 -16.5 -71.5t-20.5 -70.5t-25 -75.5l-32 -87.5l-139 -377h462zM637 1606q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="Acircumflex" unicode="Â" horiz-adv-x="1444" d="M414 489l-78 -215q-9 -24 -14 -47.5t-5 -40.5q0 -52 33.5 -76t102.5 -24h47v-86h-500v86h39q30 0 51 6.5t38 24.5t32.5 49t34.5 80l454 1216h160l463 -1267q12 -32 24.5 -53t29.5 -33.5t39 -17.5t52 -5h27v-86h-563v86h47q123 0 123 98q0 17 -4.5 35t-12.5 41l-82 229 h-538zM788 950l-58.5 170.5t-43.5 153.5q-7 -37 -16.5 -71.5t-20.5 -70.5t-25 -75.5l-32 -87.5l-139 -377h462zM422 1606l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5 t-116 -84.5h-80v27z" />-<glyph glyph-name="Atilde" unicode="Ã" horiz-adv-x="1444" d="M414 489l-78 -215q-9 -24 -14 -47.5t-5 -40.5q0 -52 33.5 -76t102.5 -24h47v-86h-500v86h39q30 0 51 6.5t38 24.5t32.5 49t34.5 80l454 1216h160l463 -1267q12 -32 24.5 -53t29.5 -33.5t39 -17.5t52 -5h27v-86h-563v86h47q123 0 123 98q0 17 -4.5 35t-12.5 41l-82 229 h-538zM788 950l-58.5 170.5t-43.5 153.5q-7 -37 -16.5 -71.5t-20.5 -70.5t-25 -75.5l-32 -87.5l-139 -377h462zM895 1712q30 0 48.5 9t29 24.5t15 35t7.5 40.5h92q-3 -47 -16.5 -90.5t-39.5 -77.5t-65 -54t-94 -20t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-31 0 -49 -9 t-28.5 -24t-15.5 -34.5t-8 -40.5h-92q3 47 16.5 90t40 77t66 54t94.5 20t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="Adieresis" unicode="Ä" horiz-adv-x="1444" d="M414 489l-78 -215q-9 -24 -14 -47.5t-5 -40.5q0 -52 33.5 -76t102.5 -24h47v-86h-500v86h39q30 0 51 6.5t38 24.5t32.5 49t34.5 80l454 1216h160l463 -1267q12 -32 24.5 -53t29.5 -33.5t39 -17.5t52 -5h27v-86h-563v86h47q123 0 123 98q0 17 -4.5 35t-12.5 41l-82 229 h-538zM788 950l-58.5 170.5t-43.5 153.5q-7 -37 -16.5 -71.5t-20.5 -70.5t-25 -75.5l-32 -87.5l-139 -377h462zM424 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM813 1747 q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="Aring" unicode="Å" horiz-adv-x="1444" d="M860 1585q0 33 -10.5 56.5t-29 38t-43 21.5t-52.5 7t-52.5 -7t-43 -21.5t-29 -38t-10.5 -56.5t10.5 -56.5t29 -38t43 -21.5t52.5 -7t52.5 7t43 21.5t29 38t10.5 56.5zM971 1585q0 -55 -19 -96.5t-52.5 -69.5t-78.5 -42.5t-96 -14.5t-96 14.5t-78.5 42.5t-52.5 69.5 t-19 96.5q0 54 19 96t52.5 70t78.5 42.5t96 14.5t96 -14.5t78.5 -42.5t52.5 -70t19 -96zM414 489l-78 -215q-9 -24 -14 -47.5t-5 -40.5q0 -52 33.5 -76t102.5 -24h47v-86h-500v86h39q30 0 51 6.5t38 24.5t32.5 49t34.5 80l454 1216h160l463 -1267q12 -32 24.5 -53 t29.5 -33.5t39 -17.5t52 -5h27v-86h-563v86h47q123 0 123 98q0 17 -4.5 35t-12.5 41l-82 229h-538zM788 950l-58.5 170.5t-43.5 153.5q-7 -37 -16.5 -71.5t-20.5 -70.5t-25 -75.5l-32 -87.5l-139 -377h462z" />-<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="1948" d="M1151 102h395q48 0 82.5 13.5t57.5 36.5t36 53.5t19 64.5l14 88h107l-15 -358h-1097v86h26q34 0 64 4.5t52.5 18.5t36.5 41.5t15 72.5v266h-471l-113 -215q-17 -32 -24.5 -61t-7.5 -47q0 -42 31.5 -61t91.5 -19h47v-86h-498v86h33q54 0 96.5 38t85.5 122l592 1120 l-160 10v86h1135l10 -358h-106l-11 88q-4 34 -15 64t-32.5 52.5t-54 36.5t-78.5 15h-344v-545h494v-100h-494v-613zM849 1221l-92.5 -183.5l-110.5 -214.5l-120 -231h418v768h-29q-25 -56 -66 -139z" />-<glyph glyph-name="Ccedilla" unicode="Ç" horiz-adv-x="1257" d="M774 1483q105 0 182.5 -17.5t129 -48.5t77 -73t25.5 -91q0 -33 -13.5 -59.5t-37.5 -45t-56.5 -28.5t-70.5 -10q0 48 -12.5 95t-41 84.5t-74 61t-112.5 23.5q-116 0 -197 -42.5t-132 -124t-74 -201t-23 -273.5q0 -137 24 -251t76 -195.5t132.5 -126.5t193.5 -45 q75 0 132.5 14.5t101.5 38.5t77.5 55.5t59.5 65.5q17 -11 28 -30t11 -50q0 -39 -26.5 -79.5t-80.5 -73.5t-137 -54.5t-197 -21.5q-153 0 -269 54t-194.5 153t-118.5 238t-40 308q0 166 42 304t124.5 237t205.5 154t285 55zM942 -258q0 -109 -69.5 -171.5t-200.5 -62.5 q-16 0 -36 1.5t-41 4.5t-42 7.5t-39 9.5v104q37 -8 74 -12t65 -4q59 0 92 31t33 84q0 60 -43.5 90t-110.5 35l43 159h97l-21 -88q100 -8 149.5 -57.5t49.5 -130.5z" />-<glyph glyph-name="Egrave" unicode="È" horiz-adv-x="1276" d="M479 102h395q49 0 83.5 13.5t57.5 36.5t36 53.5t18 64.5l14 88h107l-14 -358h-1098v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1006q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h1032l10 -358h-106l-10 88q-4 34 -15.5 64.5t-33 53.5t-54 36.5t-78.5 13.5 h-344v-545h494v-100h-494v-613zM743 1579h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="Eacute" unicode="É" horiz-adv-x="1276" d="M479 102h395q49 0 83.5 13.5t57.5 36.5t36 53.5t18 64.5l14 88h107l-14 -358h-1098v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1006q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h1032l10 -358h-106l-10 88q-4 34 -15.5 64.5t-33 53.5t-54 36.5t-78.5 13.5 h-344v-545h494v-100h-494v-613zM545 1606q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="Ecircumflex" unicode="Ê" horiz-adv-x="1276" d="M479 102h395q49 0 83.5 13.5t57.5 36.5t36 53.5t18 64.5l14 88h107l-14 -358h-1098v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1006q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h1032l10 -358h-106l-10 88q-4 34 -15.5 64.5t-33 53.5t-54 36.5t-78.5 13.5 h-344v-545h494v-100h-494v-613zM350 1606l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="Edieresis" unicode="Ë" horiz-adv-x="1276" d="M479 102h395q49 0 83.5 13.5t57.5 36.5t36 53.5t18 64.5l14 88h107l-14 -358h-1098v86h26q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v1006q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h1032l10 -358h-106l-10 88q-4 34 -15.5 64.5t-33 53.5t-54 36.5t-78.5 13.5 h-344v-545h494v-100h-494v-613zM342 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM731 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54 q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="Igrave" unicode="Ì" horiz-adv-x="752" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v996q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-996q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-596zM473 1579h-78q-41 28 -89 69.5 t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="Iacute" unicode="Í" horiz-adv-x="752" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v996q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-996q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-596zM271 1606q23 29 47.5 67t48 78.5l45 81 t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="Icircumflex" unicode="Î" horiz-adv-x="752" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v996q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-996q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-596zM73 1606l53 67l57.5 78.5t53.5 81 t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="Idieresis" unicode="Ï" horiz-adv-x="752" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v996q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-996q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-596zM73 1747q0 32 8 54t22 35.5t33 19.5 t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM462 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="1489" d="M78 815h194v422q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h627q158 0 282 -48.5t209.5 -141.5t130.5 -229t45 -310q0 -168 -42 -303.5t-125 -231t-208.5 -147t-291.5 -51.5h-627v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v482h-194v100zM657 104 q122 0 213.5 41.5t152.5 121.5t91.5 197t30.5 269t-30.5 269t-91 196.5t-152 120.5t-212.5 41h-180v-545h348v-100h-348v-611h178z" />-<glyph glyph-name="Ntilde" unicode="Ñ" horiz-adv-x="1563" d="M1165 0l-768 1180v-947q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-514v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v1004q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h375l733 -1132v907q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-27v86 h514v-86h-26q-35 0 -65.5 -5t-53.5 -20.5t-36 -44.5t-13 -77v-1229h-146zM979 1712q30 0 48.5 9t29 24.5t15 35t7.5 40.5h92q-3 -47 -16.5 -90.5t-39.5 -77.5t-65 -54t-94 -20t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-31 0 -49 -9t-28.5 -24t-15.5 -34.5t-8 -40.5h-92 q3 47 16.5 90t40 77t66 54t94.5 20t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="Ograve" unicode="Ò" horiz-adv-x="1520" d="M1403 733q0 -169 -42 -308t-124 -238t-202 -153t-275 -54q-163 0 -284 54t-201 153t-120 238.5t-40 309.5t40 308.5t120 236.5t202 151.5t285 53.5q155 0 274 -53.5t201 -152t124 -237t42 -309.5zM342 733q0 -152 22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5 t193.5 43.5t129 126t71.5 202t22 271.5t-22 271.5t-71.5 201.5t-128 125t-192.5 43t-194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5zM861 1579h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="Oacute" unicode="Ó" horiz-adv-x="1520" d="M1403 733q0 -169 -42 -308t-124 -238t-202 -153t-275 -54q-163 0 -284 54t-201 153t-120 238.5t-40 309.5t40 308.5t120 236.5t202 151.5t285 53.5q155 0 274 -53.5t201 -152t124 -237t42 -309.5zM342 733q0 -152 22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5 t193.5 43.5t129 126t71.5 202t22 271.5t-22 271.5t-71.5 201.5t-128 125t-192.5 43t-194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5zM649 1606q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="Ocircumflex" unicode="Ô" horiz-adv-x="1520" d="M1403 733q0 -169 -42 -308t-124 -238t-202 -153t-275 -54q-163 0 -284 54t-201 153t-120 238.5t-40 309.5t40 308.5t120 236.5t202 151.5t285 53.5q155 0 274 -53.5t201 -152t124 -237t42 -309.5zM342 733q0 -152 22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5 t193.5 43.5t129 126t71.5 202t22 271.5t-22 271.5t-71.5 201.5t-128 125t-192.5 43t-194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5zM459 1606l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5 q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="Otilde" unicode="Õ" horiz-adv-x="1520" d="M1403 733q0 -169 -42 -308t-124 -238t-202 -153t-275 -54q-163 0 -284 54t-201 153t-120 238.5t-40 309.5t40 308.5t120 236.5t202 151.5t285 53.5q155 0 274 -53.5t201 -152t124 -237t42 -309.5zM342 733q0 -152 22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5 t193.5 43.5t129 126t71.5 202t22 271.5t-22 271.5t-71.5 201.5t-128 125t-192.5 43t-194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5zM918 1712q30 0 48.5 9t29 24.5t15 35t7.5 40.5h92q-3 -47 -16.5 -90.5t-39.5 -77.5t-65 -54t-94 -20t-99.5 20t-83 44.5l-72 44.5t-66.5 20 q-31 0 -49 -9t-28.5 -24t-15.5 -34.5t-8 -40.5h-92q3 47 16.5 90t40 77t66 54t94.5 20t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="Odieresis" unicode="Ö" horiz-adv-x="1520" d="M1403 733q0 -169 -42 -308t-124 -238t-202 -153t-275 -54q-163 0 -284 54t-201 153t-120 238.5t-40 309.5t40 308.5t120 236.5t202 151.5t285 53.5q155 0 274 -53.5t201 -152t124 -237t42 -309.5zM342 733q0 -152 22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5 t193.5 43.5t129 126t71.5 202t22 271.5t-22 271.5t-71.5 201.5t-128 125t-192.5 43t-194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5zM455 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26 t-29.5 89zM844 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="multiply" unicode="×" d="M571 647l-340 -340l-86 88l340 340l-340 338l86 86l340 -340l340 342l86 -88l-340 -340l340 -340l-86 -86z" />-<glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="1520" d="M1163 1354q118 -97 179 -255t61 -366q0 -169 -42 -308t-124 -238t-202 -153t-275 -54q-93 0 -172.5 17.5t-145.5 51.5l-71 -131h-121l104 188q-121 98 -180 258.5t-59 370.5q0 170 40 308.5t120 236.5t202 151.5t285 53.5q91 0 169 -19.5t144 -54.5l76 135h119zM342 733 q0 -155 22.5 -273t73.5 -202l572 1034q-94 82 -248 82q-114 0 -194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5zM1176 733q0 153 -22.5 271.5t-72.5 201.5l-571 -1036q95 -80 250 -80q114 0 193.5 43.5t129 126t71.5 202t22 271.5z" />-<glyph glyph-name="Ugrave" unicode="Ù" horiz-adv-x="1468" d="M741 -20q-121 0 -217 25.5t-162.5 81t-101.5 143t-35 212.5v795q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-799q0 -89 25.5 -151.5t71 -101.5t108 -57t137.5 -18q89 0 153.5 24t107 66.5 t63 101t20.5 128.5v815q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h514v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-811q0 -102 -32.5 -183.5t-96 -138t-157.5 -86.5t-216 -30zM852 1579h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219 q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="Uacute" unicode="Ú" horiz-adv-x="1468" d="M741 -20q-121 0 -217 25.5t-162.5 81t-101.5 143t-35 212.5v795q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-799q0 -89 25.5 -151.5t71 -101.5t108 -57t137.5 -18q89 0 153.5 24t107 66.5 t63 101t20.5 128.5v815q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h514v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-811q0 -102 -32.5 -183.5t-96 -138t-157.5 -86.5t-216 -30zM649 1606q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21 q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="Ucircumflex" unicode="Û" horiz-adv-x="1468" d="M741 -20q-121 0 -217 25.5t-162.5 81t-101.5 143t-35 212.5v795q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-799q0 -89 25.5 -151.5t71 -101.5t108 -57t137.5 -18q89 0 153.5 24t107 66.5 t63 101t20.5 128.5v815q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h514v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-811q0 -102 -32.5 -183.5t-96 -138t-157.5 -86.5t-216 -30zM471 1606l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5 t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="Udieresis" unicode="Ü" horiz-adv-x="1468" d="M741 -20q-121 0 -217 25.5t-162.5 81t-101.5 143t-35 212.5v795q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h596v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-799q0 -89 25.5 -151.5t71 -101.5t108 -57t137.5 -18q89 0 153.5 24t107 66.5 t63 101t20.5 128.5v815q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-26v86h514v-86h-27q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-811q0 -102 -32.5 -183.5t-96 -138t-157.5 -86.5t-216 -30zM477 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5 t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM866 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="Yacute" unicode="Ý" horiz-adv-x="1280" d="M326 0v86h47q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v387l-379 658q-17 29 -32 49.5t-31.5 33.5t-36.5 19t-46 6h-26v86h563v-86h-76q-28 0 -45.5 -5t-27.5 -14t-13.5 -21t-3.5 -25q0 -29 12.5 -58t24.5 -51l151 -274q36 -63 61 -124.5t42 -109.5q9 22 22.5 49 l30 57.5l34.5 63l36 64.5l131 235q20 35 28.5 66.5t8.5 56.5q0 45 -32 67.5t-91 22.5h-60v86h500v-86h-24q-22 0 -41.5 -7.5t-39.5 -26t-41.5 -49t-47.5 -76.5l-344 -607v-377q0 -48 13 -77t36 -44.5t53.5 -20.5t64.5 -5h48v-86h-637zM567 1606q23 29 47.5 67t48 78.5l45 81 t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="Thorn" unicode="Þ" horiz-adv-x="1237" d="M78 0v86h26q35 0 65.5 5t53.5 20.5t36 44.5t13 77v996q0 48 -13 77t-36 44.5t-53.5 20.5t-65.5 5h-26v86h616v-86h-47q-34 0 -65 -5t-53.5 -20.5t-36 -44.5t-13.5 -77v-62h174q258 0 381 -103.5t123 -303.5q0 -91 -28.5 -172t-93.5 -142t-170 -96t-257 -35h-129v-82 q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h47v-86h-616zM479 412h109q93 0 159 16.5t108 56t61.5 105t19.5 162.5q0 86 -17 146t-55 98t-98.5 55.5t-147.5 17.5h-139v-657z" />-<glyph glyph-name="germandbls" unicode="ß" horiz-adv-x="1325" d="M887 78q75 0 123.5 46t48.5 140q0 34 -7.5 63t-29.5 56t-61 54t-101 57q-64 32 -113 63t-81.5 69t-49 86t-16.5 113q0 62 20.5 113t62 87.5t105 56.5t150.5 20q0 97 -14 166.5t-45 114.5t-79.5 66t-117.5 21q-62 0 -108.5 -20t-77.5 -56.5t-46.5 -88.5t-15.5 -117v-1188 h-387v86h27q35 0 65.5 5t53 20.5t36 44.5t13.5 77v768h-166v97h166v61q0 113 34 190t93.5 124.5t140 68.5t174.5 21q128 0 213 -36.5t136.5 -107t73.5 -174.5t23 -239h-149q-109 0 -160 -41.5t-51 -124.5q0 -31 10 -56.5t35 -49t66 -47t102 -52.5q77 -35 126 -74.5t77 -82.5 t38.5 -88t10.5 -91q0 -78 -24 -138t-68.5 -100t-108.5 -60.5t-145 -20.5q-72 0 -131 13.5t-101 41t-65 68t-23 94.5q0 41 12 68.5t30 43.5t38.5 22.5t36.5 6.5q0 -54 10.5 -101t34 -82.5t62 -56t94.5 -20.5z" />-<glyph glyph-name="agrave" unicode="à" horiz-adv-x="1153" d="M301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v166l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM549 1016q-59 0 -95.5 -16.5t-57 -46.5t-27.5 -71t-7 -89q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5 t143 11q94 0 164 -18.5t117 -60.5t70.5 -109.5t23.5 -165.5v-531q0 -43 7 -71t22 -45t39.5 -24t58.5 -7h6v-86h-277l-32 176h-17q-32 -43 -62 -79t-66 -62t-81.5 -40.5t-109.5 -14.5q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123 q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5zM667 1241h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="aacute" unicode="á" horiz-adv-x="1153" d="M301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v166l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM549 1016q-59 0 -95.5 -16.5t-57 -46.5t-27.5 -71t-7 -89q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5 t143 11q94 0 164 -18.5t117 -60.5t70.5 -109.5t23.5 -165.5v-531q0 -43 7 -71t22 -45t39.5 -24t58.5 -7h6v-86h-277l-32 176h-17q-32 -43 -62 -79t-66 -62t-81.5 -40.5t-109.5 -14.5q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123 q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5zM471 1268q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="acircumflex" unicode="â" horiz-adv-x="1153" d="M301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v166l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM549 1016q-59 0 -95.5 -16.5t-57 -46.5t-27.5 -71t-7 -89q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5 t143 11q94 0 164 -18.5t117 -60.5t70.5 -109.5t23.5 -165.5v-531q0 -43 7 -71t22 -45t39.5 -24t58.5 -7h6v-86h-277l-32 176h-17q-32 -43 -62 -79t-66 -62t-81.5 -40.5t-109.5 -14.5q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123 q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5zM261 1268l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="atilde" unicode="ã" horiz-adv-x="1153" d="M301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v166l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM549 1016q-59 0 -95.5 -16.5t-57 -46.5t-27.5 -71t-7 -89q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5 t143 11q94 0 164 -18.5t117 -60.5t70.5 -109.5t23.5 -165.5v-531q0 -43 7 -71t22 -45t39.5 -24t58.5 -7h6v-86h-277l-32 176h-17q-32 -43 -62 -79t-66 -62t-81.5 -40.5t-109.5 -14.5q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123 q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5zM743 1374q30 0 48.5 9t29 24.5t15 35t7.5 40.5h92q-3 -47 -16.5 -90.5t-39.5 -77.5t-65 -54t-94 -20t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-31 0 -49 -9t-28.5 -24t-15.5 -34.5t-8 -40.5h-92q3 47 16.5 90t40 77t66 54t94.5 20 t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="adieresis" unicode="ä" horiz-adv-x="1153" d="M301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v166l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM549 1016q-59 0 -95.5 -16.5t-57 -46.5t-27.5 -71t-7 -89q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5 t143 11q94 0 164 -18.5t117 -60.5t70.5 -109.5t23.5 -165.5v-531q0 -43 7 -71t22 -45t39.5 -24t58.5 -7h6v-86h-277l-32 176h-17q-32 -43 -62 -79t-66 -62t-81.5 -40.5t-109.5 -14.5q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123 q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5zM257 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM646 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5 t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="aring" unicode="å" horiz-adv-x="1153" d="M708 1444q0 33 -10.5 56.5t-29 38t-43 21.5t-52.5 7t-52.5 -7t-43 -21.5t-29 -38t-10.5 -56.5t10.5 -56.5t29 -38t43 -21.5t52.5 -7t52.5 7t43 21.5t29 38t10.5 56.5zM819 1444q0 -55 -19 -96.5t-52.5 -69.5t-78.5 -42.5t-96 -14.5t-96 14.5t-78.5 42.5t-52.5 69.5 t-19 96.5q0 54 19 96t52.5 70t78.5 42.5t96 14.5t96 -14.5t78.5 -42.5t52.5 -70t19 -96zM301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v166l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM549 1016q-59 0 -95.5 -16.5 t-57 -46.5t-27.5 -71t-7 -89q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5t143 11q94 0 164 -18.5t117 -60.5t70.5 -109.5t23.5 -165.5v-531q0 -43 7 -71t22 -45t39.5 -24t58.5 -7h6v-86h-277l-32 176h-17q-32 -43 -62 -79t-66 -62t-81.5 -40.5t-109.5 -14.5 q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5z" />-<glyph glyph-name="ae" unicode="æ" horiz-adv-x="1722" d="M301 297q0 -96 40.5 -143.5t125.5 -47.5q62 0 112.5 20t86 57t54.5 90t19 118v123v27v16l-131 -6q-87 -4 -145.5 -21.5t-94.5 -49t-51.5 -77.5t-15.5 -106zM1190 1008q-115 0 -176 -92.5t-72 -270.5h471q0 81 -12 148t-38 115t-68.5 74t-104.5 26zM1221 -20 q-150 0 -254.5 59t-161.5 174q-19 -46 -53 -88t-82.5 -74.5t-111 -51.5t-138.5 -19q-68 0 -126.5 19.5t-101 60t-66.5 102t-24 145.5q0 163 116 242t351 86l170 6v123q0 55 -6 101.5t-26 80t-57.5 52t-100.5 18.5q-59 0 -95.5 -16.5t-57 -46.5t-27.5 -71t-7 -89 q-85 0 -129.5 29t-44.5 100q0 53 29 90t79.5 60.5t117.5 34.5t143 11q116 0 195.5 -29.5t124.5 -95.5q114 125 317 125q99 0 178 -31t134 -92.5t84.5 -153t29.5 -212.5v-94h-682q2 -112 21.5 -192.5t58 -132.5t97.5 -76.5t140 -24.5q45 0 87 11t78.5 30.5t66 45.5t49.5 56 q14 -6 26.5 -25t12.5 -45q0 -31 -22 -66.5t-66 -65.5t-110.5 -50t-155.5 -20z" />-<glyph glyph-name="ccedilla" unicode="ç" horiz-adv-x="1008" d="M580 -20q-102 0 -188 31.5t-148 99.5t-96.5 174.5t-34.5 257.5q0 164 34.5 274.5t96 177.5t145 95t180.5 28q64 0 127.5 -12.5t114.5 -38.5t83 -65.5t32 -92.5q0 -71 -46 -100t-137 -29q0 48 -8 91t-27.5 75.5t-53 51t-85.5 18.5q-59 0 -106.5 -22t-81.5 -76t-52 -145 t-18 -228q0 -218 72.5 -325t237.5 -107q95 0 166 40t106 103q15 -12 25 -32t10 -48q0 -35 -22 -70t-65.5 -63t-108.5 -45.5t-152 -17.5zM784 -258q0 -109 -69.5 -171.5t-200.5 -62.5q-16 0 -36 1.5t-41 4.5t-42 7.5t-39 9.5v104q37 -8 74 -12t65 -4q59 0 92 31t33 84 q0 60 -43.5 90t-110.5 35l43 159h97l-21 -88q100 -8 149.5 -57.5t49.5 -130.5z" />-<glyph glyph-name="egrave" unicode="è" horiz-adv-x="1096" d="M563 1008q-114 0 -175.5 -92.5t-72.5 -270.5h471q0 81 -12 148t-38 115t-68.5 74t-104.5 26zM588 -20q-111 0 -199.5 37.5t-149.5 109.5t-93.5 176.5t-32.5 237.5q0 287 118 432t336 145q99 0 178 -31t134 -92.5t84.5 -153t29.5 -212.5v-94h-682q2 -112 22.5 -192.5 t59 -132.5t94.5 -76.5t129 -24.5q53 0 98.5 12t82.5 32t65.5 45.5t46.5 53.5q14 -6 26.5 -25t12.5 -45q0 -31 -22 -66.5t-67 -65.5t-112.5 -50t-158.5 -20zM683 1241h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67 v-27z" />-<glyph glyph-name="eacute" unicode="é" horiz-adv-x="1096" d="M563 1008q-114 0 -175.5 -92.5t-72.5 -270.5h471q0 81 -12 148t-38 115t-68.5 74t-104.5 26zM588 -20q-111 0 -199.5 37.5t-149.5 109.5t-93.5 176.5t-32.5 237.5q0 287 118 432t336 145q99 0 178 -31t134 -92.5t84.5 -153t29.5 -212.5v-94h-682q2 -112 22.5 -192.5 t59 -132.5t94.5 -76.5t129 -24.5q53 0 98.5 12t82.5 32t65.5 45.5t46.5 53.5q14 -6 26.5 -25t12.5 -45q0 -31 -22 -66.5t-67 -65.5t-112.5 -50t-158.5 -20zM473 1268q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5 h-78v27z" />-<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="1096" d="M563 1008q-114 0 -175.5 -92.5t-72.5 -270.5h471q0 81 -12 148t-38 115t-68.5 74t-104.5 26zM588 -20q-111 0 -199.5 37.5t-149.5 109.5t-93.5 176.5t-32.5 237.5q0 287 118 432t336 145q99 0 178 -31t134 -92.5t84.5 -153t29.5 -212.5v-94h-682q2 -112 22.5 -192.5 t59 -132.5t94.5 -76.5t129 -24.5q53 0 98.5 12t82.5 32t65.5 45.5t46.5 53.5q14 -6 26.5 -25t12.5 -45q0 -31 -22 -66.5t-67 -65.5t-112.5 -50t-158.5 -20zM255 1268l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80 q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="edieresis" unicode="ë" horiz-adv-x="1096" d="M563 1008q-114 0 -175.5 -92.5t-72.5 -270.5h471q0 81 -12 148t-38 115t-68.5 74t-104.5 26zM588 -20q-111 0 -199.5 37.5t-149.5 109.5t-93.5 176.5t-32.5 237.5q0 287 118 432t336 145q99 0 178 -31t134 -92.5t84.5 -153t29.5 -212.5v-94h-682q2 -112 22.5 -192.5 t59 -132.5t94.5 -76.5t129 -24.5q53 0 98.5 12t82.5 32t65.5 45.5t46.5 53.5q14 -6 26.5 -25t12.5 -45q0 -31 -22 -66.5t-67 -65.5t-112.5 -50t-158.5 -20zM253 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20 t-41 -6q-45 0 -74.5 26t-29.5 89zM642 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="igrave" unicode="ì" horiz-adv-x="655" d="M74 86q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v649q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h366v-865q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-582v86h27zM436 1241h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219 q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="iacute" unicode="í" horiz-adv-x="655" d="M74 86q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v649q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h366v-865q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-582v86h27zM240 1268q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5 t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="655" d="M74 86q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v649q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h366v-865q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-582v86h27zM22 1268l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81 l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="655" d="M74 86q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v649q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h366v-865q0 -48 13.5 -77t36 -44.5t53.5 -20.5t65 -5h27v-86h-582v86h27zM18 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54 q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM407 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="eth" unicode="ð" horiz-adv-x="1182" d="M307 1559q94 -23 184 -60.5t171 -91.5l264 154v-117l-181 -103q72 -60 132 -137.5t102.5 -171.5t66 -203.5t23.5 -232.5q0 -312 -122.5 -464t-358.5 -152q-111 0 -199 32.5t-149.5 98.5t-94 165.5t-32.5 233.5q0 266 121.5 396t359.5 130q68 0 126 -14t109 -39 q-21 68 -74.5 143.5t-131.5 143.5l-256 -146v115l172 98q-51 34 -109 62.5t-123 48.5v111zM311 510q0 -105 15 -184t48.5 -132.5t87 -80.5t130.5 -27t130 27t86 80.5t47.5 132.5t14.5 184q0 104 -15 182.5t-48 131t-86.5 78.5t-130.5 26t-130 -26t-86 -78.5t-48 -131 t-15 -182.5z" />-<glyph glyph-name="ntilde" unicode="ñ" horiz-adv-x="1321" d="M608 86v-86h-551v86h17q35 0 65.5 5t53 20.5t36 44.5t13.5 77v639q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h331l27 -166h10q32 57 67.5 93.5t75 57t84 28t93.5 7.5q81 0 144.5 -23.5t108 -72t68 -124.5t23.5 -181v-484q0 -48 11.5 -77t32.5 -44.5t50 -20.5 t63 -5h7v-86h-357v707q0 67 -12 119t-38.5 88t-69.5 54.5t-105 18.5q-70 0 -117.5 -27t-76.5 -73t-41.5 -106t-12.5 -126v-432q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6zM842 1374q30 0 48.5 9t29 24.5t15 35t7.5 40.5h92q-3 -47 -16.5 -90.5t-39.5 -77.5 t-65 -54t-94 -20t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-31 0 -49 -9t-28.5 -24t-15.5 -34.5t-8 -40.5h-92q3 47 16.5 90t40 77t66 54t94.5 20t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="ograve" unicode="ò" horiz-adv-x="1182" d="M1069 551q0 -289 -122.5 -430t-358.5 -141q-111 0 -199 35t-149.5 106t-94 178.5t-32.5 251.5q0 287 121.5 427t359.5 140q111 0 199 -34.5t149.5 -105t94 -177t32.5 -250.5zM311 551q0 -114 15 -201t48.5 -145.5t87 -88.5t130.5 -30t130 30t86 88.5t47.5 145.5t14.5 201 t-15 200t-48 143.5t-86.5 86.5t-130.5 29t-130 -29t-86 -86.5t-48 -143.5t-15 -200zM696 1241h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="oacute" unicode="ó" horiz-adv-x="1182" d="M1069 551q0 -289 -122.5 -430t-358.5 -141q-111 0 -199 35t-149.5 106t-94 178.5t-32.5 251.5q0 287 121.5 427t359.5 140q111 0 199 -34.5t149.5 -105t94 -177t32.5 -250.5zM311 551q0 -114 15 -201t48.5 -145.5t87 -88.5t130.5 -30t130 30t86 88.5t47.5 145.5t14.5 201 t-15 200t-48 143.5t-86.5 86.5t-130.5 29t-130 -29t-86 -86.5t-48 -143.5t-15 -200zM512 1268q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="ocircumflex" unicode="ô" horiz-adv-x="1182" d="M1069 551q0 -289 -122.5 -430t-358.5 -141q-111 0 -199 35t-149.5 106t-94 178.5t-32.5 251.5q0 287 121.5 427t359.5 140q111 0 199 -34.5t149.5 -105t94 -177t32.5 -250.5zM311 551q0 -114 15 -201t48.5 -145.5t87 -88.5t130.5 -30t130 30t86 88.5t47.5 145.5t14.5 201 t-15 200t-48 143.5t-86.5 86.5t-130.5 29t-130 -29t-86 -86.5t-48 -143.5t-15 -200zM284 1268l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="otilde" unicode="õ" horiz-adv-x="1182" d="M1069 551q0 -289 -122.5 -430t-358.5 -141q-111 0 -199 35t-149.5 106t-94 178.5t-32.5 251.5q0 287 121.5 427t359.5 140q111 0 199 -34.5t149.5 -105t94 -177t32.5 -250.5zM311 551q0 -114 15 -201t48.5 -145.5t87 -88.5t130.5 -30t130 30t86 88.5t47.5 145.5t14.5 201 t-15 200t-48 143.5t-86.5 86.5t-130.5 29t-130 -29t-86 -86.5t-48 -143.5t-15 -200zM757 1374q30 0 48.5 9t29 24.5t15 35t7.5 40.5h92q-3 -47 -16.5 -90.5t-39.5 -77.5t-65 -54t-94 -20t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-31 0 -49 -9t-28.5 -24t-15.5 -34.5t-8 -40.5 h-92q3 47 16.5 90t40 77t66 54t94.5 20t99.5 -20t83 -44.5l72 -44.5t65.5 -20z" />-<glyph glyph-name="odieresis" unicode="ö" horiz-adv-x="1182" d="M1069 551q0 -289 -122.5 -430t-358.5 -141q-111 0 -199 35t-149.5 106t-94 178.5t-32.5 251.5q0 287 121.5 427t359.5 140q111 0 199 -34.5t149.5 -105t94 -177t32.5 -250.5zM311 551q0 -114 15 -201t48.5 -145.5t87 -88.5t130.5 -30t130 30t86 88.5t47.5 145.5t14.5 201 t-15 200t-48 143.5t-86.5 86.5t-130.5 29t-130 -29t-86 -86.5t-48 -143.5t-15 -200zM284 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM673 1409q0 32 8 54t22 35.5t33 19.5 t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="divide" unicode="÷" d="M1012 672h-879v121h879v-121zM469 1120q0 32 8 54t22 35t33 18.5t41 5.5t41 -5.5t33.5 -18.5t22.5 -35t8 -54q0 -31 -8 -52.5t-22.5 -35t-33.5 -19t-41 -5.5t-41 5.5t-33 19t-22 35t-8 52.5zM469 344q0 32 8 54t22 35t33 18.5t41 5.5t41 -5.5t33.5 -18.5t22.5 -35t8 -54 q0 -31 -8 -53t-22.5 -35t-33.5 -19t-41 -6q-45 0 -74.5 25t-29.5 88z" />-<glyph glyph-name="oslash" unicode="ø" horiz-adv-x="1182" d="M930 991q68 -69 103.5 -178.5t35.5 -261.5q0 -289 -122.5 -430t-358.5 -141q-71 0 -133 14t-113 43l-74 -119h-121l111 180q-71 72 -108 183.5t-37 269.5q0 287 121.5 427t359.5 140q74 0 137.5 -16t116.5 -47l78 125h118zM311 551q0 -94 10 -169t31 -132l424 686 q-68 74 -186 74q-77 0 -130 -29t-86 -86.5t-48 -143.5t-15 -200zM870 551q0 177 -36 285l-422 -684q32 -32 76.5 -49t103.5 -17q77 0 130 30t86 88.5t47.5 145.5t14.5 201z" />-<glyph glyph-name="ugrave" unicode="ù" horiz-adv-x="1300" d="M1079 223q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6v-86h-325l-27 166h-10q-31 -58 -68.5 -94t-79.5 -56.5t-88 -28t-96 -7.5q-81 0 -144 23t-106 72t-65.5 125t-22.5 181v491q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h367v-707q0 -67 10.5 -119 t35 -88t66 -54.5t103.5 -18.5q68 0 116.5 24t80 67.5t46.5 104.5t15 135v422q0 48 -13.5 77.5t-36 45t-53 20.5t-65.5 5h-6v86h366v-875zM712 1241h-78q-41 28 -89 69.5t-93 85.5t-82 84.5t-56 67.5v21h219q16 -34 37.5 -74.5t45.5 -81t49 -78.5t47 -67v-27z" />-<glyph glyph-name="uacute" unicode="ú" horiz-adv-x="1300" d="M1079 223q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6v-86h-325l-27 166h-10q-31 -58 -68.5 -94t-79.5 -56.5t-88 -28t-96 -7.5q-81 0 -144 23t-106 72t-65.5 125t-22.5 181v491q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h367v-707q0 -67 10.5 -119 t35 -88t66 -54.5t103.5 -18.5q68 0 116.5 24t80 67.5t46.5 104.5t15 135v422q0 48 -13.5 77.5t-36 45t-53 20.5t-65.5 5h-6v86h366v-875zM541 1268q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="ucircumflex" unicode="û" horiz-adv-x="1300" d="M1079 223q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6v-86h-325l-27 166h-10q-31 -58 -68.5 -94t-79.5 -56.5t-88 -28t-96 -7.5q-81 0 -144 23t-106 72t-65.5 125t-22.5 181v491q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h367v-707q0 -67 10.5 -119 t35 -88t66 -54.5t103.5 -18.5q68 0 116.5 24t80 67.5t46.5 104.5t15 135v422q0 48 -13.5 77.5t-36 45t-53 20.5t-65.5 5h-6v86h366v-875zM342 1268l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5 q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="udieresis" unicode="ü" horiz-adv-x="1300" d="M1079 223q0 -45 13.5 -72.5t36.5 -41.5t53.5 -18.5t64.5 -4.5h6v-86h-325l-27 166h-10q-31 -58 -68.5 -94t-79.5 -56.5t-88 -28t-96 -7.5q-81 0 -144 23t-106 72t-65.5 125t-22.5 181v491q0 45 -13.5 72.5t-36.5 42.5t-53.5 20t-64.5 5h-6v86h367v-707q0 -67 10.5 -119 t35 -88t66 -54.5t103.5 -18.5q68 0 116.5 24t80 67.5t46.5 104.5t15 135v422q0 48 -13.5 77.5t-36 45t-53 20.5t-65.5 5h-6v86h366v-875zM348 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6 q-45 0 -74.5 26t-29.5 89zM737 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="yacute" unicode="ý" horiz-adv-x="1157" d="M1157 1098v-86h-6q-30 0 -51.5 -6.5t-39 -24.5t-32.5 -49t-33 -80l-311 -860q-36 -99 -68 -174t-67 -128.5t-76.5 -88.5t-94.5 -56t-122 -29t-160 -8h-18v97q104 0 179 31t129.5 85t91 127.5t61.5 159.5l-379 895q-14 32 -27 52.5t-29.5 33.5t-38 18t-51.5 5h-6v86h492 v-86h-6q-62 0 -92.5 -24t-30.5 -75q0 -17 3.5 -34.5t12.5 -40.5l150 -365l29.5 -76.5t29 -82l24.5 -76.5t15 -62h6q11 45 30.5 109.5t45.5 138.5l137 399q9 25 13.5 48t4.5 40q0 53 -33.5 77t-101.5 24h-6v86h426zM504 1268q23 29 47.5 67t48 78.5l45 81t37.5 74.5h219v-21 q-19 -27 -56 -67.5t-82 -84.5t-92.5 -85.5t-88.5 -69.5h-78v27z" />-<glyph glyph-name="thorn" unicode="þ" horiz-adv-x="1257" d="M692 987q-80 0 -133.5 -26.5t-85.5 -80.5t-45.5 -136t-13.5 -193q0 -107 13.5 -189t46 -138t86 -84.5t134.5 -28.5q67 0 115 28.5t78.5 84.5t44.5 138.5t14 190.5q0 218 -59 326t-195 108zM1145 551q0 -148 -27.5 -256t-80.5 -178t-131 -103.5t-179 -33.5q-59 0 -107 13 t-86.5 37t-68 57t-51.5 73h-8q2 -53 4 -99q1 -20 1.5 -40t1 -38t1 -32.5t0.5 -22.5v-196q0 -45 13.5 -72.5t36.5 -42t53.5 -19t64.5 -4.5h6v-86h-551v86h16q34 0 65 5t53.5 20.5t36 45t13.5 77.5v1589q0 45 -13.5 72.5t-36.5 42.5t-53.5 19.5t-64.5 4.5h-16v86h377v-376 q0 -35 -1 -80.5t-3 -87.5l-4 -99h8q23 47 52 85t67 64.5t86 41t108 14.5q101 0 179 -33.5t131 -103t80.5 -176.5t27.5 -254z" />-<glyph glyph-name="ydieresis" unicode="ÿ" horiz-adv-x="1157" d="M1157 1098v-86h-6q-30 0 -51.5 -6.5t-39 -24.5t-32.5 -49t-33 -80l-311 -860q-36 -99 -68 -174t-67 -128.5t-76.5 -88.5t-94.5 -56t-122 -29t-160 -8h-18v97q104 0 179 31t129.5 85t91 127.5t61.5 159.5l-379 895q-14 32 -27 52.5t-29.5 33.5t-38 18t-51.5 5h-6v86h492 v-86h-6q-62 0 -92.5 -24t-30.5 -75q0 -17 3.5 -34.5t12.5 -40.5l150 -365l29.5 -76.5t29 -82l24.5 -76.5t15 -62h6q11 45 30.5 109.5t45.5 138.5l137 399q9 25 13.5 48t4.5 40q0 53 -33.5 77t-101.5 24h-6v86h426zM320 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6 t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM709 1409q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="1964" d="M1167 102h396q48 0 82.5 13.5t57.5 36.5t36 53.5t18 64.5l15 88h106l-14 -358h-893q-21 -5 -47.5 -8.5t-55 -6t-56.5 -4t-52 -1.5q-163 0 -284 54t-201 153t-120 238.5t-40 309.5t40 308.5t120 236.5t202 151.5t285 53.5q24 0 52.5 -1.5t57 -4.5t54.5 -7t47 -10h825 l10 -358h-106l-10 88q-4 34 -15.5 64.5t-33 53.5t-54 36.5t-78.5 13.5h-344v-545h494v-100h-494v-613zM760 90q60 0 110 8.5t91 22.5v1218q-41 17 -90 26t-109 9q-114 0 -194 -43t-130.5 -125t-73 -201.5t-22.5 -271.5t22.5 -271.5t72.5 -202t129.5 -126t193.5 -43.5z" />-<glyph glyph-name="oe" unicode="œ" horiz-adv-x="1853" d="M311 551q0 -114 15 -201t48.5 -145.5t87 -88.5t130.5 -30q76 0 128.5 29t85.5 86.5t48 142.5t16 197v28q-1 110 -17 192.5t-49 138t-86 83t-128 27.5q-77 0 -130 -29t-86 -86.5t-48 -143.5t-15 -200zM1321 1008q-115 0 -176 -92.5t-72 -270.5h471q0 81 -12 148t-38 115 t-68.5 74t-104.5 26zM1346 -20q-130 0 -221.5 52t-151.5 152q-119 -204 -385 -204q-111 0 -199 35t-149.5 106t-94 178.5t-32.5 251.5q0 287 121.5 427t359.5 140q124 0 217.5 -49t155.5 -149q58 100 147.5 149t210.5 49q99 0 178 -31t134 -92.5t84.5 -153t29.5 -212.5v-94 h-682q2 -99 19 -177.5t53 -134t93 -85t140 -29.5q53 0 98.5 12t82.5 32t65.5 45.5t46.5 53.5q14 -6 26.5 -25t12.5 -45q0 -31 -22 -66.5t-67 -65.5t-112.5 -50t-158.5 -20z" />-<glyph glyph-name="Ydieresis" unicode="Ÿ" horiz-adv-x="1280" d="M326 0v86h47q34 0 64.5 4.5t53.5 18.5t36.5 41.5t13.5 72.5v387l-379 658q-17 29 -32 49.5t-31.5 33.5t-36.5 19t-46 6h-26v86h563v-86h-76q-28 0 -45.5 -5t-27.5 -14t-13.5 -21t-3.5 -25q0 -29 12.5 -58t24.5 -51l151 -274q36 -63 61 -124.5t42 -109.5q9 22 22.5 49 l30 57.5l34.5 63l36 64.5l131 235q20 35 28.5 66.5t8.5 56.5q0 45 -32 67.5t-91 22.5h-60v86h500v-86h-24q-22 0 -41.5 -7.5t-39.5 -26t-41.5 -49t-47.5 -76.5l-344 -607v-377q0 -48 13 -77t36 -44.5t53.5 -20.5t64.5 -5h48v-86h-637zM359 1747q0 32 8 54t22 35.5t33 19.5 t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89zM748 1747q0 32 8 54t22 35.5t33 19.5t41 6t41 -6t33.5 -19.5t22.5 -35.5t8 -54q0 -31 -8 -53t-22.5 -36t-33.5 -20t-41 -6q-45 0 -74.5 26t-29.5 89z" />-<glyph glyph-name="circumflex" unicode="ˆ" horiz-adv-x="1182" d="M289 1268l53 67l57.5 78.5t53.5 81t41 74.5h194q16 -34 41 -74.5t53.5 -81l57.5 -78.5l53 -67v-27h-80q-59 34 -118 84.5t-105 99.5q-47 -49 -105 -99.5t-116 -84.5h-80v27z" />-<glyph glyph-name="tilde" unicode="˜" horiz-adv-x="1182" d="M762 1374q30 0 48.5 9t29 24.5t15 35t7.5 40.5h92q-3 -47 -16.5 -90.5t-39.5 -77.5t-65 -54t-94 -20t-99.5 20t-83 44.5l-72 44.5t-66.5 20q-31 0 -49 -9t-28.5 -24t-15.5 -34.5t-8 -40.5h-92q3 47 16.5 90t40 77t66 54t94.5 20t99.5 -20t83 -44.5l72 -44.5t65.5 -20z " />-<glyph glyph-name="endash" unicode="–" horiz-adv-x="1024" d="M1034 489h-1044v121h1044v-121z" />-<glyph glyph-name="emdash" unicode="—" horiz-adv-x="2048" d="M2058 489h-2068v121h2068v-121z" />-<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="512" d="M115 1063q0 65 18 126t58.5 113t104.5 93.5t155 68.5v-86q-101 -32 -148 -78t-47 -106q0 -20 11 -33.5t28 -24t36 -20.5t36 -24t28 -34.5t11 -51.5q0 -59 -38.5 -90t-95.5 -31q-31 0 -59.5 11.5t-50.5 34t-34.5 56t-12.5 76.5z" />-<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="512" d="M397 1284q0 -65 -18 -126t-58.5 -113t-104 -93.5t-155.5 -68.5v86q101 32 148 78t47 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38.5 90t95.5 31q32 0 60 -11.5t50 -34t34.5 -56t12.5 -76.5z" />-<glyph glyph-name="quotesinglbase" unicode="‚" horiz-adv-x="512" d="M397 86q0 -65 -18 -126t-58.5 -113t-104 -93.5t-155.5 -68.5v86q101 32 148 78t47 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38.5 90t95.5 31q32 0 60 -11.5t50 -34t34.5 -56t12.5 -76.5z" />-<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="922" d="M524 1063q0 65 18 126t58.5 113t104.5 93.5t155 68.5v-86q-100 -32 -147 -78t-47 -106q0 -20 11 -33.5t27.5 -24t36 -20.5t36 -24t27.5 -34.5t11 -51.5q0 -59 -38 -90t-95 -31q-31 0 -60 11.5t-50.5 34t-34.5 56t-13 76.5zM115 1063q0 65 18 126t58.5 113t104.5 93.5 t155 68.5v-86q-101 -32 -148 -78t-47 -106q0 -20 11 -33.5t28 -24t36 -20.5t36 -24t28 -34.5t11 -51.5q0 -59 -38.5 -90t-95.5 -31q-31 0 -59.5 11.5t-50.5 34t-34.5 56t-12.5 76.5z" />-<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="922" d="M397 1284q0 -65 -18 -126t-58.5 -113t-104 -93.5t-155.5 -68.5v86q101 32 148 78t47 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38.5 90t95.5 31q32 0 60 -11.5t50 -34t34.5 -56t12.5 -76.5zM807 1284q0 -65 -18 -126t-58.5 -113t-104 -93.5 t-155.5 -68.5v86q100 32 147.5 78t47.5 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38 90t95 31q32 0 60.5 -11.5t50 -34t34.5 -56t13 -76.5z" />-<glyph glyph-name="quotedblbase" unicode="„" horiz-adv-x="922" d="M397 86q0 -65 -18 -126t-58.5 -113t-104 -93.5t-155.5 -68.5v86q101 32 148 78t47 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38.5 90t95.5 31q32 0 60 -11.5t50 -34t34.5 -56t12.5 -76.5zM807 86q0 -65 -18 -126t-58.5 -113t-104 -93.5 t-155.5 -68.5v86q100 32 147.5 78t47.5 106q0 20 -11 33.5t-28 24t-36 20.5t-36 24t-28 34.5t-11 51.5q0 59 38 90t95 31q32 0 60.5 -11.5t50 -34t34.5 -56t13 -76.5z" />-<glyph glyph-name="bullet" unicode="•" horiz-adv-x="741" d="M100 729q0 84 20.5 141t56.5 91.5t86 49.5t108 15q56 0 105 -15t86 -49.5t58 -91.5t21 -141t-21 -140.5t-58 -91.5t-86 -50t-105 -15q-58 0 -108 15t-86 50t-56.5 91.5t-20.5 140.5z" />-<glyph glyph-name="ellipsis" unicode="…" horiz-adv-x="1757" d="M164 125q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5q0 -39 -10.5 -66t-28 -43t-41 -23t-49.5 -7q-27 0 -50.5 7t-41 23t-27.5 43t-10 66zM750 125q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5 q0 -39 -10.5 -66t-28 -43t-41 -23t-49.5 -7q-27 0 -50.5 7t-41 23t-27.5 43t-10 66zM1335 125q0 40 10 66.5t27.5 42.5t41 23t50.5 7q26 0 49.5 -7t41 -23t28 -42.5t10.5 -66.5q0 -39 -10.5 -66t-28 -43t-41 -23t-49.5 -7q-27 0 -50.5 7t-41 23t-27.5 43t-10 66z" />-<glyph glyph-name="guilsinglleft" unicode="‹" horiz-adv-x="682" d="M133 586l313 356h103l-207 -389l207 -389h-103l-313 356v66z" />-<glyph glyph-name="guilsinglright" unicode="›" horiz-adv-x="682" d="M551 520l-313 -356h-103l207 389l-207 389h103l313 -356v-66z" />-<glyph glyph-name="Euro" unicode="€" d="M776 100q52 0 92.5 10t71.5 27t54.5 39.5t41.5 46.5q13 -8 25 -23t12 -46q0 -27 -18.5 -57.5t-56.5 -56.5t-96 -43t-138 -17q-96 0 -184 30.5t-159 98t-120 175.5t-68 263h-149v96h141q-2 23 -3 50t-1 48v45h-137v97h145q14 171 59.5 285.5t114 183.5t155 98t181.5 29 q78 0 141.5 -15.5t109 -43t70.5 -65.5t25 -83q0 -71 -45.5 -100t-132.5 -29q0 48 -10 91t-32 75t-57.5 50.5t-86.5 18.5q-53 0 -102 -23t-88.5 -80t-67 -152.5t-37.5 -239.5h430v-97h-434v-49v-48t2 -46h350v-96h-342q13 -109 42.5 -192.5t73.5 -140t101.5 -85.5t126.5 -29z " />-<glyph glyph-name="trademark" unicode="™" horiz-adv-x="1710" d="M1321 754v55q35 0 56 10t24 45v457l-232 -567h-71l-232 569v-451q0 -41 21 -52t61 -11v-55h-248v55h21q31 0 54.5 10t25.5 47v482q-1 19 -7.5 30.5t-17.5 17.5t-25.5 7.5t-29.5 1.5h-21v57h236l225 -567l232 567h231v-57h-22q-17 0 -31.5 -2t-25 -8t-16 -18.5t-5.5 -33.5 v-471q0 -21 5.5 -33t16 -19t25 -9t31.5 -2h22v-55h-303zM422 872q0 -21 6.5 -33t17 -19t25 -9t29.5 -2h32v-55h-348v55h35q15 0 29 2t24.5 8t16.5 17.5t6 29.5v531h-90q-22 -1 -37 -6.5t-24 -15.5t-14 -22.5t-7 -27.5l-8 -49h-60l6 186h598l7 -186h-60l-8 49q-4 29 -21 50 t-61 22h-94v-525z" />-</font>-</defs></svg>
− extra/fonts/DroidSerif-Regular.ttf
binary file changed (41852 → absent bytes)
− extra/fonts/DroidSerif-Regular.woff
binary file changed (26972 → absent bytes)
− extra/haddock.css
@@ -1,478 +0,0 @@-/* -------- Global things --------- */--@font-face {- font-family: 'DroidSerif';- src: url('fonts/DroidSerif-Regular.eot');- src: local('Droid Serif'),- url('fonts/DroidSerif-Regular.woff') format('woff'),- url('fonts/DroidSerif-Regular.ttf') format('truetype'),- url('fonts/DroidSerif-Regular.svg#DroidSerif') format('svg');-}--@font-face {- font-family: 'DroidSerif';- font-style: italic;- src: url('fonts/DroidSerif-Italic.eot');- src: local('Droid Serif'),- url('fonts/DroidSerif-Italic.woff') format('woff'),- url('fonts/DroidSerif-Italic.ttf') format('truetype'),- url('fonts/DroidSerif-Italic.svg#DroidSerif-Italic') format('svg');-}--@font-face {- font-family: 'DroidSerif';- font-weight: bold;- src: url('fonts/DroidSerif-Bold.eot');- src: local('Droid Serif'),- url('fonts/DroidSerif-Bold.woff') format('woff'),- url('fonts/DroidSerif-Bold.ttf') format('truetype'),- url('fonts/DroidSerif-Bold.svg#DroidSerif-Bold') format('svg');-}--@font-face {- font-family: 'DroidSerif';- src: url('fonts/DroidSerif-BoldItalic.eot');- font-weight: bold;- font-style: italic;- src: local('Droid Serif'),- url('fonts/DroidSerif-BoldItalic.woff') format('woff'),- url('fonts/DroidSerif-BoldItalic.ttf') format('truetype'),- url('fonts/DroidSerif-BoldItalic.svg#DroidSerif-BoldItalic') format('svg');-}----HTML {- background-color: #f0f3ff;- width: 100%;-}--BODY { - -moz-border-radius:5px;- -webkit-border-radius:5px;- width: 50em;- margin: 2em auto;- padding: 0;- background-color: #ffffff;- color: #000000;- font-size: 110%;- font-family: DroidSerif, Georgia, serif;- }--A:link { color: #5200A3; text-decoration: none }-A:visited { color: #5200A3; text-decoration: none }-A:hover { color: #5200A3; text-decoration: none; border-bottom:#5200A3 dashed 1px; }--TABLE.vanilla {- width: 100%;- border-width: 0px;- /* I can't seem to specify cellspacing or cellpadding properly using CSS... */-}--DL {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- letter-spacing: -0.01em;- margin: 0;-}--.vanilla .vanilla dl { font-size: 80%; }-.vanilla .vanilla dl dl { padding-left: 0; font-size: 95%; }--TD.section1, TD.section2, TD.section3, TD.section4, TD.doc, DL {- padding: 0 30px 0 34px;-}--TABLE.vanilla2 {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- border-width: 0px;-}--/* <TT> font is a little too small in MSIE */-TT, PRE, CODE {- font-family: Monaco,- "DejaVu Sans Mono",- "Bitstream Vera Sans Mono",- "Lucida Console",- monospace;- font-size: 90%;-}--LI P { margin: 0pt } --P { margin-top: 0; margin-bottom: 0.75em; }--TD {- border-width: 0px;-}--TABLE.narrow {- border-width: 0px;-}--TD.s8 { height: 0; margin:0; padding: 0 }-TD.s15 { height: 20px; }--SPAN.keyword { text-decoration: underline; }--/* Resize the buttom image to match the text size */-IMG.coll { width : 0.75em; height: 0.75em; margin-bottom: 0; margin-right: 0.5em }--/* --------- Contents page ---------- */--DIV.node {- padding-left: 3em;-}--DIV.cnode {- padding-left: 1.75em;-}--SPAN.pkg {- position: absolute;- left: 50em;-}--/* --------- Documentation elements ---------- */--TD FONT { font-weight: bold; letter-spacing: -0.02em; }--TD.children {- padding-left: 25px;- }--TD.synopsis {- padding: 2px;- background-color: #f0f0f0;- font-size: 80%;- font-family: Monaco,- "DejaVu Sans Mono",- "Bitstream Vera Sans Mono",- "Lucida Console",- monospace;-- }--TD.decl { - padding: 4px 8px;- background-color: #FAFAFA; - border-bottom: #F2F2F2 solid 1px;- border-top: #FCFCFC solid 1px;- font-size: 80%;- font-family: Monaco,- "DejaVu Sans Mono",- "Bitstream Vera Sans Mono",- "Lucida Console",- monospace;-- vertical-align: top;- }--TD.decl TD.decl {- font-size: 100%;- padding: 4px 0;- border: 0;-}--TD.topdecl {- padding: 20px 30px 0.5ex 30px;- font-size: 80%;- font-family: Monaco,- "DejaVu Sans Mono",- "Bitstream Vera Sans Mono",- "Lucida Console",- monospace;-;- vertical-align: top;-}--.vanilla .vanilla .vanilla .topdecl {- padding-left: 0;- padding-right: 0;-}--.vanilla .vanilla .vanilla {- padding-left: 30px;-}--.decl .vanilla {- padding-left: 0px !important;-}--.body .vanilla .body {- padding-left: 0;- padding-right: 0;-}--.body .vanilla .body .decl {- padding-left: 12px;-}--.body .vanilla .body div .vanilla .decl {- padding-left: 12px;-}--TABLE.declbar {- background-color: #f0f0f0;- border-spacing: 0px;- border-bottom:1px solid #d7d7df;- border-right:1px solid #d7d7df;- border-top:1px solid #f4f4f9;- border-left:1px solid #f4f4f9;- padding: 4px;- }--TD.declname {- width: 100%;- padding-right: 4px;- }--TD.declbut {- padding-left: 8px;- padding-right: 5px;- border-left-width: 1px;- border-left-color: #000099;- border-left-style: solid;- white-space: nowrap;- font-size: x-small;- }--/* - arg is just like decl, except that wrapping is not allowed. It is- used for function and constructor arguments which have a text box- to the right, where if wrapping is allowed the text box squashes up- the declaration by wrapping it.-*/-TD.arg { - padding: 2px 12px;- background-color: #f0f0f0; - font-size: 80%;- font-family: Monaco,- "DejaVu Sans Mono",- "Bitstream Vera Sans Mono",- "Lucida Console",- monospace;-- vertical-align: top;- white-space: nowrap;- }--TD.recfield { padding-left: 20px }--TD.doc { - padding-left: 38px;- font-size: 95%;- line-height: 1.66;- }--TD.ndoc { - font-size: 95%;- line-height: 1.66;- padding: 2px 4px 2px 8px;- }--TD.rdoc { - padding: 2px;- padding-left: 30px;- width: 100%;- font-size: 80%;- font-style: italic;- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- }--TD.body { - padding: 0 30px;- }--TD.pkg {- width: 100%;- padding-left: 30px-}--TABLE.indexsearch TR.indexrow {- display: none;-}-TABLE.indexsearch TR.indexshow {- display: table-row;-}--TD.indexentry {- vertical-align: top;- padding: 0 30px- }--TD.indexannot {- vertical-align: top;- padding-left: 20px;- white-space: nowrap- }--TD.indexlinks {- width: 100%- }--/* ------- Section Headings ------- */--TD.section1, TD.section2, TD.section3, TD.section4, TD.section5 {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;-}--TD.section1 {- padding-top: 14px;- font-weight: bold;- letter-spacing: -0.02em;- font-size: 140%- }--TD.section2 {- padding-top: 4px;- font-weight: bold;- letter-spacing: -0.02em;- font-size: 120%- }--TD.section3 {- padding-top: 5px;- font-weight: bold;- letter-spacing: -0.02em;- font-size: 105%- }--TD.section4 {- font-weight: bold;- padding-top: 12px;- padding-bottom: 4px;- letter-spacing: -0.02em;- font-size: 90%- }--/* -------------- The title bar at the top of the page */--TD.infohead {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- color: #ffffff;- font-weight: bold;- padding: 0 30px;- text-align: left;-}--TD.infoval {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- color: #ffffff;- padding: 0 30px;- text-align: left;-}--TD.topbar {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- background-color: #3465a4;- padding: 5px;- -moz-border-radius-topleft:5px;- -moz-border-radius-topright:5px;- -webkit-border-radius-topleft:5px;- -webkit-border-radius-topright:5px;-}--TD.title {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- color: #ffffff;- padding-left: 30px;- letter-spacing: -0.02em;- font-weight: bold;- width: 100%- }--TD.topbut {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- padding-left: 5px;- padding-right: 5px;- border-left-width: 1px;- border-left-color: #ffffff;- border-left-style: solid;- letter-spacing: -0.02em;- font-weight: bold;- white-space: nowrap;- }--TD.topbut A:link {- color: #ffffff- }--TD.topbut A:visited {- color: #ffff00- }--TD.topbut A:hover {- background-color: #C9D3DE;- }--TD.topbut:hover {- background-color: #C9D3DE;- }--TD.modulebar { - font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- color: #141B24;- background-color: #C9D3DE;- padding: 5px;- border-top-width: 1px;- border-top-color: #ffffff;- border-top-style: solid;- -moz-border-radius-bottomleft:5px;- -moz-border-radius-bottomright:5px;- -webkit-border-radius-bottomleft:5px;- -webkit-border-radius-bottomright:5px;-- }--/* --------- The page footer --------- */--TD.botbar {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- -moz-border-radius:5px;- -webkit-border-radius:5px;- background-color: #3465a4;- color: #ffffff;- padding: 5px- }-TD.botbar A:link {- color: #ffffff;- text-decoration: underline- }-TD.botbar A:visited {- color: #ffff00- }-TD.botbar A:hover {- background-color: #6060ff- }--/* --------- Mini Synopsis for Frame View --------- */--.outer {- margin: 0 0;- padding: 0 0;-}--.mini-synopsis {- padding: 0.25em 0.25em;-}--.mini-synopsis H1 { font-size: 120%; }-.mini-synopsis H2 { font-size: 107%; }-.mini-synopsis H3 { font-size: 100%; }-.mini-synopsis H1, .mini-synopsis H2, .mini-synopsis H3 {- font-family: "Gill Sans", "Helvetica Neue","Arial",sans-serif;- margin-top: 0.5em;- margin-bottom: 0.25em;- padding: 0 0;- font-weight: bold; letter-spacing: -0.02em;-}--.mini-synopsis H1 { border-bottom: 1px solid #ccc; }--.mini-topbar {- font-size: 120%;- background: #0077dd;- padding: 0.25em;-}--
− extra/hscolour.css
@@ -1,15 +0,0 @@-body { font-size: 90%; }--pre, code, body {- font-family: Monaco,- "DejaVu Sans Mono",- "Bitstream Vera Sans Mono",- "Lucida Console",- monospace;-}--.hs-keyglyph, .hs-layout {color: #5200A3;}-.hs-keyword {color: #3465a4; font-weight: bold;}-.hs-comment, .hs-comment a {color: #579; }-.hs-str, .hs-chr {color: #141B24;}-.hs-keyword, .hs-conid, .hs-varid, .hs-conop, .hs-varop, .hs-num, .hs-cpp, .hs-sel, .hs-definition {}
− extra/logo.gif
binary file changed (607 → absent bytes)
− haddock.sh
@@ -1,11 +0,0 @@-#!/bin/sh--set -x--HADDOCK_OPTS='--html-location=http://hackage.haskell.org/packages/archive/$pkg/latest/doc/html --css=extra/haddock.css'--cabal haddock $HADDOCK_OPTS --hyperlink-source $@--cp -r extra/fonts dist/doc/html/snap-server/-cp extra/logo.gif dist/doc/html/snap-server/haskell_icon.gif-cp extra/hscolour.css dist/doc/html/snap-server/src/
+ pong/Main.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main where++import Control.Applicative ((<$>))+import Control.Concurrent (MVar, ThreadId, forkIOWithUnmask, killThread, newEmptyMVar, putMVar, takeMVar)+import Control.Exception (SomeException, bracketOnError, evaluate)+import qualified Control.Exception as E+import Data.ByteString.Builder (byteString, toLazyByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Network.Socket as N+import Snap.Core+import System.Environment (getArgs)+import qualified System.IO.Streams as Streams+------------------------------------------------------------------------------+import Snap.Internal.Http.Server.Session (httpAcceptLoop, snapToServerHandler)+import qualified Snap.Internal.Http.Server.Socket as Sock+import qualified Snap.Internal.Http.Server.Types as Types++------------------------------------------------------------------------------+-- | Returns the thread the server is running in as well as the port it is+-- listening on.+startTestSocketServer :: Int -> Snap a -> IO (ThreadId, MVar ())+startTestSocketServer portNum userHandler =+ bracketOnError getSock cleanup forkServer+ where+ getSock = Sock.bindSocket "127.0.0.1" (fromIntegral portNum)++ forkServer sock = do+ port <- fromIntegral <$> N.socketPort sock+ putStrLn $ "starting on " ++ show (port :: Int)+ let scfg = emptyServerConfig+ mv <- newEmptyMVar+ tid <- forkIOWithUnmask $ \unmask -> do+ putStrLn "server start"+ (unmask $ httpAcceptLoop (snapToServerHandler userHandler)+ scfg+ (Sock.httpAcceptFunc sock))+ `E.finally` putMVar mv ()+ return (tid, mv)++ cleanup = N.close++ logAccess _ _ _ = return ()+ _logError !e = L.putStrLn $ toLazyByteString e+ onStart _ = return ()+ onParse _ _ = return ()+ onUserHandlerFinished _ _ _ = return ()+ onDataFinished _ _ _ = return ()+ onExceptionHook _ _ = return ()+ onEscape _ = return ()++ emptyServerConfig = Types.ServerConfig logAccess+ _logError+ onStart+ onParse+ onUserHandlerFinished+ onDataFinished+ onExceptionHook+ onEscape+ "localhost"+ 6+ False+ 1+++main :: IO ()+main = do+ portNum <- (((read . head) <$> getArgs) >>= evaluate)+ `E.catch` \(_::SomeException) -> return 3000+ (tid, mv) <- startTestSocketServer portNum $ do+ modifyResponse $ setContentLength 4 . setResponseBody output+ takeMVar mv+ killThread tid++ where+ output os = Streams.write (Just "pong") os >> return os
snap-server.cabal view
@@ -1,190 +1,558 @@ name: snap-server-version: 0.3.1.1-synopsis: A fast, iteratee-based, epoll-enabled web server for the Snap Framework+version: 1.1.2.1+synopsis: A web server for the Snap Framework description:- This is the first developer prerelease of the Snap framework. Snap is a- simple and fast web development framework and server written in Haskell. For- more information or to download the latest version, you can visit the Snap- project website at <http://snapframework.com/>.- .- The Snap HTTP server is a high performance, epoll-enabled, iteratee-based web- server library written in Haskell. Together with the @snap-core@ library upon- which it depends, it provides a clean and efficient Haskell programming- interface to the HTTP protocol.- .- Higher-level facilities for building web applications (like user/session- management, component interfaces, data modeling, etc.) are planned but not- yet implemented, so this release will mostly be of interest for those who:- .- * need a fast and minimal HTTP API at roughly the same level of abstraction- as Java servlets, or+ Snap is a simple and fast web development framework and server written in+ Haskell. For more information or to download the latest version, you can+ visit the Snap project website at <http://snapframework.com/>. .- * are interested in contributing to the Snap Framework project.+ The Snap HTTP server is a high performance web server library written in+ Haskell. Together with the @snap-core@ library upon which it depends, it+ provides a clean and efficient Haskell programming interface to the HTTP+ protocol. license: BSD3 license-file: LICENSE-author: James Sanders, Gregory Collins, Doug Beardsley+author: Snap Framework Authors (see CONTRIBUTORS) maintainer: snap@snapframework.com build-type: Simple-cabal-version: >= 1.6+cabal-version: >= 1.10 homepage: http://snapframework.com/-category: Web+bug-reports: https://github.com/snapframework/snap-server/issues+category: Web, Snap, IO-Streams extra-source-files: CONTRIBUTORS,- extra/fonts/DroidSerif-Bold.eot,- extra/fonts/DroidSerif-Bold.svg,- extra/fonts/DroidSerif-Bold.ttf,- extra/fonts/DroidSerif-Bold.woff,- extra/fonts/DroidSerif-BoldItalic.eot,- extra/fonts/DroidSerif-BoldItalic.svg,- extra/fonts/DroidSerif-BoldItalic.ttf,- extra/fonts/DroidSerif-BoldItalic.woff,- extra/fonts/DroidSerif-Italic.eot,- extra/fonts/DroidSerif-Italic.svg,- extra/fonts/DroidSerif-Italic.ttf,- extra/fonts/DroidSerif-Italic.woff,- extra/fonts/DroidSerif-Regular.eot,- extra/fonts/DroidSerif-Regular.svg,- extra/fonts/DroidSerif-Regular.ttf,- extra/fonts/DroidSerif-Regular.woff,- extra/haddock.css,- extra/hscolour.css,- extra/logo.gif,- haddock.sh, LICENSE, README.md, README.SNAP.md,- test/benchmark/Benchmark.hs,- test/benchmark/Snap/Internal/Http/Parser/Benchmark.hs,- test/benchmark/Snap/Internal/Http/Parser/Data.hs,- test/common/Paths_snap_server.hs,- test/common/Snap/Test/Common.hs,- test/common/Test/Common/TestHandler.hs,- test/common/Test/Common/Rot13.hs,- test/data/fileServe/foo.bin,- test/data/fileServe/foo.bin.bin.bin,- test/data/fileServe/foo.html,- test/data/fileServe/foo.txt,- test/pongserver/Main.hs,- test/runTestsAndCoverage.sh,- test/snap-server-testsuite.cabal,- test/suite/Data/Concurrent/HashMap/Tests.hs,- test/suite/Snap/Internal/Http/Parser/Tests.hs,- test/suite/Snap/Internal/Http/Server/Tests.hs,- test/suite/Test/Blackbox.hs,- test/suite/TestSuite.hs,- test/testserver/Main.hs,- test/testserver/static/hello.txt-+ test/bad_key.pem,+ test/cert.pem,+ test/dummy.txt,+ test/key.pem,+ testserver/static/hello.txt -Flag libev- Description: Use libev?- Default: False+tested-with:+ GHC==7.6.3,+ GHC==7.8.4,+ GHC==7.10.3,+ GHC==8.0.2,+ GHC==8.2.2,+ GHC==8.4.4,+ GHC==8.6.5,+ GHC==8.8.3,+ GHC==8.10.1 Flag portable Description: Compile in cross-platform mode. No platform-specific code or optimizations such as C routines will be used. Default: False -Flag gnutls- Description: Enable https support using the libgnutls library.+Flag openssl+ Description: Enable https support using the HsOpenSSL library. Default: False+ Manual: True +Flag build-pong+ Description: Build a server that just returns "PONG"? Normally useful only+ for benchmarks.+ Default: False+ Manual: True +Flag build-testserver+ Description: Build the blackbox testserver?+ Default: False+ Manual: True++Flag debug+ Description: Enable support for debugging.+ Default: False+ Manual: True+ Library- hs-source-dirs: src+ hs-source-dirs: src+ Default-language: Haskell2010 exposed-modules: Snap.Http.Server, Snap.Http.Server.Config,+ Snap.Http.Server.Types,+ Snap.Internal.Http.Server.Config,+ Snap.Internal.Http.Server.Types, System.FastLogger other-modules:- Data.Concurrent.HashMap,- Data.Concurrent.HashMap.Internal, Paths_snap_server,- Snap.Internal.Http.Parser,- Snap.Internal.Http.Server,+ Control.Concurrent.Extended,+ Snap.Internal.Http.Server.Address,+ Snap.Internal.Http.Server.Clock,+ Snap.Internal.Http.Server.Common, Snap.Internal.Http.Server.Date,- Snap.Internal.Http.Server.Backend,- Snap.Internal.Http.Server.ListenHelpers,- Snap.Internal.Http.Server.GnuTLS,- Snap.Internal.Http.Server.HttpPort,- Snap.Internal.Http.Server.TimeoutTable,- Snap.Internal.Http.Server.SimpleBackend,- Snap.Internal.Http.Server.LibevBackend+ Snap.Internal.Http.Server.Parser,+ Snap.Internal.Http.Server.Session,+ Snap.Internal.Http.Server.Socket,+ Snap.Internal.Http.Server.Thread,+ Snap.Internal.Http.Server.TimeoutManager,+ Snap.Internal.Http.Server.TLS build-depends:- array >= 0.2 && <0.4,- attoparsec >= 0.8.1 && < 0.9,- attoparsec-enumerator >= 0.2.0.1 && < 0.3,- base >= 4 && < 5,- binary >=0.5 && <0.6,+ attoparsec >= 0.12 && < 0.15,+ base >= 4.6 && < 5,+ blaze-builder >= 0.4 && < 0.5,+ bytestring >= 0.9.1 && < 0.12,+ case-insensitive >= 1.1 && < 1.3,+ clock >= 0.7.1 && < 0.9,+ containers >= 0.3 && < 0.7,+ filepath >= 1.1 && < 2.0,+ io-streams >= 1.3 && < 1.6,+ io-streams-haproxy >= 1.0 && < 1.1,+ lifted-base >= 0.1 && < 0.3,+ mtl >= 2.0 && < 2.4,+ network >= 2.3 && < 3.2,+ old-locale >= 1.0 && < 1.1,+ snap-core >= 1.0 && < 1.1,+ text >= 0.11 && < 2.1,+ time >= 1.0 && < 1.13,+ transformers >= 0.3 && < 0.7,+ unix-compat >= 0.2 && < 0.7,+ vector >= 0.7 && < 0.14++ other-extensions:+ BangPatterns,+ CPP,+ MagicHash,+ Rank2Types,+ OverloadedStrings,+ ScopedTypeVariables,+ DeriveDataTypeable,+ PackageImports,+ ViewPatterns,+ ForeignFunctionInterface,+ EmptyDataDecls,+ GeneralizedNewtypeDeriving++ if !impl(ghc >= 8.0)+ build-depends: semigroups >= 0.16 && < 0.19++ if !impl(ghc >= 7.8)+ build-depends: bytestring-builder >= 0.10.4 && < 0.11++ if flag(portable) || os(windows)+ cpp-options: -DPORTABLE+ else+ build-depends: unix < 2.9++ if flag(openssl)+ cpp-options: -DOPENSSL+ build-depends: HsOpenSSL >= 0.10.4 && < 0.12,+ openssl-streams >= 1.1 && < 1.3++ if os(linux) && !flag(portable)+ cpp-options: -DLINUX -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+ other-modules:+ System.SendFile,+ System.SendFile.Linux++-- Disabling sendfile() on OSX for now. See+--+-- https://github.com/snapframework/snap-core/issues/274 and+-- https://github.com/snapframework/snap-core/issues/91+--+ if os(darwin) && !flag(portable)+ cpp-options: -DHAS_UNIX_SOCKETS+ -- if os(darwin) && !flag(portable)+ -- cpp-options: -DOSX -DHAS_UNIX_SOCKETS++ if os(freebsd) && !flag(portable)+ cpp-options: -DFREEBSD -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+ other-modules:+ System.SendFile,+ System.SendFile.FreeBSD++ if impl(ghc >= 6.12.0)+ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -fno-warn-unused-do-bind+ else+ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields++ if flag(debug)+ cpp-options: -DLABEL_THREADS++Test-suite testsuite+ hs-source-dirs: src test+ Type: exitcode-stdio-1.0+ Main-is: TestSuite.hs+ Default-language: Haskell2010++ other-modules:+ Control.Concurrent.Extended,+ Paths_snap_server,+ Snap.Http.Server,+ Snap.Http.Server.Config,+ Snap.Http.Server.Types,+ Snap.Internal.Http.Server.Address,+ Snap.Internal.Http.Server.Clock,+ Snap.Internal.Http.Server.Common,+ Snap.Internal.Http.Server.Config,+ Snap.Internal.Http.Server.Date,+ Snap.Internal.Http.Server.Parser,+ Snap.Internal.Http.Server.Session,+ Snap.Internal.Http.Server.Socket,+ Snap.Internal.Http.Server.Thread,+ Snap.Internal.Http.Server.TimeoutManager,+ Snap.Internal.Http.Server.TLS+ Snap.Internal.Http.Server.Types,+ System.FastLogger,++ Snap.Internal.Http.Server.Address.Tests,+ Snap.Internal.Http.Server.Parser.Tests,+ Snap.Internal.Http.Server.Session.Tests,+ Snap.Internal.Http.Server.Socket.Tests,+ Snap.Internal.Http.Server.TimeoutManager.Tests,+ Snap.Test.Common,+ Test.Blackbox,+ Test.Common.Rot13,+ Test.Common.TestHandler++ build-depends:+ attoparsec,+ base,+ base16-bytestring >= 0.1 && < 1.1,+ blaze-builder, bytestring,- bytestring-nums,- bytestring-show >= 0.3.2 && < 0.4,- cereal >= 0.3 && < 0.4,+ case-insensitive,+ clock, containers,- directory-tree,- dlist >= 0.5 && < 0.6,- enumerator == 0.4.*,+ directory >= 1.1 && < 1.4, filepath,- MonadCatchIO-transformers >= 0.2.1 && < 0.3,- mtl == 2.0.*,- murmur-hash >= 0.1 && < 0.2,- network >= 2.3 && <2.4,+ io-streams,+ io-streams-haproxy,+ lifted-base,+ monad-control >= 1.0 && < 1.1,+ mtl,+ network, old-locale,- snap-core >= 0.3.1 && <0.4,- template-haskell,+ random >= 1.0 && < 1.3,+ snap-core,+ text,+ threads >= 0.5 && < 0.6, time, transformers,- utf8-string,- unix-compat == 0.2.*,- vector >= 0.7 && <0.8,- vector-algorithms >= 0.4 && <0.5,- PSQueue >= 1.1 && <1.2+ unix-compat,+ vector, + HUnit >= 1.2 && < 2,+ QuickCheck >= 2.3.0.2 && < 3,+ deepseq >= 1.3 && < 2,+ http-streams >= 0.7 && < 0.9,+ http-common >= 0.7 && < 0.9,+ parallel >= 3 && < 4,+ test-framework >= 0.8.0.3 && < 0.9,+ test-framework-hunit >= 0.2.7 && < 0.4,+ test-framework-quickcheck2 >= 0.2.12.1 && < 0.4++ other-extensions:+ BangPatterns,+ CPP,+ MagicHash,+ Rank2Types,+ OverloadedStrings,+ ScopedTypeVariables,+ DeriveDataTypeable,+ PackageImports,+ ViewPatterns,+ ForeignFunctionInterface,+ EmptyDataDecls,+ GeneralizedNewtypeDeriving++ if !impl(ghc >= 8.0)+ build-depends: semigroups++ if !impl(ghc >= 7.8)+ build-depends: bytestring-builder+ if flag(portable) || os(windows) cpp-options: -DPORTABLE else build-depends: unix - if flag(libev)- build-depends: hlibev >= 0.2.8 && < 0.3- cpp-options: -DLIBEV+ -- always label threads in testsuite+ cpp-options: -DLABEL_THREADS - if flag(gnutls)- extra-libraries: gnutls- cpp-options: -DGNUTLS- c-sources: src/Snap/Internal/Http/Server/gnutls_helpers.c+ if flag(openssl)+ cpp-options: -DOPENSSL+ build-depends: HsOpenSSL,+ openssl-streams if os(linux) && !flag(portable)- cpp-options: -DLINUX -DHAS_SENDFILE+ cpp-options: -DLINUX -DHAS_SENDFILE -DHAS_UNIX_SOCKETS other-modules: System.SendFile,- System.SendFile.Linux+ System.SendFile.Linux,+ System.SendFile.Tests+ c-sources: test/cbits/errno_util.c if os(darwin) && !flag(portable)- cpp-options: -DOSX -DHAS_SENDFILE+ cpp-options: -DHAS_UNIX_SOCKETS+-- if os(darwin) && !flag(portable)+-- cpp-options: -DOSX -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+-- other-modules:+-- System.SendFile,+-- System.SendFile.Darwin,+-- System.SendFile.Tests+-- c-sources: test/cbits/errno_util.c++ if os(freebsd) && !flag(portable)+ cpp-options: -DFREEBSD -DHAS_SENDFILE -DHAS_UNIX_SOCKETS other-modules: System.SendFile,- System.SendFile.Darwin+ System.SendFile.FreeBSD,+ System.SendFile.Tests+ c-sources: test/cbits/errno_util.c + cpp-options: -DTESTSUITE++ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields+ -fno-warn-unused-do-bind -threaded+++Benchmark benchmark+ type: exitcode-stdio-1.0+ hs-source-dirs: benchmark src+ main-is: Benchmark.hs+ default-language: Haskell2010++ other-modules:+ Snap.Internal.Http.Parser.Benchmark,+ Snap.Internal.Http.Parser.Data,+ Snap.Internal.Http.Server.Parser++ build-depends:+ attoparsec,+ base,+ blaze-builder,+ bytestring,+ bytestring-builder,+ criterion >= 0.6 && < 1.7,+ io-streams,+ io-streams-haproxy,+ snap-core,+ transformers,+ vector++ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields+ -fno-warn-unused-do-bind -rtsopts++ other-extensions:+ BangPatterns,+ CPP,+ MagicHash,+ Rank2Types,+ OverloadedStrings,+ ScopedTypeVariables,+ DeriveDataTypeable,+ PackageImports,+ ViewPatterns,+ ForeignFunctionInterface,+ EmptyDataDecls,+ GeneralizedNewtypeDeriving++Executable snap-test-pong-server+ hs-source-dirs: src pong+ main-is: Main.hs++ if !flag(build-pong)+ buildable: False++ default-language: Haskell2010++ other-modules:+ Control.Concurrent.Extended+ Paths_snap_server,+ Snap.Internal.Http.Server.Address,+ Snap.Internal.Http.Server.Clock,+ Snap.Internal.Http.Server.Common,+ Snap.Internal.Http.Server.Config,+ Snap.Internal.Http.Server.Date,+ Snap.Internal.Http.Server.Parser,+ Snap.Internal.Http.Server.Session,+ Snap.Internal.Http.Server.Socket,+ Snap.Internal.Http.Server.Thread,+ Snap.Internal.Http.Server.TimeoutManager,+ Snap.Internal.Http.Server.TLS,+ Snap.Internal.Http.Server.Types++ if flag(portable) || os(windows)+ cpp-options: -DPORTABLE+ else+ build-depends: unix++ if os(linux) && !flag(portable)+ cpp-options: -DLINUX -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+ other-modules:+ System.SendFile,+ System.SendFile.Linux++ if os(darwin) && !flag(portable)+ cpp-options: -DHAS_UNIX_SOCKETS+-- if os(darwin) && !flag(portable)+-- cpp-options: -DOSX -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+-- other-modules:+-- System.SendFile,+-- System.SendFile.Darwin+ if os(freebsd) && !flag(portable)- cpp-options: -DFREEBSD -DHAS_SENDFILE+ cpp-options: -DFREEBSD -DHAS_SENDFILE -DHAS_UNIX_SOCKETS other-modules: System.SendFile, System.SendFile.FreeBSD - ghc-prof-options: -prof -auto-all+ if flag(openssl)+ cpp-options: -DOPENSSL+ build-depends: HsOpenSSL,+ openssl-streams - if impl(ghc >= 6.12.0)- ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2 -fno-warn-unused-do-bind+ build-depends:+ attoparsec,+ base,+ blaze-builder,+ bytestring,+ bytestring-builder,+ case-insensitive,+ clock,+ containers,+ filepath,+ io-streams,+ io-streams-haproxy,+ lifted-base,+ mtl,+ network,+ old-locale,+ snap-core,+ text,+ time,+ unix-compat,+ vector++ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields+ -fno-warn-unused-do-bind -threaded -rtsopts++ other-extensions:+ BangPatterns,+ CPP,+ MagicHash,+ Rank2Types,+ OverloadedStrings,+ ScopedTypeVariables,+ DeriveDataTypeable,+ PackageImports,+ ViewPatterns,+ ForeignFunctionInterface,+ EmptyDataDecls,+ GeneralizedNewtypeDeriving+++Executable snap-test-server+ hs-source-dirs: src testserver test+ main-is: Main.hs++ if !flag(build-testserver)+ buildable: False++ if flag(openssl)+ cpp-options: -DOPENSSL+ build-depends: HsOpenSSL,+ openssl-streams++ default-language: Haskell2010++ other-modules:+ Control.Concurrent.Extended,+ Paths_snap_server,+ Snap.Http.Server,+ Snap.Http.Server.Config,+ Snap.Http.Server.Types,+ Snap.Internal.Http.Server.Address,+ Snap.Internal.Http.Server.Clock,+ Snap.Internal.Http.Server.Common,+ Snap.Internal.Http.Server.Config,+ Snap.Internal.Http.Server.Date,+ Snap.Internal.Http.Server.Parser,+ Snap.Internal.Http.Server.Session,+ Snap.Internal.Http.Server.Socket,+ Snap.Internal.Http.Server.TLS,+ Snap.Internal.Http.Server.Thread,+ Snap.Internal.Http.Server.TimeoutManager,+ Snap.Internal.Http.Server.Types,+ System.FastLogger,+ Test.Common.Rot13,+ Test.Common.TestHandler++ if flag(portable) || os(windows)+ cpp-options: -DPORTABLE else- ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2+ build-depends: unix + if os(linux) && !flag(portable)+ cpp-options: -DLINUX -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+ other-modules:+ System.SendFile,+ System.SendFile.Linux + if os(darwin) && !flag(portable)+ cpp-options: -DHAS_UNIX_SOCKETS+ -- if os(darwin) && !flag(portable)+ -- cpp-options: -DOSX -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+ -- other-modules:+ -- System.SendFile,+ -- System.SendFile.Darwin++ if os(freebsd) && !flag(portable)+ cpp-options: -DFREEBSD -DHAS_SENDFILE -DHAS_UNIX_SOCKETS+ other-modules:+ System.SendFile,+ System.SendFile.FreeBSD++ build-depends:+ attoparsec,+ base,+ blaze-builder,+ bytestring,+ bytestring-builder,+ case-insensitive,+ clock,+ containers,+ directory,+ filepath,+ io-streams,+ io-streams-haproxy,+ lifted-base,+ mtl,+ network,+ old-locale,+ snap-core,+ text,+ time,+ transformers,+ unix-compat,+ vector++ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields+ -fno-warn-unused-do-bind -threaded -rtsopts++ other-extensions:+ BangPatterns,+ CPP,+ MagicHash,+ Rank2Types,+ OverloadedStrings,+ ScopedTypeVariables,+ DeriveDataTypeable,+ PackageImports,+ ViewPatterns,+ ForeignFunctionInterface,+ EmptyDataDecls,+ GeneralizedNewtypeDeriving+ source-repository head type: git- location: http://git.snapframework.com/snap-server.git+ location: git://github.com/snapframework/snap-server.git
+ src/Control/Concurrent/Extended.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE UnboxedTuples #-}++-- | Handy functions that should really be merged into Control.Concurrent+-- itself.+module Control.Concurrent.Extended+ ( forkIOLabeledWithUnmaskBs+ , forkOnLabeledWithUnmaskBs+ ) where++------------------------------------------------------------------------------+import Control.Exception (mask_)+import qualified Data.ByteString as B+import GHC.Conc.Sync (ThreadId (..))++#ifdef LABEL_THREADS+import Control.Concurrent (forkIOWithUnmask, forkOnWithUnmask,+ myThreadId)+#if MIN_VERSION_base(4,18,0)+import qualified Data.ByteString.Char8 as C8+import GHC.Conc (labelThread)+#else+import GHC.Base (labelThread#)+#endif+import Foreign.C.String (CString)+import GHC.IO (IO (..))+import GHC.Ptr (Ptr (..))+#else+import Control.Concurrent (forkIOWithUnmask, forkOnWithUnmask)+#endif++------------------------------------------------------------------------------+-- | Sparks off a new thread using 'forkIOWithUnmask' to run the given IO+-- computation, but first labels the thread with the given label (using+-- 'labelThreadBs').+--+-- The implementation makes sure that asynchronous exceptions are masked until+-- the given computation is executed. This ensures the thread will always be+-- labeled which guarantees you can always easily find it in the GHC event log.+--+-- Like 'forkIOWithUnmask', the given computation is given a function to unmask+-- asynchronous exceptions. See the documentation of that function for the+-- motivation.+--+-- Returns the 'ThreadId' of the newly created thread.+forkIOLabeledWithUnmaskBs :: B.ByteString -- ^ Latin-1 encoded label+ -> ((forall a. IO a -> IO a) -> IO ())+ -> IO ThreadId+forkIOLabeledWithUnmaskBs label m =+ mask_ $ forkIOWithUnmask $ \unmask -> do+ !_ <- labelMe label+ m unmask+++------------------------------------------------------------------------------+-- | Like 'forkIOLabeledWithUnmaskBs', but lets you specify on which capability+-- (think CPU) the thread should run.+forkOnLabeledWithUnmaskBs :: B.ByteString -- ^ Latin-1 encoded label+ -> Int -- ^ Capability+ -> ((forall a. IO a -> IO a) -> IO ())+ -> IO ThreadId+forkOnLabeledWithUnmaskBs label cap m =+ mask_ $ forkOnWithUnmask cap $ \unmask -> do+ !_ <- labelMe label+ m unmask+++------------------------------------------------------------------------------+-- | Label the current thread.+{-# INLINE labelMe #-}+labelMe :: B.ByteString -> IO ()+#if defined(LABEL_THREADS)+labelMe label = do+ tid <- myThreadId+ labelThreadBs tid label+++------------------------------------------------------------------------------+-- | Like 'labelThread' but uses a Latin-1 encoded 'ByteString' instead of a+-- 'String'.+labelThreadBs :: ThreadId -> B.ByteString -> IO ()+#if MIN_VERSION_base(4,18,0)+labelThreadBs tid =+ -- The 'labelThread#' signature changed: it now requires a UTF-8 encoded+ -- ByteArray#.+ labelThread tid . C8.unpack+#else+labelThreadBs tid bs = B.useAsCString bs $ labelThreadCString tid+++------------------------------------------------------------------------------+-- | Like 'labelThread' but uses a 'CString' instead of a 'String'+labelThreadCString :: ThreadId -> CString -> IO ()+labelThreadCString (ThreadId t) (Ptr p) =+ IO $ \s -> case labelThread# t p s of+ s1 -> (# s1, () #)+#endif++#elif defined(TESTSUITE)+labelMe !_ = return $! ()+#else+labelMe _label = return $! ()+#endif
− src/Data/Concurrent/HashMap.hs
@@ -1,237 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TemplateHaskell #-}--module Data.Concurrent.HashMap- ( HashMap- , new- , new'- , null- , insert- , delete- , lookup- , update- , fromList- , toList- , hashString- , hashBS- , hashInt- , nextHighestPowerOf2 ) where----------------------------------------------------------------------------------import Control.Concurrent.MVar-import Control.Monad-import Data.Bits-import qualified Data.ByteString as B-import qualified Data.Digest.Murmur32 as Murmur-import qualified Data.Digest.Murmur64 as Murmur-import Data.IntMap (IntMap)-import qualified Data.IntMap as IM-import Data.Maybe-import qualified Data.Vector as V-import Data.Vector (Vector)-import GHC.Conc (numCapabilities)-import Prelude hiding (lookup, null)-import qualified Prelude--#if __GLASGOW_HASKELL__ >= 503-import GHC.Exts ( Word(..), Int(..), shiftRL# )-#else-import Data.Word-#endif--import Data.Concurrent.HashMap.Internal---hashString :: String -> Word-hashString = $(whichHash [| Murmur.asWord32 . Murmur.hash32 |]- [| Murmur.asWord64 . Murmur.hash64 |])-{-# INLINE hashString #-}---hashInt :: Int -> Word-hashInt = $(whichHash [| Murmur.asWord32 . Murmur.hash32 |]- [| Murmur.asWord64 . Murmur.hash64 |])-{-# INLINE hashInt #-}---hashBS :: B.ByteString -> Word-hashBS =- $(let h32 = [| \s -> s `seq`- Murmur.asWord32 $- B.foldl' (\h c -> h `seq` c `seq`- Murmur.hash32AddInt (fromEnum c) h)- (Murmur.hash32 ([] :: [Int]))- s- |]- h64 = [| \s -> s `seq`- Murmur.asWord64 $- B.foldl' (\h c -> h `seq` c `seq`- Murmur.hash64AddInt (fromEnum c) h)- (Murmur.hash64 ([] :: [Int]))- s- |]- in whichHash h32 h64)-{-# INLINE hashBS #-}---data HashMap k v = HM {- _hash :: !(k -> Word)- , _hashToBucket :: !(Word -> Word)- , _maps :: !(Vector (MVar (Submap k v)))-}----null :: HashMap k v -> IO Bool-null ht = liftM V.and $ V.mapM f $ _maps ht-- where- f mv = withMVar mv (return . IM.null)---new' :: Eq k =>- Int -- ^ number of locks to use- -> (k -> Word) -- ^ hash function- -> IO (HashMap k v)-new' numLocks hashFunc = do- vector <- V.replicateM (fromEnum n) (newMVar IM.empty)- return $! HM hf bh vector-- where- hf !x = hashFunc x- bh !x = x .&. (n-1)- !n = nextHighestPowerOf2 $ toEnum numLocks---new :: Eq k =>- (k -> Word) -- ^ hash function- -> IO (HashMap k v)-new = new' defaultNumberOfLocks---insert :: k -> v -> HashMap k v -> IO ()-insert key value ht =- modifyMVar_ submap $ \m ->- return $! insSubmap hashcode key value m-- where- hashcode = _hash ht key- bucket = _hashToBucket ht hashcode- submap = V.unsafeIndex (_maps ht) (fromEnum bucket)---delete :: (Eq k) => k -> HashMap k v -> IO ()-delete key ht =- modifyMVar_ submap $ \m ->- return $! delSubmap hashcode key m- where- hashcode = _hash ht key- bucket = _hashToBucket ht hashcode- submap = V.unsafeIndex (_maps ht) (fromEnum bucket)---lookup :: (Eq k) => k -> HashMap k v -> IO (Maybe v)-lookup key ht =- withMVar submap $ \m ->- return $! lookupSubmap hashcode key m- where- hashcode = _hash ht key- bucket = _hashToBucket ht hashcode- submap = V.unsafeIndex (_maps ht) (fromEnum bucket)---update :: (Eq k) => k -> v -> HashMap k v -> IO Bool-update key value ht =- modifyMVar submap $ \m ->- return $! updateSubmap hashcode key value m- where- hashcode = _hash ht key- bucket = _hashToBucket ht hashcode- submap = V.unsafeIndex (_maps ht) (fromEnum bucket)---toList :: HashMap k v -> IO [(k,v)]-toList ht = liftM (concat . V.toList) $ V.mapM f $ _maps ht- where- f m = withMVar m $ \sm -> return $ concat $ IM.elems sm---fromList :: (Eq k) => (k -> Word) -> [(k,v)] -> IO (HashMap k v)-fromList hf xs = do- ht <- new hf- mapM_ (\(k,v) -> insert k v ht) xs- return $! ht------------------------------------------------------------------------------------ helper functions----------------------------------------------------------------------------------- nicked this technique from Data.IntMap--shiftRL :: Word -> Int -> Word-#if __GLASGOW_HASKELL__-{--------------------------------------------------------------------- GHC: use unboxing to get @shiftRL@ inlined.---------------------------------------------------------------------}-shiftRL (W# x) (I# i)- = W# (shiftRL# x i)-#else-shiftRL x i = shiftR x i-#endif---type Submap k v = IntMap [(k,v)]---nextHighestPowerOf2 :: Word -> Word-nextHighestPowerOf2 w = highestBitMask (w-1) + 1---highestBitMask :: Word -> Word-highestBitMask !x0 = case (x0 .|. shiftRL x0 1) of- x1 -> case (x1 .|. shiftRL x1 2) of- x2 -> case (x2 .|. shiftRL x2 4) of- x3 -> case (x3 .|. shiftRL x3 8) of- x4 -> case (x4 .|. shiftRL x4 16) of- x5 -> x5 .|. shiftRL x5 32----insSubmap :: Word -> k -> v -> Submap k v -> Submap k v-insSubmap hashcode key value m = let !x = f m in x- where- f = IM.insertWith (++) (fromIntegral hashcode) [(key,value)]---delSubmap :: (Eq k) => Word -> k -> Submap k v -> Submap k v-delSubmap hashcode key m =- let !z = IM.update f (fromIntegral hashcode) m in z-- where- f l = let l' = del l in if Prelude.null l' then Nothing else Just l'-- del = filter ((/= key) . fst)---lookupSubmap :: (Eq k) => Word -> k -> Submap k v -> Maybe v-lookupSubmap hashcode key m = maybe Nothing (Prelude.lookup key) mbBucket- where- mbBucket = IM.lookup (fromIntegral hashcode) m---updateSubmap :: (Eq k) => Word -> k -> v -> Submap k v -> (Submap k v, Bool)-updateSubmap hashcode key value m = (m'', b)- where- oldV = lookupSubmap hashcode key m- m' = maybe m (const $ delSubmap hashcode key m) oldV- m'' = insSubmap hashcode key value m'- b = isJust oldV---defaultNumberOfLocks :: Int-defaultNumberOfLocks = 8 * numCapabilities
− src/Data/Concurrent/HashMap/Internal.hs
@@ -1,16 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE TemplateHaskell #-}--module Data.Concurrent.HashMap.Internal where--import Data.Bits-import Data.Word-import Language.Haskell.TH---whichHash :: ExpQ -> ExpQ -> Q Exp-whichHash as32 as64 = if bitSize (undefined :: Word) == 32- then [| \x -> fromIntegral $ $as32 x |]- else [| \x -> fromIntegral $ $as64 x |]
src/Snap/Http/Server.hs view
@@ -1,115 +1,312 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--{-|--The Snap HTTP server is a high performance, epoll-enabled, iteratee-based web-server library written in Haskell. Together with the @snap-core@ library upon-which it depends, it provides a clean and efficient Haskell programming-interface to the HTTP protocol.---}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-} +------------------------------------------------------------------------------+-- | The Snap HTTP server is a high performance web server library written in+-- Haskell. Together with the @snap-core@ library upon which it depends, it+-- provides a clean and efficient Haskell programming interface to the HTTP+-- protocol.+-- module Snap.Http.Server ( simpleHttpServe , httpServe , quickHttpServe , snapServerVersion , setUnicodeLocale+ , rawHttpServe , module Snap.Http.Server.Config ) where -import Control.Monad-import Control.Monad.CatchIO-import Data.ByteString (ByteString)-import Data.Char-import Data.List-import Data.Maybe-import Prelude hiding (catch)-import Snap.Http.Server.Config-import qualified Snap.Internal.Http.Server as Int-import Snap.Types-import Snap.Util.GZip+------------------------------------------------------------------------------+import Control.Applicative ((<$>), (<|>))+import Control.Concurrent (killThread, newEmptyMVar, newMVar, putMVar, readMVar, withMVar)+import Control.Concurrent.Extended (forkIOLabeledWithUnmaskBs)+import Control.Exception (SomeException, bracket, catch, finally, mask, mask_)+import qualified Control.Exception.Lifted as L+import Control.Monad (liftM, when)+import Control.Monad.Trans (MonadIO)+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import Data.Maybe (catMaybes, fromJust, fromMaybe)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Version (showVersion)+import Data.Word (Word64)+import Network.Socket (Socket, close)+import Prelude (Bool (..), Eq (..), IO, Maybe (..), Monad (..), Show (..), String, const, flip, fst, id, mapM, mapM_, maybe, snd, unzip3, zip, ($), ($!), (++), (.))+import System.IO (hFlush, hPutStrLn, stderr) #ifndef PORTABLE import System.Posix.Env #endif-import System.IO+------------------------------------------------------------------------------+import Data.ByteString.Builder (Builder, toLazyByteString)+------------------------------------------------------------------------------+import qualified Paths_snap_server as V+import Snap.Core (MonadSnap (..), Request, Response, Snap, rqClientAddr, rqHeaders, rqMethod, rqURI, rqVersion, rspStatus)+-- Don't use explicit imports for Snap.Http.Server.Config because we're+-- re-exporting everything.+import Snap.Http.Server.Config+import qualified Snap.Http.Server.Types as Ty+import Snap.Internal.Debug (debug)+import Snap.Internal.Http.Server.Config (ProxyType (..), emptyStartupInfo, setStartupConfig, setStartupSockets)+import Snap.Internal.Http.Server.Session (httpAcceptLoop, snapToServerHandler)+import qualified Snap.Internal.Http.Server.Socket as Sock+import qualified Snap.Internal.Http.Server.TLS as TLS+import Snap.Internal.Http.Server.Types (AcceptFunc, ServerConfig, ServerHandler)+import qualified Snap.Types.Headers as H+import Snap.Util.GZip (withCompression)+import Snap.Util.Proxy (behindProxy)+import qualified Snap.Util.Proxy as Proxy+import System.FastLogger (combinedLogEntry, logMsg, newLoggerWithCustomErrorFunction, stopLogger, timestampedLogEntry) ------------------------------------------------------------------------------ -- | A short string describing the Snap server version snapServerVersion :: ByteString-snapServerVersion = Int.snapServerVersion+snapServerVersion = S.pack $! showVersion V.version --------------------------------------------------------------------------------- | Starts serving HTTP requests using the given handler. Uses only the basic--- settings from the given config; error handling and compression are ignored.--- This function never returns; to shut down the HTTP server, kill the--- controlling thread.+rawHttpServe :: ServerHandler s -- ^ server handler+ -> ServerConfig s -- ^ server config+ -> [AcceptFunc] -- ^ listening server backends+ -> IO ()+rawHttpServe h cfg loops = do+ mvars <- mapM (const newEmptyMVar) loops+ mask $ \restore -> bracket (mapM runLoop $ mvars `zip` loops)+ (\mvTids -> do+ mapM_ (killThread . snd) mvTids+ mapM_ (readMVar . fst) mvTids)+ (const $ restore $ mapM_ readMVar mvars)+ where+ -- parents and children have a mutual suicide pact+ runLoop (mvar, loop) = do+ tid <- forkIOLabeledWithUnmaskBs+ "snap-server http master thread" $+ \r -> (r $ httpAcceptLoop h cfg loop) `finally` putMVar mvar ()+ return (mvar, tid)++------------------------------------------------------------------------------+-- | Starts serving HTTP requests using the given handler. This function never+-- returns; to shut down the HTTP server, kill the controlling thread.+--+-- This function is like 'httpServe' except it doesn't setup compression,+-- reverse proxy address translation (via 'Snap.Util.Proxy.behindProxy'), or+-- the error handler; this allows it to be used from 'MonadSnap'. simpleHttpServe :: MonadSnap m => Config m a -> Snap () -> IO () simpleHttpServe config handler = do- setUnicodeLocale $ fromJust $ getLocale conf- Int.httpServe (map listenToInt $ getListen conf)- (fmap backendToInt $ getBackend conf)- (fromJust $ getHostname conf)- (fromJust $ getAccessLog conf)- (fromJust $ getErrorLog conf)- (runSnap handler)+ conf <- completeConfig config+ let output = when (fromJust $ getVerbose conf) . hPutStrLn stderr+ (descrs, sockets, afuncs) <- unzip3 <$> listeners conf+ mapM_ (output . ("Listening on " ++) . S.unpack) descrs++ go conf sockets afuncs `finally` (mask_ $ do+ output "\nShutting down.."+ mapM_ (eatException . close) sockets)+ where- conf = completeConfig config- listenToInt (ListenHttp b p) = Int.HttpPort b p- listenToInt (ListenHttps b p c k) = Int.HttpsPort b p c k- backendToInt ConfigSimpleBackend = Int.EventLoopSimple- backendToInt ConfigLibEvBackend = Int.EventLoopLibEv+ eatException :: IO a -> IO ()+ eatException act =+ let r0 = return $! ()+ in (act >> r0) `catch` \(_::SomeException) -> r0 + --------------------------------------------------------------------------+ -- FIXME: this logging code *sucks*+ --------------------------------------------------------------------------+ debugE :: (MonadIO m) => ByteString -> m ()+ debugE s = debug $ "Error: " ++ S.unpack s ++ --------------------------------------------------------------------------+ logE :: Maybe (ByteString -> IO ()) -> Builder -> IO ()+ logE elog b = let x = S.concat $ L.toChunks $ toLazyByteString b+ in (maybe debugE (\l s -> debugE s >> logE' l s) elog) x++ --------------------------------------------------------------------------+ logE' :: (ByteString -> IO ()) -> ByteString -> IO ()+ logE' logger s = (timestampedLogEntry s) >>= logger++ --------------------------------------------------------------------------+ logA :: Maybe (ByteString -> IO ())+ -> Request+ -> Response+ -> Word64+ -> IO ()+ logA alog = maybe (\_ _ _ -> return $! ()) logA' alog++ --------------------------------------------------------------------------+ logA' logger req rsp cl = do+ let hdrs = rqHeaders req+ let host = rqClientAddr req+ let user = Nothing -- TODO we don't do authentication yet+ let (v, v') = rqVersion req+ let ver = S.concat [ "HTTP/", bshow v, ".", bshow v' ]+ let method = bshow (rqMethod req)+ let reql = S.intercalate " " [ method, rqURI req, ver ]+ let status = rspStatus rsp+ let referer = H.lookup "referer" hdrs+ let userAgent = fromMaybe "-" $ H.lookup "user-agent" hdrs++ msg <- combinedLogEntry host user reql status cl referer userAgent+ logger msg++ --------------------------------------------------------------------------+ go conf sockets afuncs = do+ let tout = fromMaybe 60 $ getDefaultTimeout conf+ let shandler = snapToServerHandler handler++ setUnicodeLocale $ fromJust $ getLocale conf++ withLoggers (fromJust $ getAccessLog conf)+ (fromJust $ getErrorLog conf) $ \(alog, elog) -> do+ let scfg = Ty.setDefaultTimeout tout .+ Ty.setLocalHostname (fromJust $ getHostname conf) .+ Ty.setLogAccess (logA alog) .+ Ty.setLogError (logE elog) $+ Ty.emptyServerConfig+ maybe (return $! ())+ ($ mkStartupInfo sockets conf)+ (getStartupHook conf)+ rawHttpServe shandler scfg afuncs++ --------------------------------------------------------------------------+ mkStartupInfo sockets conf =+ setStartupSockets sockets $+ setStartupConfig conf emptyStartupInfo++ --------------------------------------------------------------------------+ maybeSpawnLogger f (ConfigFileLog fp) =+ liftM Just $ newLoggerWithCustomErrorFunction f fp+ maybeSpawnLogger _ _ = return Nothing++ --------------------------------------------------------------------------+ maybeIoLog (ConfigIoLog a) = Just a+ maybeIoLog _ = Nothing++ --------------------------------------------------------------------------+ withLoggers afp efp act =+ bracket (do mvar <- newMVar ()+ let f s = withMVar mvar+ (const $ S.hPutStr stderr s >> hFlush stderr)+ alog <- maybeSpawnLogger f afp+ elog <- maybeSpawnLogger f efp+ return (alog, elog))+ (\(alog, elog) -> do+ maybe (return ()) stopLogger alog+ maybe (return ()) stopLogger elog)+ (\(alog, elog) -> act ( liftM logMsg alog <|> maybeIoLog afp+ , liftM logMsg elog <|> maybeIoLog efp))+{-# INLINE simpleHttpServe #-}++ ------------------------------------------------------------------------------+listeners :: Config m a -> IO [(ByteString, Socket, AcceptFunc)]+listeners conf = TLS.withTLS $ do+ let fs = catMaybes [httpListener, httpsListener, unixListener]+ mapM (\(str, mkAfunc) -> do (sock, afunc) <- mkAfunc+ return $! (str, sock, afunc)) fs+ where+ httpsListener = do+ b <- getSSLBind conf+ p <- getSSLPort conf+ cert <- getSSLCert conf+ chainCert <- getSSLChainCert conf+ key <- getSSLKey conf+ return (S.concat [ "https://"+ , b+ , ":"+ , bshow p ],+ do (sock, ctx) <- TLS.bindHttps b p cert chainCert key+ return (sock, TLS.httpsAcceptFunc sock ctx)+ )+ httpListener = do+ p <- getPort conf+ b <- getBind conf+ return (S.concat [ "http://"+ , b+ , ":"+ , bshow p ],+ do sock <- Sock.bindSocket b p+ if getProxyType conf == Just HaProxy+ then return (sock, Sock.haProxyAcceptFunc sock)+ else return (sock, Sock.httpAcceptFunc sock))+ unixListener = do+ path <- getUnixSocket conf+ let accessMode = getUnixSocketAccessMode conf+ return (T.encodeUtf8 . T.pack $ "unix:" ++ path,+ do sock <- Sock.bindUnixSocket accessMode path+ return (sock, Sock.httpAcceptFunc sock))+++------------------------------------------------------------------------------ -- | Starts serving HTTP requests using the given handler, with settings from -- the 'Config' passed in. This function never returns; to shut down the HTTP -- server, kill the controlling thread.-httpServe :: Config Snap () -> Snap () -> IO ()-httpServe config handler = do- mapM_ (output . ("Listening on "++) . show) $ getListen conf- serve handler `finally` output "\nShutting down..."+httpServe :: Config Snap a -> Snap () -> IO ()+httpServe config handler0 = do+ conf <- completeConfig config+ let !handler = chooseProxy conf+ let serve = compress conf . catch500 conf $ handler+ simpleHttpServe conf serve+ where- conf = completeConfig config- output = when (fromJust $ getVerbose conf) . hPutStrLn stderr- serve = simpleHttpServe config . compress . catch500- catch500 = flip catch $ fromJust $ getErrorHandler conf- compress = if fromJust $ getCompression conf then withCompression else id+ chooseProxy conf = maybe handler0+ (\ptype -> pickProxy ptype handler0)+ (getProxyType conf) + pickProxy NoProxy = id+ pickProxy HaProxy = id -- we handle this case elsewhere+ pickProxy X_Forwarded_For = behindProxy Proxy.X_Forwarded_For + ------------------------------------------------------------------------------+catch500 :: MonadSnap m => Config m a -> m () -> m ()+catch500 conf = flip L.catch $ fromJust $ getErrorHandler conf+++------------------------------------------------------------------------------+compress :: MonadSnap m => Config m a -> m () -> m ()+compress conf = if fromJust $ getCompression conf then withCompression else id+++------------------------------------------------------------------------------ -- | Starts serving HTTP using the given handler. The configuration is read -- from the options given on the command-line, as returned by -- 'commandLineConfig'. This function never returns; to shut down the HTTP -- server, kill the controlling thread. quickHttpServe :: Snap () -> IO ()-quickHttpServe m = commandLineConfig emptyConfig >>= \c -> httpServe c m+quickHttpServe handler = do+ conf <- commandLineConfig defaultConfig+ httpServe conf handler ------------------------------------------------------------------------------ -- | Given a string like \"en_US\", this sets the locale to \"en_US.UTF-8\". -- This doesn't work on Windows. setUnicodeLocale :: String -> IO ()-setUnicodeLocale lang = #ifndef PORTABLE- mapM_ (\k -> setEnv k (lang ++ ".UTF-8") True)- [ "LANG"- , "LC_CTYPE"- , "LC_NUMERIC"- , "LC_TIME"- , "LC_COLLATE"- , "LC_MONETARY"- , "LC_MESSAGES"- , "LC_PAPER"- , "LC_NAME"- , "LC_ADDRESS"- , "LC_TELEPHONE"- , "LC_MEASUREMENT"- , "LC_IDENTIFICATION"- , "LC_ALL" ]+setUnicodeLocale lang = mapM_ (\k -> setEnv k (lang ++ ".UTF-8") True)+ [ "LANG"+ , "LC_CTYPE"+ , "LC_NUMERIC"+ , "LC_TIME"+ , "LC_COLLATE"+ , "LC_MONETARY"+ , "LC_MESSAGES"+ , "LC_PAPER"+ , "LC_NAME"+ , "LC_ADDRESS"+ , "LC_TELEPHONE"+ , "LC_MEASUREMENT"+ , "LC_IDENTIFICATION"+ , "LC_ALL" ] #else- return ()+setUnicodeLocale = const $ return () #endif++------------------------------------------------------------------------------+bshow :: (Show a) => a -> ByteString+bshow = S.pack . show
src/Snap/Http/Server/Config.hs view
@@ -1,518 +1,93 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--{-|--This module exports the 'Config' datatype which represents partially-specified-configurations of \"serve\" functions which run 'Snap' actions in 'IO'.---}-+------------------------------------------------------------------------------+-- | This module exports the 'Config' datatype, which you can use to configure+-- the Snap HTTP server.+-- module Snap.Http.Server.Config ( Config- , ConfigListen(..)- , ConfigBackend(..)+ , ConfigLog(..)+ , ProxyType+ , emptyConfig , defaultConfig- , completeConfig , commandLineConfig+ , extendedCommandLineConfig+ , completeConfig - , getHostname- , getListen+ , optDescrs+ , fmapOpt+ , getAccessLog- , getErrorLog- , getLocale- , getBackend+ , getBind , getCompression- , getVerbose+ , getDefaultTimeout , getErrorHandler+ , getErrorLog+ , getHostname+ , getLocale , getOther+ , getPort+ , getProxyType+ , getSSLBind+ , getSSLCert+ , getSSLKey+ , getSSLChainCert+ , getSSLPort+ , getVerbose+ , getStartupHook+ , getUnixSocket+ , getUnixSocketAccessMode - , setHostname- , addListen , setAccessLog- , setErrorLog- , setLocale- , setBackend+ , setBind , setCompression- , setVerbose+ , setDefaultTimeout , setErrorHandler+ , setErrorLog+ , setHostname+ , setLocale , setOther- ) where--import Control.Exception (SomeException)-import Control.Monad-import qualified Data.ByteString.UTF8 as U-import qualified Data.ByteString.Char8 as B-import Data.ByteString (ByteString)-import Data.Char-import Data.List-import Data.Monoid-import Prelude hiding (catch)-import Snap.Types-import Snap.Iteratee ((>==>), enumBS)-import System.Console.GetOpt-import System.Environment hiding (getEnv)-#ifndef PORTABLE-import System.Posix.Env-#endif-import System.Exit-import System.IO----------------------------------------------------------------------------------- | A data type to store the bind address and port to listen on.------ For SSL support, it also stores the path to the certificate in PEM format--- and the path to the private key in PEM format-data ConfigListen = ListenHttp ByteString Int- | ListenHttps ByteString Int FilePath FilePath---instance Show ConfigListen where- show (ListenHttp b p) = "http(" ++ show b ++ ":" ++ show p ++ ")"- show (ListenHttps b p c k) = "https(" ++ show b ++ ":" ++ show p ++- ", cert = " ++ show c ++- ", key = " ++ show k ++ ")"------------------------------------------------------------------------------------ | A data type to record which backend event loop should be used when--- serving data.-data ConfigBackend = ConfigSimpleBackend- | ConfigLibEvBackend- deriving (Eq,Show)------------------------------------------------------------------------------------ | A record type which represents partial configurations (for 'httpServe')--- by wrapping all of its fields in a 'Maybe'. Values of this type are usually--- constructed via its 'Monoid' instance by doing something like:------ > setPort 9000 mempty------ Any fields which are unspecified in the 'Config' passed to 'httpServe' (and--- this is the norm) are filled in with default values from 'defaultConfig'.-data MonadSnap m => Config m a = Config- { hostname :: Maybe ByteString- -- ^ The name of the server- , listen :: [ConfigListen]- -- ^ The local interfaces to listen on- , accessLog :: Maybe (Maybe FilePath)- -- ^ The path to the access log- , errorLog :: Maybe (Maybe FilePath)- -- ^ The path to the error log- , locale :: Maybe String- -- ^ The locale to use- , backend :: Maybe ConfigBackend- -- ^ The backend to use- , compression :: Maybe Bool- -- ^ Whether to use compression- , verbose :: Maybe Bool- -- ^ Whether to write server status updates to stderr- , errorHandler :: Maybe (SomeException -> m ())- -- ^ A MonadSnap action to handle 500 errors- , other :: Maybe a- -- ^ This is for any other state needed to initialize a custom server- }----------------------------------------------------------------------------------instance MonadSnap m => Show (Config m a) where- show c = "Config {" ++ concat (intersperse ", " $ filter (/="") $ map ($c)- [ showM "hostname" . hostname- , showL "listen" . listen- , showM "accessLog" . accessLog- , showM "errorLog" . errorLog- , showM "locale" . locale- , showM "backend" . backend- , showM "compression" . compression- , showM "verbose" . verbose- , showM "errorHandler" . fmap (const ()) . errorHandler- ]) ++ "}"- where- showM s = maybe "" ((++) (s ++ " = ") . show)- showL s l = s ++ " = " ++ show l------------------------------------------------------------------------------------ | Returns a completely empty 'Config'. Equivalent to 'mempty' from--- 'Config''s 'Monoid' instance.-emptyConfig :: MonadSnap m => Config m a-emptyConfig = mempty----------------------------------------------------------------------------------instance MonadSnap m => Monoid (Config m a) where- mempty = Config- { hostname = Nothing- , listen = []- , accessLog = Nothing- , errorLog = Nothing- , locale = Nothing- , backend = Nothing- , compression = Nothing- , verbose = Nothing- , errorHandler = Nothing- , other = Nothing- }-- a `mappend` b = Config- { hostname = (hostname b) `mplus` (hostname a)- , listen = (listen b) ++ (listen a)- , accessLog = (accessLog b) `mplus` (accessLog a)- , errorLog = (errorLog b) `mplus` (errorLog a)- , locale = (locale b) `mplus` (locale a)- , backend = (backend b) `mplus` (backend a)- , compression = (compression b) `mplus` (compression a)- , verbose = (verbose b) `mplus` (verbose a)- , errorHandler = (errorHandler b) `mplus` (errorHandler a)- , other = (other b) `mplus` (other a)- }------------------------------------------------------------------------------------ | These are the default values for all the fields in 'Config'.------ > hostname = "localhost"--- > listen = []--- > accessLog = "log/access.log"--- > errorLog = "log/error.log"--- > locale = "en_US"--- > backend = Nothing (the backend is selected based on compile options)--- > compression = True--- > verbose = True--- > errorHandler = prints the error message----defaultConfig :: MonadSnap m => Config m a-defaultConfig = Config- { hostname = Just "localhost"- , listen = []- , accessLog = Just $ Just "log/access.log"- , errorLog = Just $ Just "log/error.log"- , locale = Just "en_US"- , backend = Nothing- , compression = Just True- , verbose = Just True- , errorHandler = Just $ \e -> do- let err = U.fromString $ show e- msg = mappend "A web handler threw an exception. Details:\n" err- finishWith $ setContentType "text/plain; charset=utf-8"- . setContentLength (fromIntegral $ B.length msg)- . setResponseStatus 500 "Internal Server Error"- . modifyResponseBody (>==> enumBS msg)- $ emptyResponse- , other = Nothing- }------------------------------------------------------------------------------------ | Completes a partial 'Config' by filling in the unspecified values with--- the default values from 'defaultConfig'. Also, if no listeners are--- specified, adds a http listener on 0.0.0.0:8000-completeConfig :: MonadSnap m => Config m a -> Config m a-completeConfig c = case listen c' of- [] -> addListen (ListenHttp "0.0.0.0" 8000) c'- _ -> c'- where c' = mappend defaultConfig c------------------------------------------------------------------------------------ | A data structure used during command-line option parsing------ The Config data type allows a list of listen ports, but the command line--- options only allow one http and one https listener. This data structure--- is used during option parsing-data MonadSnap m => OptionData m a = OptionData- { config :: Config m a- , bind :: Maybe ByteString- , port :: Maybe Int- , sslbind :: Maybe ByteString- , sslport :: Maybe Int- , sslcert :: Maybe FilePath- , sslkey :: Maybe FilePath- }----------------------------------------------------------------------------------instance MonadSnap m => Monoid (OptionData m a) where- mempty = OptionData- { config = mempty- , bind = Nothing- , port = Nothing- , sslbind = Nothing- , sslport = Nothing- , sslcert = Nothing- , sslkey = Nothing- }-- a `mappend` b = OptionData- { config = (config b) `mappend` (config a)- , bind = (bind b) `mplus` (bind a)- , port = (port b) `mplus` (port a)- , sslbind = (sslbind b) `mplus` (sslbind a)- , sslport = (sslport b) `mplus` (sslport a)- , sslcert = (sslcert b) `mplus` (sslcert a)- , sslkey = (sslkey b) `mplus` (sslkey a)- }------------------------------------------------------------------------------------ | These are the default values for the options-defaultOptions :: MonadSnap m => OptionData m a-defaultOptions = OptionData- { config = defaultConfig- , bind = Just "0.0.0.0"- , port = Just 8000- , sslbind = Just "0.0.0.0"- , sslport = Nothing- , sslcert = Just "cert.pem"- , sslkey = Just "key.pem"- }------------------------------------------------------------------------------------ | Convert options to config-optionsToConfig :: MonadSnap m => OptionData m a -> Config m a-optionsToConfig o = mconcat $ [config o] ++ http ++ https- where lhttp = maybe2 [] ListenHttp (bind o) (port o)- lhttps = maybe4 [] ListenHttps (sslbind o)- (sslport o)- (sslcert o)- (sslkey o)- http = map (flip addListen mempty) lhttp- https = map (flip addListen mempty) lhttps-- maybe2 _ f (Just a) (Just b) = [f a b]- maybe2 d _ _ _ = d- maybe4 _ f (Just a) (Just b) (Just c) (Just d) = [f a b c d]- maybe4 d _ _ _ _ _ = d------------------------------------------------------------------------------------ | Convert config to options-configToOptions :: MonadSnap m => Config m a -> OptionData m a-configToOptions c = OptionData- { config = c- , bind = Nothing- , port = Nothing- , sslbind = Nothing- , sslport = Nothing- , sslcert = Nothing- , sslkey = Nothing- }------------------------------------------------------------------------------------ | A description of the command-line options accepted by--- 'commandLineConfig'.------ The 'OptionData' parameter is just for specifying any default values which--- are to override those in 'defaultOptions'. This is so the usage message can--- accurately inform the user what the default values for the options are. In--- most cases, you will probably just end up passing 'mempty' for this--- parameter.------ The return type is a list of options describing @'Maybe' ('OptionData' m)@--- as opposed to @'OptionData' m@, because if the @--help@ option is given,--- the set of command-line options no longer describe a config, but an action--- (printing out the usage message).-options :: MonadSnap m- => OptionData m a- -> [OptDescr (Maybe (OptionData m a))]-options defaults =- [ Option [] ["hostname"]- (ReqArg (Just . setConfig setHostname . U.fromString) "NAME")- $ "local hostname" ++ defaultC getHostname- , Option ['b'] ["address"]- (ReqArg (\s -> Just $ mempty { bind = Just $ U.fromString s })- "ADDRESS")- $ "address to bind to" ++ defaultO bind- , Option ['p'] ["port"]- (ReqArg (\s -> Just $ mempty { port = Just $ read s}) "PORT")- $ "port to listen on" ++ defaultO port- , Option [] ["ssl-address"]- (ReqArg (\s -> Just $ mempty { sslbind = Just $ U.fromString s })- "ADDRESS")- $ "ssl address to bind to" ++ defaultO sslbind- , Option [] ["ssl-port"]- (ReqArg (\s -> Just $ mempty { sslport = Just $ read s}) "PORT")- $ "ssl port to listen on" ++ defaultO sslport- , Option [] ["ssl-cert"]- (ReqArg (\s -> Just $ mempty { sslcert = Just $ read s}) "PATH")- $ "path to ssl certificate in PEM format" ++ defaultO sslcert- , Option [] ["ssl-key"]- (ReqArg (\s -> Just $ mempty { sslkey = Just $ read s}) "PATH")- $ "path to ssl private key in PEM format" ++ defaultO sslkey- , Option [] ["access-log"]- (ReqArg (Just . setConfig setAccessLog . Just) "PATH")- $ "access log" ++ (defaultC $ join . getAccessLog)- , Option [] ["error-log"]- (ReqArg (Just . setConfig setErrorLog . Just) "PATH")- $ "error log" ++ (defaultC $ join . getErrorLog)- , Option [] ["no-access-log"]- (NoArg $ Just $ setConfig setErrorLog Nothing)- $ "don't have an access log"- , Option [] ["no-error-log"]- (NoArg $ Just $ setConfig setAccessLog Nothing)- $ "don't have an error log"- , Option ['c'] ["compression"]- (NoArg $ Just $ setConfig setCompression True)- $ "use gzip compression on responses"- , Option [] ["no-compression"]- (NoArg $ Just $ setConfig setCompression False)- $ "serve responses uncompressed"- , Option ['v'] ["verbose"]- (NoArg $ Just $ setConfig setVerbose True)- $ "print server status updates to stderr"- , Option ['q'] ["quiet"]- (NoArg $ Just $ setConfig setVerbose False)- $ "do not print anything to stderr"- , Option ['h'] ["help"]- (NoArg Nothing)- $ "display this help and exit"- ]- where- setConfig f c = configToOptions $ f c mempty- conf = completeConfig $ config defaults- opts = mappend defaultOptions defaults- defaultC f = maybe "" ((", default " ++) . show) $ f conf- defaultO f = maybe ", default off" ((", default " ++) . show) $ f opts------------------------------------------------------------------------------------ | This returns a 'Config' gotten from parsing the options specified on the--- command-line.------ The 'Config' parameter is just for specifying any default values which are--- to override those in 'defaultConfig'. This is so the usage message can--- accurately inform the user what the default values for the options are. In--- most cases, you will probably just end up passing 'mempty' for this--- parameter.------ On Unix systems, the locale is read from the @LANG@ environment variable.-commandLineConfig :: MonadSnap m => Config m a -> IO (Config m a)-commandLineConfig defaults = do- args <- getArgs- prog <- getProgName-- result <- either (usage prog) return $ case getOpt Permute opts args of- (f, _, [] ) -> maybe (Left []) Right $ fmap mconcat $ sequence f- (_, _, errs) -> Left errs-- let result' = optionsToConfig $ mappend defaultOptions result--#ifndef PORTABLE- lang <- getEnv "LANG"- return $ mconcat [defaults, result', mempty {locale = fmap upToUtf8 lang}]-#else- return $ mconcat [defaults, result']-#endif-- where- opts = options $ configToOptions defaults- usage prog errs = do- let hdr = "Usage:\n " ++ prog ++ " [OPTION...]\n\nOptions:"- let msg = concat errs ++ usageInfo hdr opts- hPutStrLn stderr msg- exitFailure- upToUtf8 = takeWhile $ \c -> isAlpha c || '_' == c----------------------------------------------------------------------------------getHostname :: MonadSnap m => Config m a -> Maybe ByteString-getHostname = hostname----------------------------------------------------------------------------------getListen :: MonadSnap m => Config m a -> [ConfigListen]-getListen = listen----------------------------------------------------------------------------------getAccessLog :: MonadSnap m => Config m a -> Maybe (Maybe FilePath)-getAccessLog = accessLog----------------------------------------------------------------------------------getErrorLog :: MonadSnap m => Config m a -> Maybe (Maybe FilePath)-getErrorLog = errorLog----------------------------------------------------------------------------------getLocale :: MonadSnap m => Config m a -> Maybe String-getLocale = locale----------------------------------------------------------------------------------getBackend :: MonadSnap m => Config m a -> Maybe ConfigBackend-getBackend = backend---------------------------------------------------------------------------------getCompression :: MonadSnap m => Config m a -> Maybe Bool-getCompression = compression----------------------------------------------------------------------------------getVerbose :: MonadSnap m => Config m a -> Maybe Bool-getVerbose = verbose----------------------------------------------------------------------------------getErrorHandler :: MonadSnap m => Config m a -> Maybe (SomeException -> m ())-getErrorHandler = errorHandler----------------------------------------------------------------------------------getOther :: MonadSnap m => Config m a -> Maybe a-getOther = other----------------------------------------------------------------------------------setHostname :: MonadSnap m => ByteString -> Config m a -> Config m a-setHostname a m = m {hostname = Just a}----------------------------------------------------------------------------------addListen :: MonadSnap m => ConfigListen -> Config m a -> Config m a-addListen a m = m {listen = a : listen m}----------------------------------------------------------------------------------setAccessLog :: MonadSnap m => Maybe FilePath -> Config m a -> Config m a-setAccessLog a m = m {accessLog = Just a}----------------------------------------------------------------------------------setErrorLog :: MonadSnap m => Maybe FilePath -> Config m a -> Config m a-setErrorLog a m = m {errorLog = Just a}----------------------------------------------------------------------------------setLocale :: MonadSnap m => String -> Config m a -> Config m a-setLocale a m = m {locale = Just a}-+ , setPort+ , setProxyType+ , setSSLBind+ , setSSLCert+ , setSSLKey+ , setSSLChainCert+ , setSSLPort+ , setVerbose+ , setUnixSocket+ , setUnixSocketAccessMode --------------------------------------------------------------------------------setBackend :: MonadSnap m => ConfigBackend -> Config m a -> Config m a-setBackend a m = m { backend = Just a}+ , setStartupHook+ , StartupInfo+ , getStartupSockets+ , getStartupConfig + -- ** Proxy protocol selection+ , noProxy+ , xForwardedFor+ , haProxy+ ) where -------------------------------------------------------------------------------setCompression :: MonadSnap m => Bool -> Config m a -> Config m a-setCompression a m = m {compression = Just a}+import Snap.Internal.Http.Server.Config -------------------------------------------------------------------------------setVerbose :: MonadSnap m => Bool -> Config m a -> Config m a-setVerbose a m = m {verbose = Just a}+-- | Configure Snap in direct / non-proxying mode.+noProxy :: ProxyType+noProxy = NoProxy -------------------------------------------------------------------------------setErrorHandler :: MonadSnap m => (SomeException -> m ()) -> Config m a- -> Config m a-setErrorHandler a m = m {errorHandler = Just a}-+-- | Assert that Snap is running behind an HTTP proxy, and that the proxied+-- connection information will be stored in the \"X-Forwarded-For\" or+-- \"Forwarded-For\" HTTP headers.+xForwardedFor :: ProxyType+xForwardedFor = X_Forwarded_For -------------------------------------------------------------------------------setOther :: MonadSnap m => a -> Config m a -> Config m a-setOther a m = m {other = Just a}+-- | Assert that Snap is running behind a proxy running the HaProxy protocol+-- (see <http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt>).+-- In this mode connections that don't obey the proxy protocol are rejected.+haProxy :: ProxyType+haProxy = HaProxy
+ src/Snap/Http/Server/Types.hs view
@@ -0,0 +1,319 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Types used by the Snap HTTP Server.+module Snap.Http.Server.Types+ ( ServerConfig+ , PerSessionData++ -- * ServerConfig+ , emptyServerConfig++ -- ** getters\/setters+ , getDefaultTimeout+ , getIsSecure+ , getLocalHostname+ , getLogAccess+ , getLogError+ , getNumAcceptLoops+ , getOnDataFinished+ , getOnEscape+ , getOnException+ , getOnNewRequest+ , getOnParse+ , getOnUserHandlerFinished+ , setDefaultTimeout+ , setIsSecure+ , setLocalHostname+ , setLogAccess+ , setLogError+ , setNumAcceptLoops+ , setOnDataFinished+ , setOnEscape+ , setOnException+ , setOnNewRequest+ , setOnParse+ , setOnUserHandlerFinished++ -- * PerSessionData+ -- ** getters+ , getTwiddleTimeout+ , isNewConnection+ , getLocalAddress+ , getLocalPort+ , getRemoteAddress+ , getRemotePort++ -- * HTTP lifecycle+ -- $lifecycle++ -- * Hooks+ -- $hooks++ , DataFinishedHook+ , EscapeSnapHook+ , ExceptionHook+ , ParseHook+ , NewRequestHook+ , UserHandlerFinishedHook++ -- * Handlers+ , SendFileHandler+ , ServerHandler+ , AcceptFunc++ -- * Socket types+ , SocketConfig(..)+ ) where++------------------------------------------------------------------------------+import Data.ByteString (ByteString)+import Data.IORef (readIORef)+import Data.Word (Word64)+------------------------------------------------------------------------------+import Data.ByteString.Builder (Builder)+------------------------------------------------------------------------------+import Snap.Core (Request, Response)+import Snap.Internal.Http.Server.Types (AcceptFunc, DataFinishedHook, EscapeSnapHook, ExceptionHook, NewRequestHook, ParseHook, PerSessionData (_isNewConnection, _localAddress, _localPort, _remoteAddress, _remotePort, _twiddleTimeout), SendFileHandler, ServerConfig (..), ServerHandler, SocketConfig (..), UserHandlerFinishedHook)+++ ---------------------------+ -- snap server lifecycle --+ ---------------------------++------------------------------------------------------------------------------+-- $lifecycle+--+-- 'Request' \/ 'Response' lifecycle for \"normal\" requests (i.e. without+-- errors):+--+-- 1. accept a new connection, set it up (e.g. with SSL)+--+-- 2. create a 'PerSessionData' object+--+-- 3. Enter the 'SessionHandler', which:+--+-- 4. calls the 'NewRequestHook', making a new hookState object.+--+-- 5. parses the HTTP request. If the session is over, we stop here.+--+-- 6. calls the 'ParseHook'+--+-- 7. enters the 'ServerHandler', which is provided by another part of the+-- framework+--+-- 8. the server handler passes control to the user handler+--+-- 9. a 'Response' is produced, and the 'UserHandlerFinishedHook' is called.+--+-- 10. the 'Response' is written to the client+--+-- 11. the 'DataFinishedHook' is called.+--+-- 12. we go to #3.+++ -----------+ -- hooks --+ -----------++------------------------------------------------------------------------------+-- $hooks+-- #hooks#+--+-- At various critical points in the HTTP lifecycle, the Snap server will call+-- user-defined \"hooks\" that can be used for instrumentation or tracing of+-- the process of building the HTTP response. The first hook called, the+-- 'NewRequestHook', will generate a \"hookState\" object (having some+-- user-defined abstract type), and this object will be passed to the rest of+-- the hooks as the server handles the process of responding to the HTTP+-- request.+--+-- For example, you could pass a set of hooks to the Snap server that measured+-- timings for each URI handled by the server to produce online statistics and+-- metrics using something like @statsd@ (<https://github.com/etsy/statsd>).+++------------------------------------------------------------------------------+emptyServerConfig :: ServerConfig a+emptyServerConfig =+ ServerConfig (\_ _ _ -> return $! ())+ (\_ -> return $! ())+ (\_ -> return $ error "undefined hook state")+ (\_ _ -> return $! ())+ (\_ _ _ -> return $! ())+ (\_ _ _ -> return $! ())+ (\_ _ -> return $! ())+ (\_ -> return $! ())+ "localhost"+ 30+ False+ 1+++------------------------------------------------------------------------------+getLogAccess :: ServerConfig hookState -> Request -> Response -> Word64 -> IO ()+getLogAccess sc = _logAccess sc+++------------------------------------------------------------------------------+getLogError :: ServerConfig hookState -> Builder -> IO ()+getLogError sc = _logError sc+++------------------------------------------------------------------------------+getOnNewRequest :: ServerConfig hookState -> NewRequestHook hookState+getOnNewRequest sc = _onNewRequest sc+++------------------------------------------------------------------------------+getOnParse :: ServerConfig hookState -> ParseHook hookState+getOnParse sc = _onParse sc+++------------------------------------------------------------------------------+getOnUserHandlerFinished :: ServerConfig hookState+ -> UserHandlerFinishedHook hookState+getOnUserHandlerFinished sc = _onUserHandlerFinished sc+++------------------------------------------------------------------------------+getOnDataFinished :: ServerConfig hookState -> DataFinishedHook hookState+getOnDataFinished sc = _onDataFinished sc+++------------------------------------------------------------------------------+getOnException :: ServerConfig hookState -> ExceptionHook hookState+getOnException sc = _onException sc+++------------------------------------------------------------------------------+getOnEscape :: ServerConfig hookState -> EscapeSnapHook hookState+getOnEscape sc = _onEscape sc+++------------------------------------------------------------------------------+getLocalHostname :: ServerConfig hookState -> ByteString+getLocalHostname sc = _localHostname sc+++------------------------------------------------------------------------------+getDefaultTimeout :: ServerConfig hookState -> Int+getDefaultTimeout sc = _defaultTimeout sc+++------------------------------------------------------------------------------+getIsSecure :: ServerConfig hookState -> Bool+getIsSecure sc = _isSecure sc+++------------------------------------------------------------------------------+getNumAcceptLoops :: ServerConfig hookState -> Int+getNumAcceptLoops sc = _numAcceptLoops sc+++------------------------------------------------------------------------------+setLogAccess :: (Request -> Response -> Word64 -> IO ())+ -> ServerConfig hookState+ -> ServerConfig hookState+setLogAccess s sc = sc { _logAccess = s }+++------------------------------------------------------------------------------+setLogError :: (Builder -> IO ())+ -> ServerConfig hookState+ -> ServerConfig hookState+setLogError s sc = sc { _logError = s }+++------------------------------------------------------------------------------+setOnNewRequest :: NewRequestHook hookState+ -> ServerConfig hookState+ -> ServerConfig hookState+setOnNewRequest s sc = sc { _onNewRequest = s }+++------------------------------------------------------------------------------+setOnParse :: ParseHook hookState+ -> ServerConfig hookState+ -> ServerConfig hookState+setOnParse s sc = sc { _onParse = s }+++------------------------------------------------------------------------------+setOnUserHandlerFinished :: UserHandlerFinishedHook hookState+ -> ServerConfig hookState+ -> ServerConfig hookState+setOnUserHandlerFinished s sc = sc { _onUserHandlerFinished = s }+++------------------------------------------------------------------------------+setOnDataFinished :: DataFinishedHook hookState+ -> ServerConfig hookState+ -> ServerConfig hookState+setOnDataFinished s sc = sc { _onDataFinished = s }+++------------------------------------------------------------------------------+setOnException :: ExceptionHook hookState+ -> ServerConfig hookState+ -> ServerConfig hookState+setOnException s sc = sc { _onException = s }+++------------------------------------------------------------------------------+setOnEscape :: EscapeSnapHook hookState+ -> ServerConfig hookState+ -> ServerConfig hookState+setOnEscape s sc = sc { _onEscape = s }+++------------------------------------------------------------------------------+setLocalHostname :: ByteString+ -> ServerConfig hookState+ -> ServerConfig hookState+setLocalHostname s sc = sc { _localHostname = s }+++------------------------------------------------------------------------------+setDefaultTimeout :: Int -> ServerConfig hookState -> ServerConfig hookState+setDefaultTimeout s sc = sc { _defaultTimeout = s }+++------------------------------------------------------------------------------+setIsSecure :: Bool -> ServerConfig hookState -> ServerConfig hookState+setIsSecure s sc = sc { _isSecure = s }+++------------------------------------------------------------------------------+setNumAcceptLoops :: Int -> ServerConfig hookState -> ServerConfig hookState+setNumAcceptLoops s sc = sc { _numAcceptLoops = s }+++------------------------------------------------------------------------------+getTwiddleTimeout :: PerSessionData -> ((Int -> Int) -> IO ())+getTwiddleTimeout psd = _twiddleTimeout psd+++------------------------------------------------------------------------------+isNewConnection :: PerSessionData -> IO Bool+isNewConnection = readIORef . _isNewConnection+++------------------------------------------------------------------------------+getLocalAddress :: PerSessionData -> ByteString+getLocalAddress psd = _localAddress psd+++------------------------------------------------------------------------------+getLocalPort :: PerSessionData -> Int+getLocalPort psd = _localPort psd+++------------------------------------------------------------------------------+getRemoteAddress :: PerSessionData -> ByteString+getRemoteAddress psd = _remoteAddress psd+++------------------------------------------------------------------------------+getRemotePort :: PerSessionData -> Int+getRemotePort psd = _remotePort psd
− src/Snap/Internal/Http/Parser.hs
@@ -1,496 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE PackageImports #-}--module Snap.Internal.Http.Parser- ( IRequest(..)- , parseRequest- , readChunkedTransferEncoding- , iterParser- , parseCookie- , parseUrlEncoded- , writeChunkedTransferEncoding- , strictize- ) where----------------------------------------------------------------------------------import Control.Applicative-import Control.Arrow (second)-import Control.Monad (liftM)-import Control.Monad.Trans-import Data.Attoparsec hiding (many, Result(..))-import Data.Attoparsec.Enumerator-import Data.Bits-import Data.ByteString (ByteString)-import qualified Data.ByteString as S-import Data.ByteString.Internal (c2w, w2c)-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString.Nums.Careless.Hex as Cvt-import Data.Char-import Data.DList (DList)-import qualified Data.DList as D-import Data.List (foldl')-import Data.Int-import Data.Map (Map)-import qualified Data.Map as Map-import Data.Maybe (catMaybes)-import qualified Data.Vector.Unboxed as Vec-import Data.Vector.Unboxed (Vector)-import Data.Word (Word8, Word64)-import Prelude hiding (head, take, takeWhile)--------------------------------------------------------------------------------import Snap.Internal.Http.Types-import Snap.Internal.Debug-import Snap.Internal.Iteratee.Debug-import Snap.Iteratee hiding (map, take)------------------------------------------------------------------------------------ | an internal version of the headers part of an HTTP request-data IRequest = IRequest- { iMethod :: Method- , iRequestUri :: ByteString- , iHttpVersion :: (Int,Int)- , iRequestHeaders :: [(ByteString, ByteString)]- }----------------------------------------------------------------------------------instance Show IRequest where- show (IRequest m u v r) =- concat [ show m- , " "- , show u- , " "- , show v- , " "- , show r ]----------------------------------------------------------------------------------parseRequest :: (Monad m) => Iteratee ByteString m (Maybe IRequest)-parseRequest = iterParser pRequest----------------------------------------------------------------------------------readChunkedTransferEncoding :: (MonadIO m) =>- Enumeratee ByteString ByteString m a-readChunkedTransferEncoding =- chunkParserToEnumeratee $- iterateeDebugWrapper "pGetTransferChunk" $- iterParser pGetTransferChunk----------------------------------------------------------------------------------toHex :: Int64 -> S.ByteString-toHex 0 = "0"-toHex n' = s- where- !s = trim 16 (fromIntegral (abs n'))-- trim :: Int -> Word64 -> S.ByteString- trim !i !n- | n .&. 0xf000000000000000 == 0 = trim (i-1) (n `shiftL` 4)- | otherwise = fst (S.unfoldrN i f n)-- f n = Just (ch (n `shiftR` 60), n `shiftL` 4)-- ch (fromIntegral -> i)- | i < 10 = (c2w '0' - 0) + i- | otherwise = (c2w 'a' - 10) + i------------------------------------------------------------------------------------ | Given an iteratee, produces a new one that wraps chunks sent to it with a--- chunked transfer-encoding. Example usage:--------- > FIXME this text is now wrong------ > > (writeChunkedTransferEncoding--- > (enumLBS (L.fromChunks ["foo","bar","quux"]))--- > stream2stream) >>=--- > run >>=--- > return . fromWrap--- >--- > Chunk "a\r\nfoobarquux\r\n0\r\n\r\n" Empty----writeChunkedTransferEncoding :: Enumeratee ByteString ByteString IO a-writeChunkedTransferEncoding = checkDone start-- where- start = bufIt 0 D.empty-- bufSiz = 16284-- sendOut :: DList ByteString- -> (Stream ByteString -> Iteratee ByteString IO a)- -> Iteratee ByteString IO (Step ByteString IO a)- sendOut dl k = do- let chunks = D.toList dl- let bs = L.fromChunks chunks- let n = L.length bs-- if n == 0- then return $ Continue k- else do- let o = L.concat [ L.fromChunks [ toHex (toEnum . fromEnum $ n)- , "\r\n" ]- , bs- , "\r\n" ]-- lift $ runIteratee $ enumLBS o (Continue k)---- bufIt :: Int- -> DList ByteString- -> (Stream ByteString -> Iteratee ByteString IO a)- -> Iteratee ByteString IO (Step ByteString IO a)- bufIt n dl k = do- mbS <- head- case mbS of- Nothing -> do- step <- sendOut dl k- step' <- lift $ runIteratee $ enumBS "0\r\n\r\n" step- lift $ runIteratee $ enumEOF step'-- (Just s) -> do- let m = S.length s-- if m == 0- then bufIt n dl k- else do- let n' = m + n- let dl' = D.snoc dl s-- if n' > bufSiz- then do- step <- sendOut dl' k- checkDone start step- else bufIt n' dl' k----------------------------------------------------------------------------------chunkParserToEnumeratee :: (MonadIO m) =>- Iteratee ByteString m (Maybe ByteString)- -> Enumeratee ByteString ByteString m a-chunkParserToEnumeratee getChunk client = do- debug $ "chunkParserToEnumeratee: getting chunk"- mbB <- getChunk- debug $ "chunkParserToEnumeratee: getChunk was " ++ show mbB- mbX <- peek- debug $ "chunkParserToEnumeratee: .. and peek is " ++ show mbX--- maybe finishIt sendBS mbB-- where- whatWasReturn (Continue _) = "continue"- whatWasReturn (Yield _ z) = "yield, with remainder " ++ show z- whatWasReturn (Error e) = "error, with " ++ show e-- sendBS s = do- step' <- lift $ runIteratee $ enumBS s client- debug $ "chunkParserToEnumeratee: after sending "- ++ show s ++ ", return was "- ++ whatWasReturn step'- mbX <- peek- debug $ "chunkParserToEnumeratee: .. and peek is " ++ show mbX- chunkParserToEnumeratee getChunk step'-- finishIt = lift $ runIteratee $ enumEOF client------------------------------------------------------------------------------------ parse functions----------------------------------------------------------------------------------- theft alert: many of these routines adapted from Johan Tibell's hyena--- package------------------------------------------------------------------------------------ | Parsers for different tokens in an HTTP request.-sp, digit, letter :: Parser Word8-sp = word8 $ c2w ' '-digit = satisfy (isDigit . w2c)-letter = satisfy (isAlpha . w2c)----------------------------------------------------------------------------------untilEOL :: Parser ByteString-untilEOL = takeWhile notend- where- notend d = let c = w2c d in not $ c == '\r' || c == '\n'----------------------------------------------------------------------------------crlf :: Parser ByteString-crlf = string "\r\n"------------------------------------------------------------------------------------ | Parser for zero or more spaces.-spaces :: Parser [Word8]-spaces = many sp----------------------------------------------------------------------------------pSpaces :: Parser ByteString-pSpaces = takeWhile (isSpace . w2c)------------------------------------------------------------------------------------ | Parser for the internal request data type.-pRequest :: Parser (Maybe IRequest)-pRequest = (Just <$> pRequest') <|>- (option "" crlf *> endOfInput *> pure Nothing)----------------------------------------------------------------------------------pRequest' :: Parser IRequest-pRequest' = IRequest- <$> (option "" crlf *> pMethod) <* sp- <*> pUri <* sp- <*> pVersion <* crlf- <*> pHeaders <* crlf-- -- note: the optional crlf is at the beginning because some older browsers- -- send an extra crlf after a POST body------------------------------------------------------------------------------------ | Parser for the request method.-pMethod :: Parser Method-pMethod = (OPTIONS <$ string "OPTIONS")- <|> (GET <$ string "GET")- <|> (HEAD <$ string "HEAD")- <|> word8 (c2w 'P') *> ((POST <$ string "OST") <|>- (PUT <$ string "UT"))- <|> (DELETE <$ string "DELETE")- <|> (TRACE <$ string "TRACE")- <|> (CONNECT <$ string "CONNECT")------------------------------------------------------------------------------------ | Parser for the request URI.-pUri :: Parser ByteString-pUri = takeWhile (not . isSpace . w2c)------------------------------------------------------------------------------------ | Parser for the request's HTTP protocol version.-pVersion :: Parser (Int, Int)-pVersion = string "HTTP/" *>- liftA2 (,) (digit' <* word8 (c2w '.')) digit'- where- digit' = fmap (digitToInt . w2c) digit----------------------------------------------------------------------------------fieldChars :: Parser ByteString-fieldChars = takeWhile isFieldChar- where- isFieldChar c = (Vec.!) fieldCharTable (fromEnum c)----------------------------------------------------------------------------------fieldCharTable :: Vector Bool-fieldCharTable = Vec.generate 256 f- where- f d = let c=toEnum d in (isDigit c) || (isAlpha c) || c == '-' || c == '_'------------------------------------------------------------------------------------ | Parser for request headers.-pHeaders :: Parser [(ByteString, ByteString)]-pHeaders = many header- where- header = {-# SCC "pHeaders/header" #-}- liftA2 (,)- fieldName- (word8 (c2w ':') *> spaces *> contents)-- fieldName = {-# SCC "pHeaders/fieldName" #-}- liftA2 S.cons letter fieldChars-- contents = {-# SCC "pHeaders/contents" #-}- liftA2 S.append- (untilEOL <* crlf)- (continuation <|> pure S.empty)-- isLeadingWS w = {-# SCC "pHeaders/isLeadingWS" #-}- elem w wstab-- wstab = map c2w " \t"-- leadingWhiteSpace = {-# SCC "pHeaders/leadingWhiteSpace" #-}- takeWhile1 isLeadingWS-- continuation = {-# SCC "pHeaders/continuation" #-}- liftA2 S.cons- (leadingWhiteSpace *> pure (c2w ' '))- contents----------------------------------------------------------------------------------pGetTransferChunk :: Parser (Maybe ByteString)-pGetTransferChunk = do- !hex <- liftM fromHex $ (takeWhile (isHexDigit . w2c))- takeTill ((== '\r') . w2c)- crlf- if hex <= 0- then return Nothing- else do- x <- take hex- crlf- return $ Just x- where- fromHex :: ByteString -> Int- fromHex s = Cvt.hex (L.fromChunks [s])------------------------------------------------------------------------------------ COOKIE PARSING----------------------------------------------------------------------------------- these definitions try to mirror RFC-2068 (the HTTP/1.1 spec) and RFC-2109--- (cookie spec): please point out any errors!---------------------------------------------------------------------------------{-# INLINE matchAll #-}-matchAll :: [ Char -> Bool ] -> Char -> Bool-matchAll x c = and $ map ($ c) x----------------------------------------------------------------------------------{-# INLINE isToken #-}-isToken :: Char -> Bool-isToken c = (Vec.!) tokenTable (fromEnum c)- where- tokenTable :: Vector Bool- tokenTable = Vec.generate 256 (f . toEnum)-- f = matchAll [ isAscii- , not . isControl- , not . isSpace- , not . flip elem [ '(', ')', '<', '>', '@', ',', ';'- , ':', '\\', '\"', '/', '[', ']'- , '?', '=', '{', '}' ]- ]---------------------------------------------------------------------------------{-# INLINE isRFCText #-}-isRFCText :: Char -> Bool-isRFCText = not . isControl----------------------------------------------------------------------------------pToken :: Parser ByteString-pToken = takeWhile (isToken . w2c)----------------------------------------------------------------------------------pQuotedString :: Parser ByteString-pQuotedString = q *> quotedText <* q- where- quotedText = (S.concat . reverse) <$> f []-- f soFar = do- t <- takeWhile qdtext-- let soFar' = t:soFar-- -- RFC says that backslash only escapes for <">- choice [ string "\\\"" *> f ("\"" : soFar')- , pure soFar' ]--- q = word8 $ c2w '\"'-- qdtext = matchAll [ isRFCText, (/= '\"'), (/= '\\') ] . w2c----------------------------------------------------------------------------------pCookies :: Parser [Cookie]-pCookies = do- -- grab kvps and turn to strict bytestrings- kvps <- pAvPairs-- return $ map toCookie $ filter (not . S.isPrefixOf "$" . fst) kvps-- where- toCookie (nm,val) = Cookie nm val Nothing Nothing Nothing------------------------------------------------------------------------------------ unhelpfully, the spec mentions "old-style" cookies that don't have quotes--- around the value. wonderful.-pWord :: Parser ByteString-pWord = pQuotedString <|> (takeWhile ((/= ';') . w2c))----------------------------------------------------------------------------------pAvPairs :: Parser [(ByteString, ByteString)]-pAvPairs = do- a <- pAvPair- b <- many (pSpaces *> char ';' *> pSpaces *> pAvPair)-- return $ a:b----------------------------------------------------------------------------------pAvPair :: Parser (ByteString, ByteString)-pAvPair = do- key <- pToken <* pSpaces- val <- option "" $ char '=' *> pSpaces *> pWord-- return (key,val)----------------------------------------------------------------------------------parseCookie :: ByteString -> Maybe [Cookie]-parseCookie = parseToCompletion pCookies------------------------------------------------------------------------------------ application/x-www-form-urlencoded----------------------------------------------------------------------------------------------------------------------------------------------------------------parseUrlEncoded :: ByteString -> Map ByteString [ByteString]-parseUrlEncoded s = foldl' (\m (k,v) -> Map.insertWith' (++) k [v] m)- Map.empty- decoded- where- breakApart = (second (S.drop 1)) . S.break (== (c2w '='))-- parts :: [(ByteString,ByteString)]- parts = map breakApart $ S.split (c2w '&') s-- urldecode = parseToCompletion pUrlEscaped-- decodeOne (a,b) = do- a' <- urldecode a- b' <- urldecode b- return (a',b')-- decoded = catMaybes $ map decodeOne parts------------------------------------------------------------------------------------ utility functions----------------------------------------------------------------------------------------------------------------------------------------------------------------strictize :: L.ByteString -> ByteString-strictize = S.concat . L.toChunks----------------------------------------------------------------------------------char :: Char -> Parser Word8-char = word8 . c2w
− src/Snap/Internal/Http/Server.hs
@@ -1,853 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Snap.Internal.Http.Server where---------------------------------------------------------------------------------import Control.Arrow (first, second)-import Control.Monad.State.Strict-import Control.Exception-import Data.Char-import Data.CIByteString-import Data.Binary.Put-import Data.ByteString (ByteString)-import qualified Data.ByteString as S-import qualified Data.ByteString.Char8 as SC-import qualified Data.ByteString.Lazy as L-import Data.ByteString.Internal (c2w, w2c)-import qualified Data.ByteString.Nums.Careless.Int as Cvt-import Data.Int-import Data.IORef-import Data.List (foldl')-import qualified Data.Map as Map-import Data.Maybe (fromJust, catMaybes, fromMaybe)-import Data.Monoid-import Data.Version-import Data.Time-import Foreign.C.Types-import Foreign.ForeignPtr-import GHC.Conc-import Prelude hiding (catch, show, Show)-import qualified Prelude-import System.PosixCompat.Files hiding (setFileSize)-import System.Posix.Types (FileOffset)-import System.Locale-import Text.Show.ByteString hiding (runPut)--------------------------------------------------------------------------------import System.FastLogger-import Snap.Internal.Http.Types-import Snap.Internal.Debug-import Snap.Internal.Http.Parser-import Snap.Internal.Http.Server.Date--import Snap.Internal.Http.Server.Backend-import Snap.Internal.Http.Server.HttpPort-import qualified Snap.Internal.Http.Server.GnuTLS as TLS-import Snap.Internal.Http.Server.SimpleBackend-import Snap.Internal.Http.Server.LibevBackend--import Snap.Internal.Iteratee.Debug-import Snap.Iteratee hiding (head, take, map)-import qualified Snap.Iteratee as I--import qualified Paths_snap_server as V------------------------------------------------------------------------------------ | The handler has to return the request object because we have to clear the--- HTTP request body before we send the response. If the handler consumes the--- request body, it is responsible for setting @rqBody=return@ in the returned--- request (otherwise we will mess up reading the input stream).------ Note that we won't be bothering end users with this -- the details will be--- hidden inside the Snap monad-type ServerHandler = (ByteString -> IO ())- -> Request- -> Iteratee ByteString IO (Request,Response)----------------------------------------------------------------------------------type ServerMonad = StateT ServerState (Iteratee ByteString IO)----------------------------------------------------------------------------------data ListenPort =- -- (bind address, port)- HttpPort ByteString Int |- -- (bind address, port, path to certificate, path to key)- HttpsPort ByteString Int FilePath FilePath----------------------------------------------------------------------------------data EventLoopType = EventLoopSimple- | EventLoopLibEv- deriving (Prelude.Show)----------------------------------------------------------------------------------defaultEvType :: EventLoopType-#ifdef LIBEV-defaultEvType = EventLoopLibEv-#else-defaultEvType = EventLoopSimple-#endif----------------------------------------------------------------------------------data ServerState = ServerState- { _forceConnectionClose :: Bool- , _localHostname :: ByteString- , _sessionPort :: SessionInfo- , _logAccess :: Request -> Response -> IO ()- , _logError :: ByteString -> IO ()- }----------------------------------------------------------------------------------runServerMonad :: ByteString -- ^ local host name- -> SessionInfo -- ^ session port information- -> (Request -> Response -> IO ()) -- ^ access log function- -> (ByteString -> IO ()) -- ^ error log function- -> ServerMonad a -- ^ monadic action to run- -> Iteratee ByteString IO a-runServerMonad lh s la le m = evalStateT m st- where- st = ServerState False lh s la le------------------------------------------------------------------------------------ input/output----------------------------------------------------------------------------------httpServe :: [ListenPort] -- ^ ports to listen on- -> Maybe EventLoopType -- ^ Specify a given event loop,- -- otherwise a default is picked- -> ByteString -- ^ local hostname (server name)- -> Maybe FilePath -- ^ path to the access log- -> Maybe FilePath -- ^ path to the error log- -> ServerHandler -- ^ handler procedure- -> IO ()-httpServe ports mevType localHostname alogPath elogPath handler =- withLoggers alogPath elogPath- (\(alog, elog) -> spawnAll alog elog)-- where- --------------------------------------------------------------------------- spawnAll alog elog = {-# SCC "httpServe/spawnAll" #-} do-- let evType = maybe defaultEvType id mevType-- logE elog $ S.concat [ "Server.httpServe: START ("- , toBS $ Prelude.show evType, ")"]-- let isHttps p = case p of { (HttpsPort _ _ _ _) -> True; _ -> False;}- let initHttps = foldr (\p b -> b || isHttps p) False ports-- if initHttps- then TLS.initTLS- else return ()-- nports <- mapM bindPort ports-- (runEventLoop evType nports numCapabilities (logE elog) $- runHTTP alog elog handler localHostname) `finally` do-- logE elog "Server.httpServe: SHUTDOWN"-- if initHttps- then TLS.stopTLS- else return ()-- logE elog "Server.httpServe: BACKEND STOPPED"-- --------------------------------------------------------------------------- bindPort (HttpPort baddr port) = bindHttp baddr port- bindPort (HttpsPort baddr port cert key) =- TLS.bindHttps baddr port cert key--- --------------------------------------------------------------------------- runEventLoop EventLoopSimple = simpleEventLoop- runEventLoop EventLoopLibEv = libEvEventLoop--- --------------------------------------------------------------------------- maybeSpawnLogger = maybe (return Nothing) $ (liftM Just) . newLogger--- --------------------------------------------------------------------------- withLoggers afp efp =- bracket (do alog <- maybeSpawnLogger afp- elog <- maybeSpawnLogger efp- return (alog, elog))- (\(alog, elog) -> do- maybe (return ()) stopLogger alog- maybe (return ()) stopLogger elog)----------------------------------------------------------------------------------debugE :: (MonadIO m) => ByteString -> m ()-debugE s = debug $ "Server: " ++ (map w2c $ S.unpack s)----------------------------------------------------------------------------------logE :: Maybe Logger -> ByteString -> IO ()-logE elog = maybe debugE (\l s -> debugE s >> logE' l s) elog----------------------------------------------------------------------------------logE' :: Logger -> ByteString -> IO ()-logE' logger s = (timestampedLogEntry s) >>= logMsg logger----------------------------------------------------------------------------------bshow :: (Prelude.Show a) => a -> ByteString-bshow = toBS . Prelude.show----------------------------------------------------------------------------------logA ::Maybe Logger -> Request -> Response -> IO ()-logA alog = maybe (\_ _ -> return ()) logA' alog----------------------------------------------------------------------------------logA' :: Logger -> Request -> Response -> IO ()-logA' logger req rsp = do- let hdrs = rqHeaders req- let host = rqRemoteAddr req- let user = Nothing -- TODO we don't do authentication yet- let (v, v') = rqVersion req- let ver = S.concat [ "HTTP/", bshow v, ".", bshow v' ]- let method = toBS $ Prelude.show (rqMethod req)- let reql = S.intercalate " " [ method, rqURI req, ver ]- let status = rspStatus rsp- let cl = rspContentLength rsp- let referer = maybe Nothing (Just . head) $ Map.lookup "referer" hdrs- let userAgent = maybe "-" head $ Map.lookup "user-agent" hdrs-- msg <- combinedLogEntry host user reql status cl referer userAgent- logMsg logger msg----------------------------------------------------------------------------------runHTTP :: Maybe Logger -- ^ access logger- -> Maybe Logger -- ^ error logger- -> ServerHandler -- ^ handler procedure- -> ByteString -- ^ local host name- -> SessionInfo -- ^ session port information- -> Enumerator ByteString IO () -- ^ read end of socket- -> Iteratee ByteString IO () -- ^ write end of socket- -> (FilePath -> Int64 -> Int64 -> IO ())- -- ^ sendfile end- -> IO () -- ^ timeout tickler- -> IO ()-runHTTP alog elog handler lh sinfo readEnd writeEnd onSendFile tickle =- go `catches` [ Handler $ \(e :: AsyncException) -> do- throwIO e-- , Handler $ \(e :: SomeException) ->- logE elog $ S.concat [ logPrefix , bshow e ] ]-- where- logPrefix = S.concat [ "[", remoteAddress sinfo, "]: error: " ]-- go = do- buf <- mkIterateeBuffer- let iter1 = runServerMonad lh sinfo (logA alog) (logE elog) $- httpSession writeEnd buf onSendFile tickle- handler- let iter = iterateeDebugWrapper "httpSession iteratee" iter1-- debug "runHTTP/go: prepping iteratee for start"-- step <- liftIO $ runIteratee iter-- debug "runHTTP/go: running..."- run_ $ readEnd step- debug "runHTTP/go: finished"----------------------------------------------------------------------------------sERVER_HEADER :: [ByteString]-sERVER_HEADER = [S.concat ["Snap/", snapServerVersion]]----------------------------------------------------------------------------------snapServerVersion :: ByteString-snapServerVersion = SC.pack $ showVersion $ V.version----------------------------------------------------------------------------------logAccess :: Request -> Response -> ServerMonad ()-logAccess req rsp = gets _logAccess >>= (\l -> liftIO $ l req rsp)----------------------------------------------------------------------------------logError :: ByteString -> ServerMonad ()-logError s = gets _logError >>= (\l -> liftIO $ l s)------------------------------------------------------------------------------------ | Runs an HTTP session.-httpSession :: Iteratee ByteString IO () -- ^ write end of socket- -> ForeignPtr CChar -- ^ iteratee buffer- -> (FilePath -> Int64 -> Int64 -> IO ())- -- ^ sendfile continuation- -> IO () -- ^ timeout tickler- -> ServerHandler -- ^ handler procedure- -> ServerMonad ()-httpSession writeEnd' ibuf onSendFile tickle handler = do-- let writeEnd1 = I.unsafeBufferIterateeWithBuffer ibuf writeEnd'- let writeEndI = iterateeDebugWrapper "writeEnd" writeEnd1-- -- everything downstream expects a Step here- writeEnd <- liftIO $ runIteratee writeEndI-- liftIO $ debug "Server.httpSession: entered"- mreq <- receiveRequest- liftIO $ debug "Server.httpSession: receiveRequest finished"-- -- successfully got a request, so restart timer- liftIO tickle-- case mreq of- (Just req) -> do- liftIO $ debug $ "Server.httpSession: got request: " ++- Prelude.show (rqMethod req) ++- " " ++ SC.unpack (rqURI req) ++- " " ++ Prelude.show (rqVersion req)-- -- check for Expect: 100-continue- checkExpect100Continue req writeEnd-- logerr <- gets _logError-- (req',rspOrig) <- lift $ handler logerr req-- liftIO $ debug $ "Server.httpSession: finished running user handler"-- let rspTmp = rspOrig { rspHttpVersion = rqVersion req }- checkConnectionClose (rspHttpVersion rspTmp) (rspHeaders rspTmp)-- cc <- gets _forceConnectionClose- let rsp = if cc- then (setHeader "Connection" "close" rspTmp)- else rspTmp-- liftIO $ debug "Server.httpSession: handled, skipping request body"-- if rspTransformingRqBody rsp- then liftIO $ debug $- "Server.httpSession: not skipping " ++- "request body, transforming."- else do- srqEnum <- liftIO $ readIORef $ rqBody req'- let (SomeEnumerator rqEnum) = srqEnum-- skipStep <- liftIO $ runIteratee $ iterateeDebugWrapper- "httpSession/skipToEof" skipToEof- lift $ rqEnum skipStep-- liftIO $ debug $ "Server.httpSession: request body skipped, " ++- "sending response"-- date <- liftIO getDateString- let ins = Map.insert "Date" [date] .- Map.insert "Server" sERVER_HEADER- let rsp' = updateHeaders ins rsp- (bytesSent,_) <- sendResponse req rsp' writeEnd onSendFile-- liftIO . debug $ "Server.httpSession: sent " ++- (Prelude.show bytesSent) ++ " bytes"-- maybe (logAccess req rsp')- (\_ -> logAccess req $ setContentLength bytesSent rsp')- (rspContentLength rsp')-- if cc- then do- debug $ "httpSession: Connection: Close, harikari"- liftIO $ myThreadId >>= killThread- else httpSession writeEnd' ibuf onSendFile tickle handler-- Nothing -> do- liftIO $ debug $ "Server.httpSession: parser did not produce a " ++- "request, ending session"- return ()----------------------------------------------------------------------------------checkExpect100Continue :: Request- -> Step ByteString IO ()- -> ServerMonad ()-checkExpect100Continue req writeEnd = do- let mbEx = getHeaders "Expect" req-- maybe (return ())- (\l -> if elem "100-continue" l then go else return ())- mbEx-- where- go = do- let (major,minor) = rqVersion req- let hl = runPut $ do- putByteString "HTTP/"- showp major- putAscii '.'- showp minor- putByteString " 100 Continue\r\n\r\n"- liftIO $ runIteratee $ (enumLBS hl >==> enumEOF) writeEnd- return ()----------------------------------------------------------------------------------receiveRequest :: ServerMonad (Maybe Request)-receiveRequest = do- debug "receiveRequest: entered"- mreq <- {-# SCC "receiveRequest/parseRequest" #-} lift $- iterateeDebugWrapper "parseRequest" parseRequest- debug "receiveRequest: parseRequest returned"-- case mreq of- (Just ireq) -> do- req' <- toRequest ireq- setEnumerator req'- req <- parseForm req'- checkConnectionClose (rqVersion req) (rqHeaders req)- return $ Just req-- Nothing -> return Nothing--- where- --------------------------------------------------------------------------- -- check: did the client specify "transfer-encoding: chunked"? then we- -- have to honor that.- --- -- otherwise: check content-length header. if set: only take N bytes from- -- the read end of the socket- --- -- if no content-length and no chunked encoding, enumerate the entire- -- socket and close afterwards- setEnumerator :: Request -> ServerMonad ()- setEnumerator req = {-# SCC "receiveRequest/setEnumerator" #-} do- if isChunked- then do- liftIO $ debug $ "receiveRequest/setEnumerator: " ++- "input in chunked encoding"- let e = joinI . readChunkedTransferEncoding- liftIO $ writeIORef (rqBody req)- (SomeEnumerator e)- else maybe (noContentLength req) hasContentLength mbCL-- where- isChunked = maybe False- ((== ["chunked"]) . map toCI)- (Map.lookup "transfer-encoding" hdrs)-- hasContentLength :: Int64 -> ServerMonad ()- hasContentLength len = do- liftIO $ debug $ "receiveRequest/setEnumerator: " ++- "request had content-length " ++ Prelude.show len- liftIO $ writeIORef (rqBody req) (SomeEnumerator e)- liftIO $ debug "receiveRequest/setEnumerator: body enumerator set"- where- e :: Enumerator ByteString IO a- e st = do- st' <- lift $- runIteratee $- iterateeDebugWrapper "rqBody iterator" $- returnI st-- joinI $ takeExactly len st'-- noContentLength :: Request -> ServerMonad ()- noContentLength rq = liftIO $ do- debug ("receiveRequest/setEnumerator: " ++- "request did NOT have content-length")- let enum = SomeEnumerator $- if rqMethod rq == POST || rqMethod rq == PUT- then returnI- else iterateeDebugWrapper "noContentLength" .- joinI . I.take 0- writeIORef (rqBody rq) enum- debug "receiveRequest/setEnumerator: body enumerator set"--- hdrs = rqHeaders req- mbCL = Map.lookup "content-length" hdrs >>= return . Cvt.int . head--- --------------------------------------------------------------------------- parseForm :: Request -> ServerMonad Request- parseForm req = {-# SCC "receiveRequest/parseForm" #-}- if doIt then getIt else return req- where- mbCT = liftM head $ Map.lookup "content-type" (rqHeaders req)- trimIt = fst . SC.spanEnd isSpace . SC.takeWhile (/= ';')- . SC.dropWhile isSpace- mbCT' = liftM trimIt mbCT- doIt = mbCT' == Just "application/x-www-form-urlencoded"-- maximumPOSTBodySize :: Int64- maximumPOSTBodySize = 10*1024*1024-- getIt :: ServerMonad Request- getIt = {-# SCC "receiveRequest/parseForm/getIt" #-} do- liftIO $ debug "parseForm: got application/x-www-form-urlencoded"- liftIO $ debug "parseForm: reading POST body"- senum <- liftIO $ readIORef $ rqBody req- let (SomeEnumerator enum) = senum- consumeStep <- liftIO $ runIteratee consume- step <- liftIO $- runIteratee $- joinI $ takeNoMoreThan maximumPOSTBodySize consumeStep- body <- liftM S.concat $ lift $ enum step- let newParams = parseUrlEncoded body-- liftIO $ debug "parseForm: stuffing 'enumBS body' into request"-- let e = enumBS body >==> I.joinI . I.take 0-- let e' = \st -> do- let ii = iterateeDebugWrapper "regurgitate body" (returnI st)- st' <- lift $ runIteratee ii- e st'-- liftIO $ writeIORef (rqBody req) $ SomeEnumerator e'- return $ req { rqParams = rqParams req `mappend` newParams }--- --------------------------------------------------------------------------- toRequest (IRequest method uri version kvps) =- {-# SCC "receiveRequest/toRequest" #-} do- localAddr <- gets $ localAddress . _sessionPort- lport <- gets $ localPort . _sessionPort- remoteAddr <- gets $ remoteAddress . _sessionPort- rport <- gets $ remotePort . _sessionPort- localHostname <- gets $ _localHostname- secure <- gets $ isSecure . _sessionPort-- let (serverName, serverPort) = fromMaybe- (localHostname, lport)- (liftM (parseHost . head)- (Map.lookup "host" hdrs))-- -- will override in "setEnumerator"- enum <- liftIO $ newIORef $ SomeEnumerator (enumBS "")--- return $ Request serverName- serverPort- remoteAddr- rport- localAddr- lport- localHostname- secure- hdrs- enum- mbContentLength- method- version- cookies- snapletPath- pathInfo- contextPath- uri- queryString- params-- where- snapletPath = "" -- TODO: snaplets in v0.2-- dropLeadingSlash s = maybe s f mbS- where- f (a,s') = if a == c2w '/' then s' else s- mbS = S.uncons s-- hdrs = toHeaders kvps-- mbContentLength = liftM (Cvt.int . head) $- Map.lookup "content-length" hdrs-- cookies = concat $- maybe []- (catMaybes . map parseCookie)- (Map.lookup "cookie" hdrs)-- contextPath = "/"-- parseHost h = (a, Cvt.int (S.drop 1 b))- where- (a,b) = S.break (== (c2w ':')) h-- params = parseUrlEncoded queryString-- (pathInfo, queryString) = first dropLeadingSlash . second (S.drop 1) $- S.break (== (c2w '?')) uri------------------------------------------------------------------------------------ Response must be well-formed here-sendResponse :: forall a . Request- -> Response- -> Step ByteString IO a -- ^ iteratee write end- -> (FilePath -> Int64 -> Int64 -> IO a) -- ^ function to call on- -- sendfile- -> ServerMonad (Int64, a)-sendResponse req rsp' writeEnd onSendFile = do- let rsp'' = renderCookies rsp'- rsp <- fixupResponse rsp''- let !headerString = mkHeaderString rsp-- (!x,!bs) <- case (rspBody rsp) of- (Enum e) -> lift $ whenEnum headerString rsp e- (SendFile f Nothing) -> lift $- whenSendFile headerString rsp f 0- (SendFile f (Just (st,_))) ->- lift $ whenSendFile headerString rsp f st-- debug "sendResponse: response sent"-- return $! (bs,x)-- where- --------------------------------------------------------------------------- whenEnum :: ByteString- -> Response- -> (forall x . Enumerator ByteString IO x)- -> Iteratee ByteString IO (a,Int64)- whenEnum hs rsp e = do- -- "enum" here has to be run in the context of the READ iteratee, even- -- though it's writing to the output, because we may be transforming- -- the input. That's why we check if we're transforming the request- -- body here, and if not, send EOF to the write end; so that it- -- doesn't join up with the read iteratee and try to get more data- -- from the socket.- let enum = if rspTransformingRqBody rsp- then enumBS hs >==> e- else enumBS hs >==> e >==> (joinI . I.take 0)-- let hl = fromIntegral $ S.length hs-- debug $ "sendResponse: whenEnum: enumerating bytes"-- outstep <- lift $ runIteratee $- iterateeDebugWrapper "countBytes writeEnd" $- countBytes $ returnI writeEnd- (x,bs) <- enum outstep- debug $ "sendResponse: whenEnum: " ++ Prelude.show bs ++- " bytes enumerated"-- return (x, bs-hl)--- --------------------------------------------------------------------------- whenSendFile :: ByteString -- ^ headers- -> Response- -> FilePath -- ^ file to send- -> Int64 -- ^ start byte offset- -> Iteratee ByteString IO (a,Int64)- whenSendFile hs r f start = do- -- Guaranteed to have a content length here. Sending EOF through to- -- the write end guarantees that we flush the buffer before we send- -- the file with sendfile().- lift $ runIteratee $ (enumBS hs >==> enumEOF) writeEnd-- let !cl = fromJust $ rspContentLength r- x <- liftIO $ onSendFile f start cl- return (x, cl)--- --------------------------------------------------------------------------- (major,minor) = rspHttpVersion rsp'--- --------------------------------------------------------------------------- putHdrs hdrs =- {-# SCC "putHdrs" #-}- Prelude.mapM_ putHeader $ Map.toList hdrs- where- putHeader (k, ys) = Prelude.mapM_ (putOne k) ys-- putOne k y = do- putByteString $ unCI k- putByteString ": "- putByteString y- putByteString "\r\n"--- --------------------------------------------------------------------------- noCL :: Response -> ServerMonad Response- noCL r =- {-# SCC "noCL" #-}- do- -- are we in HTTP/1.1?- let sendChunked = (rspHttpVersion r) == (1,1)- if sendChunked- then do- let r' = setHeader "Transfer-Encoding" "chunked" r- let origE = rspBodyToEnum $ rspBody r-- let e i = do- step <- lift $ runIteratee $ joinI $- writeChunkedTransferEncoding i- origE step-- return $ r' { rspBody = Enum e }-- else do- -- HTTP/1.0 and no content-length? We'll have to close the- -- socket.- modify $! \s -> s { _forceConnectionClose = True }- return $ setHeader "Connection" "close" r--- --------------------------------------------------------------------------- hasCL :: Int64 -> Response -> ServerMonad Response- hasCL cl r =- {-# SCC "hasCL" #-}- do- -- set the content-length header- let r' = setHeader "Content-Length" (l2s $ show cl) r- let b = case (rspBody r') of- (Enum e) -> Enum (i e)- (SendFile f m) -> SendFile f m-- return $ r' { rspBody = b }-- where- i :: forall z . Enumerator ByteString IO z- -> Enumerator ByteString IO z- i enum step = do- step' <- lift $ runIteratee $ joinI $ takeExactly cl step- enum step'--- --------------------------------------------------------------------------- setFileSize :: FilePath -> Response -> ServerMonad Response- setFileSize fp r =- {-# SCC "setFileSize" #-}- do- fs <- liftM fromIntegral $ liftIO $ getFileSize fp- return $ r { rspContentLength = Just fs }--- --------------------------------------------------------------------------- handle304 :: Response -> Response- handle304 r = setResponseBody (enumBS "") $- updateHeaders (Map.delete "Transfer-Encoding") $- setContentLength 0 r--- --------------------------------------------------------------------------- renderCookies :: Response -> Response- renderCookies r = updateHeaders f r- where- f h = Map.insert "Set-Cookie" cookies h- cookies = fmap cookieToBS . Map.elems $ rspCookies r-- --------------------------------------------------------------------------- fixupResponse :: Response -> ServerMonad Response- fixupResponse r = {-# SCC "fixupResponse" #-} do- let r' = deleteHeader "Content-Length" r-- let code = rspStatus r'-- let r'' = if code == 204 || code == 304- then handle304 r'- else r'-- r''' <- do- z <- case (rspBody r'') of- (Enum _) -> return r''- (SendFile f Nothing) -> setFileSize f r''- (SendFile _ (Just (s,e))) -> return $- setContentLength (e-s) r''-- case (rspContentLength z) of- Nothing -> noCL z- (Just sz) -> hasCL sz z-- -- HEAD requests cannot have bodies per RFC 2616 sec. 9.4- if rqMethod req == HEAD- then return $ deleteHeader "Transfer-Encoding"- $ r''' { rspBody = Enum $ enumBS "" }- else return r'''--- --------------------------------------------------------------------------- mkHeaderString :: Response -> ByteString- mkHeaderString r = out- where- !out = {-# SCC "mkHeaderString" #-}- S.concat $ L.toChunks $ runPut $ do- putByteString "HTTP/"- showp major- putAscii '.'- showp minor- putAscii ' '- showp $ rspStatus r- putAscii ' '- putByteString $ rspStatusReason r- putByteString "\r\n"- putHdrs $ headers r- putByteString "\r\n"----------------------------------------------------------------------------------checkConnectionClose :: (Int, Int) -> Headers -> ServerMonad ()-checkConnectionClose ver hdrs =- -- For HTTP/1.1:- -- if there is an explicit Connection: close, close the socket.- -- For HTTP/1.0:- -- if there is no explicit Connection: Keep-Alive, close the socket.- if (ver == (1,1) && l == Just ["close"]) ||- (ver == (1,0) && l /= Just ["keep-alive"])- then modify $ \s -> s { _forceConnectionClose = True }- else return ()- where- l = liftM (map tl) $ Map.lookup "Connection" hdrs- tl = S.map (c2w . toLower . w2c)------------------------------------------------------------------------------------ FIXME: whitespace-trim the values here.-toHeaders :: [(ByteString,ByteString)] -> Headers-toHeaders kvps = foldl' f Map.empty kvps'- where- kvps' = map (first toCI . second (:[])) kvps- f m (k,v) = Map.insertWith' (flip (++)) k v m------------------------------------------------------------------------------------ | Convert 'Cookie' into 'ByteString' for output.-cookieToBS :: Cookie -> ByteString-cookieToBS (Cookie k v mbExpTime mbDomain mbPath) = cookie- where- cookie = S.concat [k, "=", v, path, exptime, domain]- path = maybe "" (S.append "; path=") mbPath- domain = maybe "" (S.append "; domain=") mbDomain- exptime = maybe "" (S.append "; expires=" . fmt) mbExpTime- fmt = fromStr . formatTime defaultTimeLocale "%a, %d-%b-%Y %H:%M:%S GMT"----------------------------------------------------------------------------------getFileSize :: FilePath -> IO FileOffset-getFileSize fp = liftM fileSize $ getFileStatus fp----------------------------------------------------------------------------------l2s :: L.ByteString -> S.ByteString-l2s = S.concat . L.toChunks----------------------------------------------------------------------------------toBS :: String -> ByteString-toBS = S.pack . map c2w
+ src/Snap/Internal/Http/Server/Address.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}++module Snap.Internal.Http.Server.Address+ ( getHostAddr+ , getHostAddrImpl+ , getSockAddr+ , getSockAddrImpl+ , getAddress+ , getAddressImpl+ , AddressNotSupportedException(..)+ ) where++------------------------------------------------------------------------------+#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif+import Control.Exception (Exception, throwIO)+import Control.Monad (liftM)+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import Data.Maybe (fromMaybe)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Typeable (Typeable)+import Network.Socket (AddrInfo (addrAddress, addrFamily, addrFlags, addrSocketType), AddrInfoFlag (AI_NUMERICSERV, AI_PASSIVE), Family (AF_INET, AF_INET6), HostName, NameInfoFlag (NI_NUMERICHOST), ServiceName, SockAddr (SockAddrInet, SockAddrInet6, SockAddrUnix), SocketType (Stream), defaultHints, getAddrInfo, getNameInfo)+++------------------------------------------------------------------------------+data AddressNotSupportedException = AddressNotSupportedException String+ deriving (Typeable)++instance Show AddressNotSupportedException where+ show (AddressNotSupportedException x) = "Address not supported: " ++ x++instance Exception AddressNotSupportedException++------------------------------------------------------------------------------+getHostAddr :: SockAddr -> IO String+getHostAddr = getHostAddrImpl getNameInfo+++------------------------------------------------------------------------------+getHostAddrImpl :: ([NameInfoFlag]+ -> Bool+ -> Bool+ -> SockAddr+ -> IO (Maybe HostName, Maybe ServiceName))+ -> SockAddr+ -> IO String+getHostAddrImpl !_getNameInfo addr =+ (fromMaybe "" . fst) `liftM` _getNameInfo [NI_NUMERICHOST] True False addr+++------------------------------------------------------------------------------+getAddress :: SockAddr -> IO (Int, ByteString)+getAddress = getAddressImpl getHostAddr+++------------------------------------------------------------------------------+getAddressImpl :: (SockAddr -> IO String) -> SockAddr -> IO (Int, ByteString)+getAddressImpl !_getHostAddr addr =+ case addr of+ SockAddrInet p _ -> host (fromIntegral p)+ SockAddrInet6 p _ _ _ -> host (fromIntegral p)+ SockAddrUnix path -> return (-1, prefix path)+#if MIN_VERSION_network(2,6,0)+ _ -> fail "Unsupported address type"+#endif+ where+ prefix path = T.encodeUtf8 $! T.pack $ "unix:" ++ path+ host port = (,) port . S.pack <$> _getHostAddr addr+++------------------------------------------------------------------------------+getSockAddr :: Int+ -> ByteString+ -> IO (Family, SockAddr)+getSockAddr = getSockAddrImpl getAddrInfo+++------------------------------------------------------------------------------+getSockAddrImpl+ :: (Maybe AddrInfo -> Maybe String -> Maybe String -> IO [AddrInfo])+ -> Int -> ByteString -> IO (Family, SockAddr)+getSockAddrImpl !_getAddrInfo p s =+ case () of+ !_ | s == "*" -> getAddrs isIPv4 (Just wildhints) Nothing (Just $ show p)+ | s == "::" -> getAddrs isIPv6 (Just wildhints) Nothing (Just $ show p)+ | otherwise -> getAddrs (const True) (Just hints) (Just $ S.unpack s) (Just $ show p)++ where+ isIPv4 ai = addrFamily ai == AF_INET+ isIPv6 ai = addrFamily ai == AF_INET6++ getAddrs flt a b c = do+ ais <- filter flt <$> _getAddrInfo a b c+ if null ais+ then throwIO $ AddressNotSupportedException $ show s+ else do+ let ai = head ais+ let fm = addrFamily ai+ let sa = addrAddress ai+ return (fm, sa)++ wildhints = hints { addrFlags = [AI_NUMERICSERV, AI_PASSIVE] }+ hints = defaultHints { addrFlags = [AI_NUMERICSERV]+ , addrSocketType = Stream+ }
− src/Snap/Internal/Http/Server/Backend.hs
@@ -1,93 +0,0 @@-module Snap.Internal.Http.Server.Backend where--{---The server backend is made up of two APIs.--+ The ListenSocket class abstracts the reading and writing from the network.- We have seperate implementations of ListenSocket for http and https.--+ The EventLoop function is the interface to accept on the socket.- The EventLoop function will listen on the ports, and for each accepted- connection it wil call the SessionHandler.---}--import Data.ByteString (ByteString)-import Foreign-import Foreign.C-import Network.Socket (Socket)-import Snap.Iteratee (Iteratee, Enumerator)----------------------------------------------------------------------------------data SessionInfo = SessionInfo- { localAddress :: ByteString- , localPort :: Int- , remoteAddress :: ByteString- , remotePort :: Int- , isSecure :: Bool- }----------------------------------------------------------------------------------type SessionHandler =- SessionInfo -- ^ session port information- -> Enumerator ByteString IO () -- ^ read end of socket- -> Iteratee ByteString IO () -- ^ write end of socket- -> (FilePath -> Int64 -> Int64 -> IO ()) -- ^ sendfile end- -> IO () -- ^ timeout tickler- -> IO ()----------------------------------------------------------------------------------type EventLoop = [ListenSocket] -- ^ list of ports- -> Int -- ^ number of capabilities- -> (ByteString -> IO ()) -- ^ error log- -> SessionHandler -- ^ session handler- -> IO ()---{- For performance reasons, we do not implement this as a class-class ListenSocket a where- data ListenSocketSession a :: *-- listenSocket :: a -> Socket- isSecure :: a -> Bool-- closePort :: a -> IO ()-- createSession :: a- -> Int -- ^ recv buffer size- -> CInt -- ^ network socket- -> IO () -- ^ action to block waiting for handshake- -> IO (ListenSocketSession a)-- endSession :: a -> ListenSocketSession a -> IO ()-- recv :: a- -> IO () -- ^ action to block waiting for data- -> ListenSocketSession a -- ^ session- -> IO (Maybe ByteString)-- send :: a- -> IO () -- ^ action to tickle the timeout- -> IO () -- ^ action to block waiting for data- -> ListenSocketSession a -- ^ session- -> ByteString -- ^ data to send- -> IO ()--}----------------------------------------------------------------------------------data ListenSocket = ListenHttp Socket- | ListenHttps Socket (Ptr Word) (Ptr Word)----------------------------------------------------------------------------------data NetworkSession = NetworkSession- { _socket :: CInt- , _session :: Ptr Word- , _recvBuffer :: Ptr CChar- , _recvLen :: CSize- }
+ src/Snap/Internal/Http/Server/Clock.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Snap.Internal.Http.Server.Clock+ ( ClockTime+ , getClockTime+ , sleepFor+ , sleepSecs+ , fromSecs+ , toSecs+ ) where++import Control.Concurrent (threadDelay)+import qualified System.Clock as Clock++type ClockTime = Clock.TimeSpec++------------------------------------------------------------------------------+sleepFor :: ClockTime -> IO ()+sleepFor t = threadDelay $ fromIntegral d+ where+ d = (Clock.nsec t `div` 1000) + (1000000 * Clock.sec t)+++------------------------------------------------------------------------------+sleepSecs :: Double -> IO ()+sleepSecs = sleepFor . fromSecs+++------------------------------------------------------------------------------+getClockTime :: IO ClockTime+getClockTime = Clock.getTime Clock.Monotonic+++------------------------------------------------------------------------------+fromSecs :: Double -> ClockTime+fromSecs d = let (s, r) = properFraction d+ in Clock.TimeSpec s (truncate $! 1000000000 * r)+++------------------------------------------------------------------------------+toSecs :: ClockTime -> Double+toSecs t = fromIntegral (Clock.sec t) ++ fromIntegral (Clock.nsec t) / 1000000000.0
+ src/Snap/Internal/Http/Server/Common.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}++module Snap.Internal.Http.Server.Common+ ( atomicModifyIORef'+ , eatException+ ) where++import Control.Exception (SomeException, catch)+import Control.Monad (void)+import Prelude (IO, return, ($!))++#if MIN_VERSION_base(4,6,0)+------------------------------------------------------------------------------+import Data.IORef (atomicModifyIORef')++#else+------------------------------------------------------------------------------+import Data.IORef (IORef, atomicModifyIORef)+import Prelude (seq)+++------------------------------------------------------------------------------+-- | Strict version of 'atomicModifyIORef'. This forces both the value stored+-- in the 'IORef' as well as the value returned.+atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b+atomicModifyIORef' ref f = do+ b <- atomicModifyIORef ref+ (\x -> let (a, b) = f x+ in (a, a `seq` b))+ b `seq` return b+#endif+++------------------------------------------------------------------------------+eatException :: IO a -> IO ()+eatException m = void m `catch` f+ where+ f :: SomeException -> IO ()+ f !_ = return $! ()
+ src/Snap/Internal/Http/Server/Config.hs view
@@ -0,0 +1,856 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+------------------------------------------------------------------------------+-- | This module exports the 'Config' datatype, which you can use to configure+-- the Snap HTTP server.+--+module Snap.Internal.Http.Server.Config+ -- NOTE: also edit Snap.Http.Server.Config if you change these+ ( ConfigLog(..)+ , Config(..)+ , ProxyType(..)++ , emptyConfig+ , defaultConfig++ , commandLineConfig+ , extendedCommandLineConfig+ , completeConfig++ , optDescrs+ , fmapOpt++ , getAccessLog+ , getBind+ , getCompression+ , getDefaultTimeout+ , getErrorHandler+ , getErrorLog+ , getHostname+ , getLocale+ , getOther+ , getPort+ , getProxyType+ , getSSLBind+ , getSSLCert+ , getSSLChainCert+ , getSSLKey+ , getSSLPort+ , getVerbose+ , getStartupHook+ , getUnixSocket+ , getUnixSocketAccessMode++ , setAccessLog+ , setBind+ , setCompression+ , setDefaultTimeout+ , setErrorHandler+ , setErrorLog+ , setHostname+ , setLocale+ , setOther+ , setPort+ , setProxyType+ , setSSLBind+ , setSSLCert+ , setSSLChainCert+ , setSSLKey+ , setSSLPort+ , setVerbose+ , setUnixSocket+ , setUnixSocketAccessMode++ , setStartupHook++ , StartupInfo(..)+ , getStartupSockets+ , getStartupConfig++ -- * Private+ , emptyStartupInfo+ , setStartupSockets+ , setStartupConfig+ ) where++------------------------------------------------------------------------------+import Control.Exception (SomeException)+import Control.Monad (when)+import Data.Bits ((.&.))+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.CaseInsensitive as CI+import Data.Function (on)+import Data.List (foldl')+import qualified Data.Map as Map+import Data.Maybe (isJust, isNothing)+#if !MIN_VERSION_base(4,8,0)+import Data.Monoid (Monoid (..))+#endif+import Data.Monoid (Last (Last, getLast))+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup (Semigroup (..))+#endif+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+#if MIN_VERSION_base(4,7,0)+import Data.Typeable (Typeable)+#else+import Data.Typeable (TyCon, Typeable, Typeable1 (..), mkTyCon3, mkTyConApp)+#endif+import Network.Socket (Socket)+import Numeric (readOct, showOct)+#if !MIN_VERSION_base(4,6,0)+import Prelude hiding (catch)+#endif+import System.Console.GetOpt (ArgDescr (..), ArgOrder (Permute), OptDescr (..), getOpt, usageInfo)+import System.Environment hiding (getEnv)+#ifndef PORTABLE+import Data.Char (isAlpha)+import System.Posix.Env (getEnv)+#endif+import System.Exit (exitFailure)+import System.IO (hPutStrLn, stderr)+------------------------------------------------------------------------------+import Data.ByteString.Builder (Builder, byteString, stringUtf8, toLazyByteString)+import qualified System.IO.Streams as Streams+------------------------------------------------------------------------------+import Snap.Core (MonadSnap, Request (rqClientAddr, rqClientPort, rqParams, rqPostParams), emptyResponse, finishWith, getsRequest, logError, setContentLength, setContentType, setResponseBody, setResponseStatus)+import Snap.Internal.Debug (debug)+++------------------------------------------------------------------------------+-- | FIXME+--+-- Note: this type changed in snap-server 1.0.0.0.+data ProxyType = NoProxy+ | HaProxy+ | X_Forwarded_For+ deriving (Show, Eq, Typeable)++------------------------------------------------------------------------------+-- | Data type representing the configuration of a logging target+data ConfigLog = ConfigNoLog -- ^ no logging+ | ConfigFileLog FilePath -- ^ log to text file+ | ConfigIoLog (ByteString -> IO ()) -- ^ log custom IO handler++instance Show ConfigLog where+ show ConfigNoLog = "no log"+ show (ConfigFileLog f) = "log to file " ++ show f+ show (ConfigIoLog _) = "custom logging handler"+++------------------------------------------------------------------------------+-- We should be using ServerConfig here. There needs to be a clearer+-- separation between:+--+-- * what the underlying code needs to configure itself+--+-- * what the command-line processing does.+--+-- The latter will provide "library" helper functions that operate on+-- ServerConfig/etc in order to allow users to configure their own environment.+--+--+-- Todo:+--+-- * need a function ::+-- CommandLineConfig -> IO [(ServerConfig hookState, AcceptFunc)]+--+-- this will prep for another function that will spawn all of the+-- accept loops with httpAcceptLoop.+--+-- * all backends provide "Some -> Foo -> Config -> IO AcceptFunc"+--+-- * add support for socket activation to command line, or delegate to+-- different library? It's linux-only anyways, need to ifdef. It would be+-- silly to depend on the socket-activation library for that one little+-- function.+--+-- * break config into multiple modules:+--+-- * everything that modifies the snap handler (compression, proxy+-- settings, error handler)+--+-- * everything that directly modifies server settings (hostname /+-- defaultTimeout / hooks / etc)+--+-- * everything that configures backends (port/bind/ssl*)+--+-- * everything that handles command line stuff+--+-- * utility stuff+--+-- Cruft that definitely must be removed:+--+-- * ConfigLog -- this becomes a binary option on the command-line side (no+-- logging or yes, to this file), but the ConfigIoLog gets zapped+-- altogether.++------------------------------------------------------------------------------+-- | A record type which represents partial configurations (for 'httpServe')+-- by wrapping all of its fields in a 'Maybe'. Values of this type are usually+-- constructed via its 'Monoid' instance by doing something like:+--+-- > setPort 1234 mempty+--+-- Any fields which are unspecified in the 'Config' passed to 'httpServe' (and+-- this is the norm) are filled in with default values from 'defaultConfig'.+data Config m a = Config+ { hostname :: Maybe ByteString+ , accessLog :: Maybe ConfigLog+ , errorLog :: Maybe ConfigLog+ , locale :: Maybe String+ , port :: Maybe Int+ , bind :: Maybe ByteString+ , sslport :: Maybe Int+ , sslbind :: Maybe ByteString+ , sslcert :: Maybe FilePath+ , sslchaincert :: Maybe Bool+ , sslkey :: Maybe FilePath+ , unixsocket :: Maybe FilePath+ , unixaccessmode :: Maybe Int+ , compression :: Maybe Bool+ , verbose :: Maybe Bool+ , errorHandler :: Maybe (SomeException -> m ())+ , defaultTimeout :: Maybe Int+ , other :: Maybe a+ , proxyType :: Maybe ProxyType+ , startupHook :: Maybe (StartupInfo m a -> IO ())+ }+#if MIN_VERSION_base(4,7,0)+ deriving Typeable+#else++------------------------------------------------------------------------------+-- | The 'Typeable1' instance is here so 'Config' values can be+-- dynamically loaded with Hint.+configTyCon :: TyCon+configTyCon = mkTyCon3 "snap-server" "Snap.Http.Server.Config" "Config"+{-# NOINLINE configTyCon #-}++instance (Typeable1 m) => Typeable1 (Config m) where+ typeOf1 _ = mkTyConApp configTyCon [typeOf1 (undefined :: m ())]+#endif+++instance Show (Config m a) where+ show c = unlines [ "Config:"+ , "hostname: " ++ _hostname+ , "accessLog: " ++ _accessLog+ , "errorLog: " ++ _errorLog+ , "locale: " ++ _locale+ , "port: " ++ _port+ , "bind: " ++ _bind+ , "sslport: " ++ _sslport+ , "sslbind: " ++ _sslbind+ , "sslcert: " ++ _sslcert+ , "sslchaincert: " ++ _sslchaincert+ , "sslkey: " ++ _sslkey+ , "unixsocket: " ++ _unixsocket+ , "unixaccessmode: " ++ _unixaccessmode+ , "compression: " ++ _compression+ , "verbose: " ++ _verbose+ , "defaultTimeout: " ++ _defaultTimeout+ , "proxyType: " ++ _proxyType+ ]++ where+ _hostname = show $ hostname c+ _accessLog = show $ accessLog c+ _errorLog = show $ errorLog c+ _locale = show $ locale c+ _port = show $ port c+ _bind = show $ bind c+ _sslport = show $ sslport c+ _sslbind = show $ sslbind c+ _sslcert = show $ sslcert c+ _sslchaincert = show $ sslchaincert c+ _sslkey = show $ sslkey c+ _compression = show $ compression c+ _verbose = show $ verbose c+ _defaultTimeout = show $ defaultTimeout c+ _proxyType = show $ proxyType c+ _unixsocket = show $ unixsocket c+ _unixaccessmode = case unixaccessmode c of+ Nothing -> "Nothing"+ Just s -> ("Just 0" ++) . showOct s $ []+++------------------------------------------------------------------------------+-- | Returns a completely empty 'Config'. Equivalent to 'mempty' from+-- 'Config''s 'Monoid' instance.+emptyConfig :: Config m a+emptyConfig = mempty+++------------------------------------------------------------------------------+instance Semigroup (Config m a) where+ a <> b = Config+ { hostname = ov hostname+ , accessLog = ov accessLog+ , errorLog = ov errorLog+ , locale = ov locale+ , port = ov port+ , bind = ov bind+ , sslport = ov sslport+ , sslbind = ov sslbind+ , sslcert = ov sslcert+ , sslchaincert = ov sslchaincert+ , sslkey = ov sslkey+ , unixsocket = ov unixsocket+ , unixaccessmode = ov unixaccessmode+ , compression = ov compression+ , verbose = ov verbose+ , errorHandler = ov errorHandler+ , defaultTimeout = ov defaultTimeout+ , other = ov other+ , proxyType = ov proxyType+ , startupHook = ov startupHook+ }+ where+ ov :: (Config m a -> Maybe b) -> Maybe b+ ov f = getLast $! (mappend `on` (Last . f)) a b+++instance Monoid (Config m a) where+ mempty = Config+ { hostname = Nothing+ , accessLog = Nothing+ , errorLog = Nothing+ , locale = Nothing+ , port = Nothing+ , bind = Nothing+ , sslport = Nothing+ , sslbind = Nothing+ , sslcert = Nothing+ , sslchaincert = Nothing+ , sslkey = Nothing+ , unixsocket = Nothing+ , unixaccessmode = Nothing+ , compression = Nothing+ , verbose = Nothing+ , errorHandler = Nothing+ , defaultTimeout = Nothing+ , other = Nothing+ , proxyType = Nothing+ , startupHook = Nothing+ }++#if !MIN_VERSION_base(4,11,0)+ mappend = (<>)+#endif+++------------------------------------------------------------------------------+-- | These are the default values for the options+defaultConfig :: MonadSnap m => Config m a+defaultConfig = mempty+ { hostname = Just "localhost"+ , accessLog = Just $ ConfigFileLog "log/access.log"+ , errorLog = Just $ ConfigFileLog "log/error.log"+ , locale = Just "en_US"+ , compression = Just True+ , verbose = Just True+ , errorHandler = Just defaultErrorHandler+ , bind = Just "0.0.0.0"+ , sslbind = Nothing+ , sslcert = Nothing+ , sslkey = Nothing+ , sslchaincert = Nothing+ , defaultTimeout = Just 60+ }+++------------------------------------------------------------------------------+-- | The hostname of the HTTP server. This field has the same format as an HTTP+-- @Host@ header; if a @Host@ header came in with the request, we use that,+-- otherwise we default to this value specified in the configuration.+getHostname :: Config m a -> Maybe ByteString+getHostname = hostname++-- | Path to the access log+getAccessLog :: Config m a -> Maybe ConfigLog+getAccessLog = accessLog++-- | Path to the error log+getErrorLog :: Config m a -> Maybe ConfigLog+getErrorLog = errorLog++-- | Gets the locale to use. Locales are used on Unix only, to set the+-- @LANG@\/@LC_ALL@\/etc. environment variable. For instance if you set the+-- locale to \"@en_US@\", we'll set the relevant environment variables to+-- \"@en_US.UTF-8@\".+getLocale :: Config m a -> Maybe String+getLocale = locale++-- | Returns the port to listen on (for http)+getPort :: Config m a -> Maybe Int+getPort = port++-- | Returns the address to bind to (for http)+getBind :: Config m a -> Maybe ByteString+getBind = bind++-- | Returns the port to listen on (for https)+getSSLPort :: Config m a -> Maybe Int+getSSLPort = sslport++-- | Returns the address to bind to (for https)+getSSLBind :: Config m a -> Maybe ByteString+getSSLBind = sslbind++-- | Path to the SSL certificate file+getSSLCert :: Config m a -> Maybe FilePath+getSSLCert = sslcert++-- | Path to the SSL certificate file+getSSLChainCert :: Config m a -> Maybe Bool+getSSLChainCert = sslchaincert++-- | Path to the SSL key file+getSSLKey :: Config m a -> Maybe FilePath+getSSLKey = sslkey++-- | File path to unix socket. Must be absolute path, but allows for symbolic+-- links.+getUnixSocket :: Config m a -> Maybe FilePath+getUnixSocket = unixsocket++-- | Access mode for unix socket, by default is system specific.+-- This should only be used to grant additional permissions to created+-- socket file, and not to remove permissions set by default.+-- The only portable way to limit access to socket is creating it in a+-- directory with proper permissions set.+--+-- Most BSD systems ignore access permissions on unix sockets.+--+-- Note: This uses umask. There is a race condition if process creates other+-- files at the same time as opening a unix socket with this option set.+getUnixSocketAccessMode :: Config m a -> Maybe Int+getUnixSocketAccessMode = unixaccessmode++-- | If set and set to True, compression is turned on when applicable+getCompression :: Config m a -> Maybe Bool+getCompression = compression++-- | Whether to write server status updates to stderr+getVerbose :: Config m a -> Maybe Bool+getVerbose = verbose++-- | A MonadSnap action to handle 500 errors+getErrorHandler :: Config m a -> Maybe (SomeException -> m ())+getErrorHandler = errorHandler++getDefaultTimeout :: Config m a -> Maybe Int+getDefaultTimeout = defaultTimeout++getOther :: Config m a -> Maybe a+getOther = other++getProxyType :: Config m a -> Maybe ProxyType+getProxyType = proxyType++-- | A startup hook is run after the server initializes but before user request+-- processing begins. The server passes, through a 'StartupInfo' object, the+-- startup hook a list of the sockets it is listening on and the final 'Config'+-- object completed after command-line processing.+getStartupHook :: Config m a -> Maybe (StartupInfo m a -> IO ())+getStartupHook = startupHook+++------------------------------------------------------------------------------+setHostname :: ByteString -> Config m a -> Config m a+setHostname x c = c { hostname = Just x }++setAccessLog :: ConfigLog -> Config m a -> Config m a+setAccessLog x c = c { accessLog = Just x }++setErrorLog :: ConfigLog -> Config m a -> Config m a+setErrorLog x c = c { errorLog = Just x }++setLocale :: String -> Config m a -> Config m a+setLocale x c = c { locale = Just x }++setPort :: Int -> Config m a -> Config m a+setPort x c = c { port = Just x }++setBind :: ByteString -> Config m a -> Config m a+setBind x c = c { bind = Just x }++setSSLPort :: Int -> Config m a -> Config m a+setSSLPort x c = c { sslport = Just x }++setSSLBind :: ByteString -> Config m a -> Config m a+setSSLBind x c = c { sslbind = Just x }++setSSLCert :: FilePath -> Config m a -> Config m a+setSSLCert x c = c { sslcert = Just x }++setSSLChainCert :: Bool -> Config m a -> Config m a+setSSLChainCert x c = c { sslchaincert = Just x }++setSSLKey :: FilePath -> Config m a -> Config m a+setSSLKey x c = c { sslkey = Just x }++setUnixSocket :: FilePath -> Config m a -> Config m a+setUnixSocket x c = c { unixsocket = Just x }++setUnixSocketAccessMode :: Int -> Config m a -> Config m a+setUnixSocketAccessMode p c = c { unixaccessmode = Just ( p .&. 0o777) }++setCompression :: Bool -> Config m a -> Config m a+setCompression x c = c { compression = Just x }++setVerbose :: Bool -> Config m a -> Config m a+setVerbose x c = c { verbose = Just x }++setErrorHandler :: (SomeException -> m ()) -> Config m a -> Config m a+setErrorHandler x c = c { errorHandler = Just x }++setDefaultTimeout :: Int -> Config m a -> Config m a+setDefaultTimeout x c = c { defaultTimeout = Just x }++setOther :: a -> Config m a -> Config m a+setOther x c = c { other = Just x }++setProxyType :: ProxyType -> Config m a -> Config m a+setProxyType x c = c { proxyType = Just x }++setStartupHook :: (StartupInfo m a -> IO ()) -> Config m a -> Config m a+setStartupHook x c = c { startupHook = Just x }+++------------------------------------------------------------------------------++-- | Arguments passed to 'setStartupHook'.+data StartupInfo m a = StartupInfo+ { startupHookConfig :: Config m a+ , startupHookSockets :: [Socket]+ }++emptyStartupInfo :: StartupInfo m a+emptyStartupInfo = StartupInfo emptyConfig []++-- | The 'Socket's opened by the server. There will be two 'Socket's for SSL+-- connections, and one otherwise.+getStartupSockets :: StartupInfo m a -> [Socket]+getStartupSockets = startupHookSockets++-- The 'Config', after any command line parsing has been performed.+getStartupConfig :: StartupInfo m a -> Config m a+getStartupConfig = startupHookConfig++setStartupSockets :: [Socket] -> StartupInfo m a -> StartupInfo m a+setStartupSockets x c = c { startupHookSockets = x }++setStartupConfig :: Config m a -> StartupInfo m a -> StartupInfo m a+setStartupConfig x c = c { startupHookConfig = x }+++------------------------------------------------------------------------------+completeConfig :: (MonadSnap m) => Config m a -> IO (Config m a)+completeConfig config = do+ when noPort $ hPutStrLn stderr+ "no port specified, defaulting to port 8000"++ return $! cfg `mappend` cfg'++ where+ cfg = defaultConfig `mappend` config++ sslVals = map ($ cfg) [ isJust . getSSLPort+ , isJust . getSSLBind+ , isJust . getSSLKey+ , isJust . getSSLCert ]++ sslValid = and sslVals+ unixValid = isJust $ unixsocket cfg+ noPort = isNothing (getPort cfg) && not sslValid && not unixValid++ cfg' = emptyConfig { port = if noPort then Just 8000 else Nothing }+++------------------------------------------------------------------------------+bsFromString :: String -> ByteString+bsFromString = T.encodeUtf8 . T.pack+++------------------------------------------------------------------------------+toString :: ByteString -> String+toString = T.unpack . T.decodeUtf8+++------------------------------------------------------------------------------+-- | Returns a description of the snap command line options suitable for use+-- with "System.Console.GetOpt".+optDescrs :: forall m a . MonadSnap m =>+ Config m a -- ^ the configuration defaults.+ -> [OptDescr (Maybe (Config m a))]+optDescrs defaults =+ [ Option "" ["hostname"]+ (ReqArg (Just . setConfig setHostname . bsFromString) "NAME")+ $ "local hostname" ++ defaultC getHostname+ , Option "b" ["address"]+ (ReqArg (\s -> Just $ mempty { bind = Just $ bsFromString s })+ "ADDRESS")+ $ "address to bind to" ++ defaultO bind+ , Option "p" ["port"]+ (ReqArg (\s -> Just $ mempty { port = Just $ read s}) "PORT")+ $ "port to listen on" ++ defaultO port+ , Option "" ["ssl-address"]+ (ReqArg (\s -> Just $ mempty { sslbind = Just $ bsFromString s })+ "ADDRESS")+ $ "ssl address to bind to" ++ defaultO sslbind+ , Option "" ["ssl-port"]+ (ReqArg (\s -> Just $ mempty { sslport = Just $ read s}) "PORT")+ $ "ssl port to listen on" ++ defaultO sslport+ , Option "" ["ssl-cert"]+ (ReqArg (\s -> Just $ mempty { sslcert = Just s}) "PATH")+ $ "path to ssl certificate in PEM format" ++ defaultO sslcert+ , Option [] ["ssl-chain-cert"]+ (NoArg $ Just $ setConfig setSSLChainCert True)+ $ "certificate file contains complete certificate chain" ++ defaultB sslchaincert "site certificate only" "complete certificate chain"+ , Option [] ["no-ssl-chain-cert"]+ (NoArg $ Just $ setConfig setSSLChainCert False)+ $ "certificate file contains only the site certificate" ++ defaultB sslchaincert "site certificate only" "complete certificate chain"+ , Option [] ["ssl-key"]+ (ReqArg (\s -> Just $ mempty { sslkey = Just s}) "PATH")+ $ "path to ssl private key in PEM format" ++ defaultO sslkey+ , Option "" ["access-log"]+ (ReqArg (Just . setConfig setAccessLog . ConfigFileLog) "PATH")+ $ "access log" ++ defaultC getAccessLog+ , Option "" ["error-log"]+ (ReqArg (Just . setConfig setErrorLog . ConfigFileLog) "PATH")+ $ "error log" ++ defaultC getErrorLog+ , Option "" ["no-access-log"]+ (NoArg $ Just $ setConfig setAccessLog ConfigNoLog)+ "don't have an access log"+ , Option "" ["no-error-log"]+ (NoArg $ Just $ setConfig setErrorLog ConfigNoLog)+ "don't have an error log"+ , Option "c" ["compression"]+ (NoArg $ Just $ setConfig setCompression True)+ $ "use gzip compression on responses" +++ defaultB getCompression "compressed" "uncompressed"+ , Option "t" ["timeout"]+ (ReqArg (\t -> Just $ mempty {+ defaultTimeout = Just $ read t+ }) "SECS")+ $ "set default timeout in seconds" ++ defaultC defaultTimeout+ , Option "" ["no-compression"]+ (NoArg $ Just $ setConfig setCompression False)+ $ "serve responses uncompressed" +++ defaultB compression "compressed" "uncompressed"+ , Option "v" ["verbose"]+ (NoArg $ Just $ setConfig setVerbose True)+ $ "print server status updates to stderr" +++ defaultC getVerbose+ , Option "q" ["quiet"]+ (NoArg $ Just $ setConfig setVerbose False)+ $ "do not print anything to stderr" +++ defaultB getVerbose "verbose" "quiet"+ , Option "" ["proxy"]+ (ReqArg (Just . setConfig setProxyType . parseProxy . CI.mk)+ "X_Forwarded_For")+ $ concat [ "Set --proxy=X_Forwarded_For if your snap application \n"+ , "is behind an HTTP reverse proxy to ensure that \n"+ , "rqClientAddr is set properly.\n"+ , "Set --proxy=haproxy to use the haproxy protocol\n("+ , "http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt)"+ , defaultC getProxyType ]+ , Option "" ["unix-socket"]+ (ReqArg (Just . setConfig setUnixSocket) "PATH")+ $ concat ["Absolute path to unix socket file. "+ , "File will be removed if already exists"]+ , Option "" ["unix-socket-mode"]+ (ReqArg (Just . setConfig setUnixSocketAccessMode . parseOctal)+ "MODE")+ $ concat ["Access mode for unix socket in octal, for example 0760.\n"+ ," Default is system specific."]+ , Option "h" ["help"]+ (NoArg Nothing)+ "display this help and exit"+ ]++ where+ parseProxy s | s == "NoProxy" = NoProxy+ | s == "X_Forwarded_For" = X_Forwarded_For+ | s == "haproxy" = HaProxy+ | otherwise = error $ concat [+ "Error (--proxy): expected one of 'NoProxy', "+ , "'X_Forwarded_For', or 'haproxy'. Got '"+ , CI.original s+ , "'"+ ]+ parseOctal s = case readOct s of+ ((v, _):_) | v >= 0 && v <= 0o777 -> v+ _ -> error $ "Error (--unix-socket-mode): expected octal access mode"++ setConfig f c = f c mempty+ conf = defaultConfig `mappend` defaults++ defaultB :: (Config m a -> Maybe Bool) -> String -> String -> String+ defaultB f y n = (maybe "" (\b -> ", default " ++ if b+ then y+ else n) $ f conf) :: String++ defaultC :: (Show b) => (Config m a -> Maybe b) -> String+ defaultC f = maybe "" ((", default " ++) . show) $ f conf++ defaultO :: (Show b) => (Config m a -> Maybe b) -> String+ defaultO f = maybe ", default off" ((", default " ++) . show) $ f conf+++------------------------------------------------------------------------------+defaultErrorHandler :: MonadSnap m => SomeException -> m ()+defaultErrorHandler e = do+ debug "Snap.Http.Server.Config errorHandler:"+ req <- getsRequest blindParams+ let sm = smsg req+ debug $ toString sm+ logError sm++ finishWith $ setContentType "text/plain; charset=utf-8"+ . setContentLength (fromIntegral $ S.length msg)+ . setResponseStatus 500 "Internal Server Error"+ . setResponseBody errBody+ $ emptyResponse++ where+ blindParams r = r { rqPostParams = rmValues $ rqPostParams r+ , rqParams = rmValues $ rqParams r }+ rmValues = Map.map (const ["..."])++ errBody os = Streams.write (Just msgB) os >> return os++ toByteString = S.concat . L.toChunks . toLazyByteString+ smsg req = toByteString $ requestErrorMessage req e++ msg = toByteString msgB+ msgB = mconcat [+ byteString "A web handler threw an exception. Details:\n"+ , stringUtf8 $ show e+ ]+++------------------------------------------------------------------------------+-- | Returns a 'Config' obtained from parsing command-line options, using the+-- default Snap 'OptDescr' set.+--+-- On Unix systems, the locale is read from the @LANG@ environment variable.+commandLineConfig :: MonadSnap m+ => Config m a+ -- ^ default configuration. This is combined with+ -- 'defaultConfig' to obtain default values to use if the+ -- given parameter is specified on the command line.+ -- Usually it is fine to use 'emptyConfig' here.+ -> IO (Config m a)+commandLineConfig defaults = extendedCommandLineConfig (optDescrs defaults) f defaults+ where+ -- Here getOpt can ever change the "other" field, because we only use the+ -- Snap OptDescr list. The combining function will never be invoked.+ f = undefined+++------------------------------------------------------------------------------+-- | Returns a 'Config' obtained from parsing command-line options, using the+-- default Snap 'OptDescr' set as well as a list of user OptDescrs. User+-- OptDescrs use the \"other\" field (accessible using 'getOther' and+-- 'setOther') to store additional command-line option state. These are+-- combined using a user-defined combining function.+--+-- On Unix systems, the locale is read from the @LANG@ environment variable.++extendedCommandLineConfig :: MonadSnap m+ => [OptDescr (Maybe (Config m a))]+ -- ^ Full list of command line options (combine+ -- yours with 'optDescrs' to extend Snap's default+ -- set of options)+ -> (a -> a -> a)+ -- ^ State for multiple invoked user command-line+ -- options will be combined using this function.+ -> Config m a+ -- ^ default configuration. This is combined with+ -- Snap's 'defaultConfig' to obtain default values+ -- to use if the given parameter is specified on+ -- the command line. Usually it is fine to use+ -- 'emptyConfig' here.+ -> IO (Config m a)+extendedCommandLineConfig opts combiningFunction defaults = do+ args <- getArgs+ prog <- getProgName++ result <- either (usage prog)+ return+ (case getOpt Permute opts args of+ (f, _, [] ) -> maybe (Left []) Right $+ fmap (foldl' combine mempty) $+ sequence f+ (_, _, errs) -> Left errs)++#ifndef PORTABLE+ lang <- getEnv "LANG"+ completeConfig $ mconcat [defaults,+ mempty {locale = fmap upToUtf8 lang},+ result]+#else+ completeConfig $ mconcat [defaults, result]+#endif++ where+ usage prog errs = do+ let hdr = "Usage:\n " ++ prog ++ " [OPTION...]\n\nOptions:"+ let msg = concat errs ++ usageInfo hdr opts+ hPutStrLn stderr msg+ exitFailure+#ifndef PORTABLE+ upToUtf8 = takeWhile $ \c -> isAlpha c || '_' == c+#endif++ combine !a !b = a `mappend` b `mappend` newOther+ where+ -- combined is only a Just if both a and b have other fields, and then+ -- we use the combining function. Config's mappend picks the last+ -- "Just" in the other list.+ combined = do+ x <- getOther a+ y <- getOther b+ return $! combiningFunction x y++ newOther = mempty { other = combined }++fmapArg :: (a -> b) -> ArgDescr a -> ArgDescr b+fmapArg f (NoArg a) = NoArg (f a)+fmapArg f (ReqArg g s) = ReqArg (f . g) s+fmapArg f (OptArg g s) = OptArg (f . g) s++fmapOpt :: (a -> b) -> OptDescr a -> OptDescr b+fmapOpt f (Option s l d e) = Option s l (fmapArg f d) e+++------------------------------------------------------------------------------+requestErrorMessage :: Request -> SomeException -> Builder+requestErrorMessage req e =+ mconcat [ byteString "During processing of request from "+ , byteString $ rqClientAddr req+ , byteString ":"+ , fromShow $ rqClientPort req+ , byteString "\nrequest:\n"+ , fromShow $ show req+ , byteString "\n"+ , msgB+ ]+ where+ msgB = mconcat [+ byteString "A web handler threw an exception. Details:\n"+ , fromShow e+ ]++------------------------------------------------------------------------------+fromShow :: Show a => a -> Builder+fromShow = stringUtf8 . show
src/Snap/Internal/Http/Server/Date.hs view
@@ -1,131 +1,81 @@ {-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP #-} module Snap.Internal.Http.Server.Date-( getDateString-, getLogDateString-, getCurrentDateTime) where--import Control.Concurrent-import Control.Exception-import Control.Monad-import Data.ByteString (ByteString)-import Data.IORef-import Data.Maybe-import Foreign.C.Types-import System.IO.Unsafe-import System.PosixCompat.Time+ ( getDateString+ , getLogDateString+ ) where +------------------------------------------------------------------------------+import Control.Exception (mask_)+import Control.Monad (when)+import Data.ByteString (ByteString)+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import Foreign.C.Types (CTime)+import System.IO.Unsafe (unsafePerformIO)+import System.PosixCompat.Time (epochTime)+------------------------------------------------------------------------------ import Snap.Internal.Http.Types (formatHttpTime, formatLogTime) --- Here comes a dirty hack. We don't want to be wasting context switches--- building date strings, so we're only going to compute one every two--- seconds. (Approximate timestamps to within a couple of seconds are OK here,--- and we'll reduce overhead.)------ Note that we also don't want to wake up a potentially sleeping CPU by just--- running the computation on a timer. We'll allow client traffic to trigger--- the process. ------------------------------------------------------------------------------ data DateState = DateState { _cachedDateString :: !(IORef ByteString) , _cachedLogString :: !(IORef ByteString)- , _cachedDate :: !(IORef CTime)- , _valueIsOld :: !(IORef Bool)- , _morePlease :: !(MVar ())- , _dateThread :: !(MVar ThreadId)+ , _lastFetchTime :: !(IORef CTime) } ------------------------------------------------------------------------------ dateState :: DateState dateState = unsafePerformIO $ do- (s1,s2,date) <- fetchTime- bs1 <- newIORef s1- bs2 <- newIORef s2- dt <- newIORef date- ov <- newIORef False- th <- newEmptyMVar- mp <- newMVar ()-- let d = DateState bs1 bs2 dt ov mp th-- t <- forkIO $ dateThread d- putMVar th t+ (s1, s2, date) <- fetchTime+ bs1 <- newIORef $! s1+ bs2 <- newIORef $! s2+ dt <- newIORef $! date - return d+ return $! DateState bs1 bs2 dt+{-# NOINLINE dateState #-} ------------------------------------------------------------------------------ fetchTime :: IO (ByteString,ByteString,CTime) fetchTime = do- now <- epochTime- t1 <- formatHttpTime now- t2 <- formatLogTime now- return (t1, t2, now)+ !now <- epochTime+ !t1 <- formatHttpTime now+ !t2 <- formatLogTime now+ let !out = (t1, t2, now)+ return out ------------------------------------------------------------------------------ updateState :: DateState -> IO ()-updateState (DateState dateString logString time valueIsOld _ _) = do- (s1,s2,now) <- fetchTime- atomicModifyIORef dateString $ const (s1,())- atomicModifyIORef logString $ const (s2,())- atomicModifyIORef time $ const (now,())- writeIORef valueIsOld False-- -- force values in the iorefs to prevent thunk buildup- !_ <- readIORef dateString- !_ <- readIORef logString- !_ <- readIORef time-- return ()----------------------------------------------------------------------------------dateThread :: DateState -> IO ()-dateThread ds@(DateState _ _ _ valueIsOld morePlease _) = loop- where- loop = do- b <- tryTakeMVar morePlease- when (isNothing b) $ do- writeIORef valueIsOld True- takeMVar morePlease+updateState (DateState dateString logString time) = do+ (s1, s2, now) <- fetchTime+ writeIORef dateString $! s1+ writeIORef logString $! s2+ writeIORef time $! now - updateState ds- threadDelay 2000000- loop+ return $! () ------------------------------------------------------------------------------ ensureFreshDate :: IO ()-ensureFreshDate = block $ do- old <- readIORef $ _valueIsOld dateState- tryPutMVar (_morePlease dateState) ()-- -- if the value is not fresh we will tickle the date thread but also fetch- -- the new value immediately; we used to block but we'll do a little extra- -- work to avoid a delay- when old $ updateState dateState+ensureFreshDate = mask_ $ do+ now <- epochTime+ old <- readIORef $ _lastFetchTime dateState+ when (now > old) $! updateState dateState ------------------------------------------------------------------------------ getDateString :: IO ByteString-getDateString = block $ do+getDateString = mask_ $ do ensureFreshDate readIORef $ _cachedDateString dateState ------------------------------------------------------------------------------ getLogDateString :: IO ByteString-getLogDateString = block $ do+getLogDateString = mask_ $ do ensureFreshDate readIORef $ _cachedLogString dateState----------------------------------------------------------------------------------getCurrentDateTime :: IO CTime-getCurrentDateTime = block $ do- ensureFreshDate- readIORef $ _cachedDate dateState
− src/Snap/Internal/Http/Server/GnuTLS.hs
@@ -1,357 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE CPP #-}--module Snap.Internal.Http.Server.GnuTLS- ( GnuTLSException(..)- , initTLS- , stopTLS- , bindHttps- , freePort- , createSession- , endSession- , recv- , send- ) where----------------------------------------------------------------------------------import Control.Exception-import Data.ByteString (ByteString)-import Data.Dynamic-import Foreign.C--import Snap.Internal.Http.Server.Backend--#ifdef GNUTLS-import Control.Monad (liftM)-import qualified Data.ByteString as B-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)-import Data.ByteString.Internal (w2c)-import Foreign-import qualified Network.Socket as Socket-#endif----------------------------------------------------------------------------------data GnuTLSException = GnuTLSException String- deriving (Show, Typeable)-instance Exception GnuTLSException--#ifndef GNUTLS--initTLS :: IO ()-initTLS = throwIO $ GnuTLSException "TLS is not supported"--stopTLS :: IO ()-stopTLS = return ()--bindHttps :: ByteString -> Int -> FilePath -> FilePath -> IO ListenSocket-bindHttps _ _ _ _ = throwIO $ GnuTLSException "TLS is not supported"--freePort :: ListenSocket -> IO ()-freePort _ = return ()--createSession :: ListenSocket -> Int -> CInt -> IO () -> IO NetworkSession-createSession _ _ _ _ = throwIO $ GnuTLSException "TLS is not supported"--endSession :: NetworkSession -> IO ()-endSession _ = return ()--send :: IO () -> IO () -> NetworkSession -> ByteString -> IO ()-send _ _ _ _ = return ()--recv :: IO b -> NetworkSession -> IO (Maybe ByteString)-recv _ _ = throwIO $ GnuTLSException "TLS is not supported"--#else------------------------------------------------------------------------------------- | Init-initTLS :: IO ()-initTLS = gnutls_set_threading_helper >>- throwErrorIf "TLS init" gnutls_global_init-----------------------------------------------------------------------------------stopTLS :: IO ()-stopTLS = gnutls_global_deinit------------------------------------------------------------------------------------- | Binds ssl port-bindHttps :: ByteString- -> Int- -> FilePath- -> FilePath- -> IO ListenSocket-bindHttps bindAddress bindPort cert key = do- sock <- Socket.socket Socket.AF_INET Socket.Stream 0- addr <- getHostAddr bindPort bindAddress- Socket.setSocketOption sock Socket.ReuseAddr 1- Socket.bindSocket sock addr- Socket.listen sock 150-- creds <- loadCredentials cert key- dh <- regenerateDHParam creds-- return $ ListenHttps sock (castPtr creds) (castPtr dh)-----------------------------------------------------------------------------------loadCredentials :: FilePath --- ^ Path to certificate- -> FilePath --- ^ Path to key- -> IO (Ptr GnuTLSCredentials)-loadCredentials cert key = alloca $ \cPtr -> do- throwErrorIf "TLS allocate" $ gnutls_certificate_allocate_credentials cPtr- creds <- peek cPtr-- withCString cert $ \certstr -> withCString key $ \keystr ->- throwErrorIf "TLS set Certificate" $- gnutls_certificate_set_x509_key_file- creds certstr keystr gnutls_x509_fmt_pem-- return creds-----------------------------------------------------------------------------------regenerateDHParam :: Ptr GnuTLSCredentials -> IO (Ptr GnuTLSDHParam)-regenerateDHParam creds = alloca $ \dhptr -> do- throwErrorIf "TLS allocate" $ gnutls_dh_params_init dhptr- dh <- peek dhptr- throwErrorIf "TLS DHParm" $ gnutls_dh_params_generate2 dh 1024- gnutls_certificate_set_dh_params creds dh- return dh-----------------------------------------------------------------------------------freePort :: ListenSocket -> IO ()-freePort (ListenHttps _ creds dh) = do- gnutls_certificate_free_credentials $ castPtr creds- gnutls_dh_params_deinit $ castPtr dh-freePort _ = return ()-----------------------------------------------------------------------------------createSession :: ListenSocket -> Int -> CInt -> IO () -> IO NetworkSession-createSession (ListenHttps _ creds _) recvSize socket on_block =- alloca $ \sPtr -> do- throwErrorIf "TLS alloacte" $ gnutls_init sPtr 1- session <- peek sPtr- throwErrorIf "TLS session" $- gnutls_credentials_set session 1 $ castPtr creds- throwErrorIf "TLS session" $ gnutls_set_default_priority session- gnutls_certificate_send_x509_rdn_sequence session 1- gnutls_session_enable_compatibility_mode session-- buffer <- mallocBytes $ fromIntegral recvSize- let s = NetworkSession socket (castPtr session) buffer $- fromIntegral recvSize-- gnutls_transport_set_ptr session $ intPtrToPtr $ fromIntegral $ socket-- handshake s on_block-- return s-createSession _ _ _ _ = error "Invalid socket"-----------------------------------------------------------------------------------endSession :: NetworkSession -> IO ()-endSession (NetworkSession _ session buffer _) = do- throwErrorIf "TLS bye" $ gnutls_bye (castPtr session) 1 `finally` do- gnutls_deinit $ castPtr session- free buffer-----------------------------------------------------------------------------------handshake :: NetworkSession -> IO () -> IO ()-handshake s@(NetworkSession { _session = session}) on_block = do- rc <- gnutls_handshake $ castPtr session- case rc of- x | x >= 0 -> return ()- | isIntrCode x -> handshake s on_block- | isAgainCode x -> on_block >> handshake s on_block- | otherwise -> throwError "TLS handshake" rc-----------------------------------------------------------------------------------send :: IO () -> IO () -> NetworkSession -> ByteString -> IO ()-send tickleTimeout onBlock (NetworkSession { _session = session}) bs =- unsafeUseAsCStringLen bs $ uncurry loop- where- loop ptr len = do- sent <- gnutls_record_send (castPtr session) ptr $ fromIntegral len- let sent' = fromIntegral sent- case sent' of- x | x == 0 || x == len -> return ()- | x > 0 && x < len -> tickleTimeout >>- loop (plusPtr ptr sent') (len - sent')- | isIntrCode x -> loop ptr len- | isAgainCode x -> onBlock >> loop ptr len- | otherwise -> throwError "TLS send" $- fromIntegral sent'------------------------------------------------------------------------------------ | I originally wrote recv to use mallocBytes and unsafePackCStringFinalizer--- to achieve zero-copy. The downside to that method is we might waste memory--- if a malicious adversary only sends us a few bytes, since the entire buffer--- won't be freed until the ByteString is collected. Thus I use--- packCStringLen which makes a copy. Perhaps in the future the recv function--- could be changed to use unsafePackCStringFinalizer if the buffer is at--- least 3/4 full and packCStringLen otherwise or something like that-recv :: IO b -> NetworkSession -> IO (Maybe ByteString)-recv onBlock (NetworkSession _ session recvBuf recvLen) = loop- where- loop = do- size <- gnutls_record_recv (castPtr session) recvBuf recvLen- let size' = fromIntegral size- case size' of- x | x == 0 -> return Nothing- | x > 0 -> liftM Just $ B.packCStringLen (recvBuf, x)- | isIntrCode x -> loop- | isAgainCode x -> onBlock >> loop- | otherwise -> (throwError "TLS recv" $ fromIntegral size')- >> return Nothing----------------------------------------------------------------------------------throwError :: String -> ReturnCode -> IO ()-throwError prefix rc = gnutls_strerror rc >>=- peekCString >>=- throwIO . GnuTLSException . (prefix'++)- where- prefix' = prefix ++ "<" ++ show rc ++ ">: "----------------------------------------------------------------------------------throwErrorIf :: String -> IO ReturnCode -> IO ()-throwErrorIf prefix action = do- rc <- action- if (rc < 0)- then throwError prefix rc- else return ()----------------------------------------------------------------------------------isAgainCode :: (Integral a) => a -> Bool-isAgainCode x = (fromIntegral x) == (-28 :: Int)----------------------------------------------------------------------------------isIntrCode :: (Integral a) => a -> Bool-isIntrCode x = (fromIntegral x) == (-52 :: Int)----------------------------------------------------------------------------------getHostAddr :: Int- -> ByteString- -> IO Socket.SockAddr-getHostAddr p s = do- h <- if s == "*"- then return Socket.iNADDR_ANY- else Socket.inet_addr (map w2c . B.unpack $ s)-- return $ Socket.SockAddrInet (fromIntegral p) h---- Types--newtype ReturnCode = ReturnCode CInt- deriving (Show, Eq, Ord, Num, Real, Enum, Integral)--data GnuTLSCredentials-data GnuTLSSession-data GnuTLSDHParam---- Global init/errors--foreign import ccall safe "gnutls_set_threading_helper"- gnutls_set_threading_helper :: IO ()--foreign import ccall safe "gnutls/gnutls.h gnutls_global_init"- gnutls_global_init :: IO ReturnCode--foreign import ccall safe "gnutls/gnutls.h gnutls_global_deinit"- gnutls_global_deinit :: IO ()--foreign import ccall safe "gnutls/gnutls.h gnutls_strerror"- gnutls_strerror :: ReturnCode -> IO CString---- Sessions. All functions here except handshake and bye just--- allocate memory or update members of structures, so they are ok with--- unsafe ccall.--foreign import ccall unsafe "gnutls/gnutls.h gnutls_init"- gnutls_init :: Ptr (Ptr GnuTLSSession) -> CInt -> IO ReturnCode--foreign import ccall unsafe "gnutls/gnutls.h gnutls_deinit"- gnutls_deinit :: Ptr GnuTLSSession -> IO ()--foreign import ccall safe "gnutls/gnutls.h gnutls_handshake"- gnutls_handshake :: Ptr GnuTLSSession -> IO ReturnCode--foreign import ccall safe "gnutls/gnutls.h gnutls_bye"- gnutls_bye :: Ptr GnuTLSSession -> CInt -> IO ReturnCode--foreign import ccall unsafe "gnutls/gnutls.h gnutls_set_default_priority"- gnutls_set_default_priority :: Ptr GnuTLSSession -> IO ReturnCode--foreign import ccall unsafe "gnutls/gnutls.h gnutls_session_enable_compatibility_mode"- gnutls_session_enable_compatibility_mode :: Ptr GnuTLSSession -> IO ()--foreign import ccall unsafe "gnutls/gnutls.h gnutls_certificate_send_x509_rdn_sequence"- gnutls_certificate_send_x509_rdn_sequence :: Ptr GnuTLSSession -> CInt -> IO ()---- Certificates. Perhaps these could be unsafe but they are not performance critical,--- since they are called only once during server startup.--foreign import ccall safe "gnutls/gnutls.h gnutls_certificate_allocate_credentials"- gnutls_certificate_allocate_credentials :: Ptr (Ptr GnuTLSCredentials) -> IO ReturnCode--foreign import ccall safe "gnutls/gnutls.h gnutls_certificate_free_credentials"- gnutls_certificate_free_credentials :: Ptr GnuTLSCredentials -> IO ()--gnutls_x509_fmt_pem :: CInt-gnutls_x509_fmt_pem = 1--foreign import ccall safe "gnutls/gnutls.h gnutls_certificate_set_x509_key_file"- gnutls_certificate_set_x509_key_file :: Ptr GnuTLSCredentials -> CString -> CString -> CInt -> IO ReturnCode----- Credentials. This is ok as unsafe because it just sets members in the session structure.--foreign import ccall unsafe "gnutls/gnutls.h gnutls_credentials_set"- gnutls_credentials_set :: Ptr GnuTLSSession -> CInt -> Ptr a -> IO ReturnCode---- Records. These are marked unsafe because they are very performance critical. Since--- we are using non-blocking sockets send and recv will not block.--foreign import ccall unsafe "gnutls/gnutls.h gnutls_transport_set_ptr"- gnutls_transport_set_ptr :: Ptr GnuTLSSession -> Ptr a -> IO ()--foreign import ccall unsafe "gnutls/gnutls.h gnutls_record_recv"- gnutls_record_recv :: Ptr GnuTLSSession -> Ptr a -> CSize -> IO CSize--foreign import ccall unsafe "gnutls/gnutls.h gnutls_record_send"- gnutls_record_send :: Ptr GnuTLSSession -> Ptr a -> CSize -> IO CSize---- DHParam. Perhaps these could be unsafe but they are not performance critical.--foreign import ccall safe "gnutls/gnutls.h gnutls_dh_params_init"- gnutls_dh_params_init :: Ptr (Ptr GnuTLSDHParam) -> IO ReturnCode--foreign import ccall safe "gnutls/gnutls.h gnutls_dh_params_deinit"- gnutls_dh_params_deinit :: Ptr GnuTLSDHParam -> IO ()--foreign import ccall safe "gnutls/gnutls.h gnutls_dh_params_generate2"- gnutls_dh_params_generate2 :: Ptr GnuTLSDHParam -> CUInt -> IO ReturnCode--foreign import ccall safe "gnutls/gnutls.h gnutls_certificate_set_dh_params"- gnutls_certificate_set_dh_params :: Ptr GnuTLSCredentials -> Ptr GnuTLSDHParam -> IO ()--#endif
− src/Snap/Internal/Http/Server/HttpPort.hs
@@ -1,117 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE CPP #-}--module Snap.Internal.Http.Server.HttpPort- ( bindHttp- , createSession- , endSession- , recv- , send- ) where----------------------------------------------------------------------------------import Data.ByteString (ByteString)-import qualified Data.ByteString as B-import Data.ByteString.Internal (w2c)-import Foreign-import Foreign.C-import Network.Socket hiding (recv, send)--#ifdef PORTABLE-import qualified Network.Socket.ByteString as SB-#else-import Control.Monad (liftM)-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)-#endif--import Snap.Internal.Http.Server.Backend----------------------------------------------------------------------------------bindHttp :: ByteString -> Int -> IO ListenSocket-bindHttp bindAddr bindPort = do- sock <- socket AF_INET Stream 0- addr <- getHostAddr bindPort bindAddr- setSocketOption sock ReuseAddr 1- bindSocket sock addr- listen sock 150- return $ ListenHttp sock----------------------------------------------------------------------------------getHostAddr :: Int- -> ByteString- -> IO SockAddr-getHostAddr p s = do- h <- if s == "*"- then return iNADDR_ANY- else inet_addr (map w2c . B.unpack $ s)-- return $ SockAddrInet (fromIntegral p) h----------------------------------------------------------------------------------createSession :: Int -> CInt -> IO () -> IO NetworkSession-createSession buffSize s _ = do- buffer <- mallocBytes $ fromIntegral buffSize- return $ NetworkSession s nullPtr buffer $ fromIntegral buffSize----------------------------------------------------------------------------------endSession :: NetworkSession -> IO ()-endSession (NetworkSession {_recvBuffer = buff}) = free buff--#ifdef PORTABLE---------------------------------------------------------------------------------recv :: Socket -> IO () -> NetworkSession -> IO (Maybe ByteString)-recv sock _ (NetworkSession { _recvLen = s }) = do- bs <- SB.recv sock (fromIntegral s)- if B.null bs- then return Nothing- else return $ Just bs----------------------------------------------------------------------------------send :: Socket -> IO () -> IO () -> NetworkSession -> ByteString -> IO ()-send sock tickle _ _ bs = SB.sendAll sock bs >> tickle--#else---------------------------------------------------------------------------------recv :: IO () -> NetworkSession -> IO (Maybe ByteString)-recv onBlock (NetworkSession s _ buff buffSize) = do- sz <- throwErrnoIfMinus1RetryMayBlock- "recv"- (c_read s buff buffSize)- onBlock- if sz == 0- then return Nothing- else liftM Just $ B.packCStringLen (buff, fromIntegral sz)----------------------------------------------------------------------------------send :: IO () -> IO () -> NetworkSession -> ByteString -> IO ()-send tickleTimeout onBlock (NetworkSession s _ _ _) bs =- unsafeUseAsCStringLen bs $ uncurry loop- where loop ptr len = do- sent <- throwErrnoIfMinus1RetryMayBlock- "send"- (c_write s ptr $ fromIntegral len)- onBlock-- let sent' = fromIntegral sent- if sent' < len- then tickleTimeout >> loop (plusPtr ptr sent') (len - sent')- else return ()----------------------------------------------------------------------------------foreign import ccall unsafe "unistd.h read" c_read- :: CInt -> Ptr a -> CSize -> IO (CSize)-foreign import ccall unsafe "unistd.h write" c_write- :: CInt -> Ptr a -> CSize -> IO (CSize)--#endif
− src/Snap/Internal/Http/Server/LibevBackend.hs
@@ -1,727 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE PackageImports #-}--module Snap.Internal.Http.Server.LibevBackend- ( libEvEventLoop- ) where--#ifndef LIBEV--import Control.Exception-import Data.Typeable-import Snap.Internal.Http.Server.Backend--data LibevException = LibevException String- deriving (Show, Typeable)-instance Exception LibevException--libEvEventLoop :: EventLoop-libEvEventLoop _ _ _ _ = throwIO $- LibevException "libev event loop is not supported"--#else-------------------------------- TODO: document module ---------------------------------------------------------------------------------------------------------------import Control.Concurrent hiding (yield)-import Control.Exception-import Control.Monad-import Control.Monad.Trans-import Data.ByteString (ByteString)-import Data.ByteString.Internal (c2w)-import qualified Data.ByteString as S-import Data.Maybe-import Data.IORef-import Data.Typeable-import Foreign hiding (new)-import Foreign.C.Types-import GHC.Conc (forkOnIO)-import Network.Libev-import Network.Socket-import Prelude hiding (catch)----------------------------------------------------------------------------------- FIXME: should be HashSet, make that later.-import qualified Data.Concurrent.HashMap as H-import Data.Concurrent.HashMap (HashMap)-import Snap.Iteratee hiding (map)-import Snap.Internal.Debug-import Snap.Internal.Http.Server.Date-import Snap.Internal.Http.Server.Backend-import qualified Snap.Internal.Http.Server.ListenHelpers as Listen--#if defined(HAS_SENDFILE)-import qualified System.SendFile as SF-import System.Posix.IO-import System.Posix.Types (Fd(..))-#endif----------------------------------------------------------------------------------data Backend = Backend- { _acceptSockets :: [ListenSocket]- , _evLoop :: !EvLoopPtr- , _acceptIOCallbacks :: ![MVar (FunPtr IoCallback)]- , _acceptIOObjs :: ![EvIoPtr]- , _mutexCallbacks :: !(FunPtr MutexCallback, FunPtr MutexCallback)- , _loopLock :: !(MVar ())- , _asyncCb :: !(FunPtr AsyncCallback)- , _asyncObj :: !EvAsyncPtr- , _killCb :: !(FunPtr AsyncCallback)- , _killObj :: !EvAsyncPtr- , _connectionThreads :: !(HashMap ThreadId Connection)- , _backendCPU :: !Int- , _loopExit :: !(MVar ())- }----------------------------------------------------------------------------------data Connection = Connection- { _backend :: !Backend- , _listenSocket :: !ListenSocket- , _rawSocket :: !CInt- , _sessionInfo :: !SessionInfo- , _readAvailable :: !(MVar ())- , _writeAvailable :: !(MVar ())- , _timerObj :: !EvTimerPtr- , _timerCallback :: !(FunPtr TimerCallback)- , _timerTimeoutTime :: !(IORef CTime)- , _readActive :: !(IORef Bool)- , _writeActive :: !(IORef Bool)- , _connReadIOObj :: !EvIoPtr- , _connReadIOCallback :: !(FunPtr IoCallback)- , _connWriteIOObj :: !EvIoPtr- , _connWriteIOCallback :: !(FunPtr IoCallback)- , _connThread :: !(ThreadId)- }----------------------------------------------------------------------------------libEvEventLoop :: EventLoop-libEvEventLoop sockets cap elog handler = do- backends <- Prelude.mapM (newLoop sockets handler elog) [0..(cap-1)]-- debug "libevEventLoop: waiting for loop exit"- Prelude.mapM_ (takeMVar . _loopExit) backends `finally` do- debug "libevEventLoop: stopping all backends"- mapM stop backends- mapM Listen.closeSocket sockets----------------------------------------------------------------------------------newLoop :: [ListenSocket] -- ^ value you got from bindIt- -> SessionHandler -- ^ handler- -> (ByteString -> IO ()) -- ^ error logger- -> Int -- ^ cpu- -> IO Backend-newLoop sockets handler elog cpu = do- -- We'll try kqueue on OSX even though the libev docs complain that it's- -- "broken", in the hope that it works as expected for sockets- f <- evRecommendedBackends- lp <- evLoopNew $ toEnum . fromEnum $ f .|. evbackend_kqueue--- -- we'll be working multithreaded so we need to set up locking for the C- -- event loop struct- (mc1,mc2,looplock) <- setupLockingForLoop lp-- -- setup async callbacks -- these allow us to wake up the main loop- -- (normally blocked in c-land) from other threads- asyncObj <- mkEvAsync- asyncCB <- mkAsyncCallback $ \_ _ _ -> do- debug "async wakeup"- return ()-- killObj <- mkEvAsync- killCB <- mkAsyncCallback $ \_ _ _ -> do- debug "async kill wakeup"- evUnloop lp evunloop_all- return ()-- evAsyncInit asyncObj asyncCB- evAsyncStart lp asyncObj- evAsyncInit killObj killCB- evAsyncStart lp killObj-- -- create the ios for the accept callbacks- accMVars <- forM sockets $ \_ -> newEmptyMVar- accIOs <- forM sockets $ \_ -> mkEvIo-- -- thread set stuff- connSet <- H.new (H.hashString . show)-- -- freed gets stuffed with () when all resources are released.- freed <- newEmptyMVar-- let b = Backend sockets- lp- accMVars- accIOs- (mc1,mc2)- looplock- asyncCB- asyncObj- killCB- killObj- connSet- cpu- freed-- -- setup the accept callback; this watches for read readiness on the- -- listen port- forM_ (zip3 sockets accIOs accMVars) $ \(sock, accIO, x) -> do- accCB <- mkIoCallback $ acceptCallback b handler elog cpu sock- evIoInit accIO accCB (fdSocket $ Listen.listenSocket sock) ev_read- evIoStart lp accIO- putMVar x accCB-- forkOnIO cpu $ loopThread b-- debug $ "LibEv.newLoop: loop spawned"- return b------------------------------------------------------------------------------------ | Run evLoop in a thread-loopThread :: Backend -> IO ()-loopThread backend = do- debug $ "starting loop"- (ignoreException go) `finally` cleanup- debug $ "loop finished"- where- cleanup = block $ do- debug $ "loopThread: cleaning up"- ignoreException $ freeBackend backend- putMVar (_loopExit backend) ()-- lock = _loopLock backend- loop = _evLoop backend- go = takeMVar lock >> block (evLoop loop 0)----------------------------------------------------------------------------------acceptCallback :: Backend- -> SessionHandler- -> (ByteString -> IO ())- -> Int- -> ListenSocket- -> IoCallback-acceptCallback back handler elog cpu sock _loopPtr _ioPtr _ = do- debug "inside acceptCallback"- r <- c_accept $ fdSocket $ Listen.listenSocket sock-- case r of- -- this (EWOULDBLOCK) shouldn't happen (we just got told it was ready!),- -- if it does (maybe the request got picked up by another thread) we'll- -- just bail out- -2 -> return ()- -1 -> debugErrno "Libev.acceptCallback:c_accept()"- fd -> do- debug $ "acceptCallback: accept()ed fd, writing to chan " ++ show fd- forkOnIO cpu $ (go r `catches` cleanup)- return ()- where- go = runSession back handler sock- cleanup = [ Handler $ \(_ :: TimeoutException) -> return ()- , Handler $ \(e :: SomeException) ->- elog $ S.concat [ "libev.acceptCallback: "- , S.pack . map c2w $ show e ]- ]----------------------------------------------------------------------------------ioReadCallback :: CInt -> IORef Bool -> MVar () -> IoCallback-ioReadCallback fd active ra _loopPtr _ioPtr _ = do- -- send notifications to the worker thread- debug $ "ioReadCallback: notification (" ++ show fd ++ ")"- tryPutMVar ra ()- debug $ "stopping ioReadCallback (" ++ show fd ++ ")"- evIoStop _loopPtr _ioPtr- writeIORef active False----------------------------------------------------------------------------------ioWriteCallback :: CInt -> IORef Bool -> MVar () -> IoCallback-ioWriteCallback fd active wa _loopPtr _ioPtr _ = do- -- send notifications to the worker thread- debug $ "ioWriteCallback: notification (" ++ show fd ++ ")"- tryPutMVar wa ()- debug $ "stopping ioWriteCallback (" ++ show fd ++ ")"- evIoStop _loopPtr _ioPtr- writeIORef active False----------------------------------------------------------------------------------stop :: Backend -> IO ()-stop b = ignoreException $ do- debug $ "Libev.stop"-- -- 1. take the loop lock- -- 2. shut down the accept() callback- -- 3. call evUnloop and wake up the loop using evAsyncSend- -- 4. release the loop lock, the main loop thread should then free/clean- -- everything up (threads, connections, io objects, callbacks, etc)-- withMVar lock $ \_ -> do- forM acceptObjs $ evIoStop loop- evUnloop loop evunloop_all- evAsyncSend loop killObj-- where- loop = _evLoop b- acceptObjs = _acceptIOObjs b- killObj = _killObj b- lock = _loopLock b----------------------------------------------------------------------------------getAddr :: SockAddr -> IO (ByteString, Int)-getAddr addr =- case addr of- SockAddrInet p ha -> do- s <- liftM (S.pack . map c2w) (inet_ntoa ha)- return (s, fromIntegral p)-- a -> throwIO $ AddressNotSupportedException (show a)------------------------------------------------------------------------------------ | Throws a timeout exception to the handling thread. The thread will clean--- up everything.-timerCallback :: EvLoopPtr -- ^ loop obj- -> EvTimerPtr -- ^ timer obj- -> IORef CTime -- ^ when to timeout?- -> ThreadId -- ^ thread to kill- -> TimerCallback-timerCallback loop tmr ioref tid _ _ _ = do- debug "Libev.timerCallback: entered"-- now <- getCurrentDateTime- whenToDie <- readIORef ioref-- if whenToDie <= now- then do- debug "Libev.timerCallback: killing thread"- throwTo tid TimeoutException-- else do- debug $ "Libev.timerCallback: now=" ++ show now- ++ ", whenToDie=" ++ show whenToDie- evTimerSetRepeat tmr $ fromRational . toRational $ (whenToDie - now)- evTimerAgain loop tmr------------------------------------------------------------------------------------ | If you already hold the loop lock, you are entitled to destroy a--- connection-destroyConnection :: Connection -> IO ()-destroyConnection conn = do- debug "Libev.destroyConnection: closing socket and killing connection"- c_close fd-- -- stop and free timer object- evTimerStop loop timerObj- freeEvTimer timerObj- freeTimerCallback timerCb-- -- stop and free i/o objects- evIoStop loop ioWrObj- freeEvIo ioWrObj- freeIoCallback ioWrCb-- evIoStop loop ioRdObj- freeEvIo ioRdObj- freeIoCallback ioRdCb-- where- backend = _backend conn- loop = _evLoop backend-- fd = _rawSocket conn- ioWrObj = _connWriteIOObj conn- ioWrCb = _connWriteIOCallback conn- ioRdObj = _connReadIOObj conn- ioRdCb = _connReadIOCallback conn- timerObj = _timerObj conn- timerCb = _timerCallback conn----------------------------------------------------------------------------------freeConnection :: Connection -> IO ()-freeConnection conn = ignoreException $ do- withMVar loopLock $ \_ -> block $ do- debug $ "freeConnection (" ++ show (_rawSocket conn) ++ ")"- destroyConnection conn- let tid = _connThread conn-- -- remove the thread id from the backend set- H.delete tid $ _connectionThreads backend-- -- wake up the event loop so it can be apprised of the changes- evAsyncSend loop asyncObj-- where- backend = _backend conn- loop = _evLoop backend- loopLock = _loopLock backend- asyncObj = _asyncObj backend----------------------------------------------------------------------------------ignoreException :: IO () -> IO ()-ignoreException = handle (\(_::SomeException) -> return ())----------------------------------------------------------------------------------freeBackend :: Backend -> IO ()-freeBackend backend = ignoreException $ block $ do- -- note: we only get here after an unloop, so we have the loop lock- -- here. (?)-- -- kill everything in thread table- tset <- H.toList $ _connectionThreads backend-- let nthreads = Prelude.length tset-- debug $ "Libev.freeBackend: killing active connection threads"-- Prelude.mapM_ (destroyConnection . snd) tset-- -- kill the threads twice, they're probably getting stuck in the- -- freeConnection 'finally' handler- Prelude.mapM_ (killThread . fst) tset- Prelude.mapM_ (killThread . fst) tset-- debug $ "Libev.freeBackend: " ++ show nthreads ++ " thread(s) killed"- debug $ "Libev.freeBackend: destroying libev resources"-- mapM freeEvIo acceptObjs- forM acceptCbs $ \x -> do- acceptCb <- readMVar x- freeIoCallback acceptCb-- evAsyncStop loop asyncObj- freeEvAsync asyncObj- freeAsyncCallback asyncCb-- evAsyncStop loop killObj- freeEvAsync killObj- freeAsyncCallback killCb-- freeMutexCallback mcb1- freeMutexCallback mcb2-- evLoopDestroy loop- debug $ "Libev.freeBackend: resources destroyed"-- where- acceptObjs = _acceptIOObjs backend- acceptCbs = _acceptIOCallbacks backend- asyncObj = _asyncObj backend- asyncCb = _asyncCb backend- killObj = _killObj backend- killCb = _killCb backend- (mcb1,mcb2) = _mutexCallbacks backend- loop = _evLoop backend------------------------------------------------------------------------------------ | Note: proc gets run in the background-runSession :: Backend- -> SessionHandler- -> ListenSocket- -> CInt- -> IO ()-runSession backend handler lsock fd = do- sock <- mkSocket fd AF_INET Stream 0 Connected- peerName <- getPeerName sock- sockName <- getSocketName sock- tid <- myThreadId-- -- set_linger fd- c_setnonblocking fd-- (raddr, rport) <- getAddr peerName- (laddr, lport) <- getAddr sockName-- let lp = _evLoop backend-- -- makes sense to assume the socket is read/write available when- -- opened; worst-case is we get EWOULDBLOCK- ra <- newMVar ()- wa <- newMVar ()--- ------------------ -- setup timer --- ------------------ tmr <- mkEvTimer- now <- getCurrentDateTime- timeoutTime <- newIORef $ now + 20- tcb <- mkTimerCallback $ timerCallback lp- tmr- timeoutTime- tid- -- 20 second timeout- evTimerInit tmr tcb 0 20.0--- readActive <- newIORef True- writeActive <- newIORef True-- evioRead <- mkEvIo- ioReadCb <- mkIoCallback $ ioReadCallback fd readActive ra-- evioWrite <- mkEvIo- ioWriteCb <- mkIoCallback $ ioWriteCallback fd writeActive wa-- evIoInit evioRead ioReadCb fd ev_read- evIoInit evioWrite ioWriteCb fd ev_write-- -- take ev_loop lock, start timer and io watchers- withMVar (_loopLock backend) $ \_ -> do- evTimerAgain lp tmr- evIoStart lp evioRead- evIoStart lp evioWrite-- -- wakeup the loop thread so that these new watchers get- -- registered next time through the loop- evAsyncSend lp $ _asyncObj backend-- let sinfo = SessionInfo laddr lport raddr rport $- Listen.isSecure lsock- let conn = Connection backend- lsock- fd- sinfo- ra- wa- tmr- tcb- timeoutTime- readActive- writeActive- evioRead- ioReadCb- evioWrite- ioWriteCb- tid-- bracket (Listen.createSession lsock bLOCKSIZE fd $- waitForLock True conn)- (\session -> block $ do- debug "runSession: thread killed, closing socket"-- eatException $ Listen.endSession lsock session- eatException $ freeConnection conn- )- (\session -> do H.update tid conn (_connectionThreads backend)- handler sinfo- (enumerate conn session)- (writeOut conn session)- (sendFile conn session)- (tickleTimeout conn)- )----------------------------------------------------------------------------------eatException :: IO a -> IO ()-eatException act = (act >> return ()) `catch` \(_::SomeException) -> return ()----------------------------------------------------------------------------------data AddressNotSupportedException = AddressNotSupportedException String- deriving (Typeable)--instance Show AddressNotSupportedException where- show (AddressNotSupportedException x) = "Address not supported: " ++ x--instance Exception AddressNotSupportedException-----------------------------------------------------------------------------------bLOCKSIZE :: Int-bLOCKSIZE = 8192------- About timeouts------ It's not good enough to restart the timer from io(Read|Write)Callback,--- because those seem to be edge-triggered. I've definitely had where after 20--- seconds they still weren't being re-awakened.-------------------------------------------------------------------------------------data TimeoutException = TimeoutException- deriving (Typeable)--instance Show TimeoutException where- show _ = "timeout"--instance Exception TimeoutException----------------------------------------------------------------------------------tickleTimeout :: Connection -> IO ()-tickleTimeout conn = do- debug "Libev.tickleTimeout"- now <- getCurrentDateTime- writeIORef (_timerTimeoutTime conn) (now + 30)----------------------------------------------------------------------------------waitForLock :: Bool -- ^ True = wait for read, False = wait for write- -> Connection- -> IO ()-waitForLock readLock conn = do- dbg "start waitForLock"-- withMVar looplock $ \_ -> do- act <- readIORef active- if act- then dbg "read watcher already active, skipping"- else do- dbg "starting watcher, sending async"- tryTakeMVar lock- evIoStart lp io- writeIORef active True- evAsyncSend lp async-- dbg "waitForLock: waiting for mvar"- takeMVar lock- dbg "waitForLock: took mvar"-- where- dbg s = debug $ "Libev.recvData(" ++ show (_rawSocket conn) ++ "): "- ++ s- io = if readLock- then (_connReadIOObj conn)- else (_connWriteIOObj conn)- bk = _backend conn- active = if readLock- then (_readActive conn)- else (_writeActive conn)- lp = _evLoop bk- looplock = _loopLock bk- async = _asyncObj bk- lock = if readLock- then (_readAvailable conn)- else (_writeAvailable conn)----------------------------------------------------------------------------------sendFile :: Connection -> NetworkSession -> FilePath -> Int64 -> Int64- -> IO ()-sendFile c s fp start sz = do- withMVar lock $ \_ -> do- act <- readIORef $ _writeActive c- when act $ evIoStop loop io- writeIORef (_writeActive c) False- evAsyncSend loop asy--#if defined(HAS_SENDFILE)- case (_listenSocket c) of- ListenHttp _ -> bracket (openFd fp ReadOnly Nothing defaultFileFlags)- (closeFd)- (go start sz)- _ -> do- step <- runIteratee $ writeOut c s- run_ $ enumFilePartial fp (start,start+sz) step-#else- step <- runIteratee $ writeOut c s-- run_ $ enumFilePartial fp (start,start+sz) step- return ()-#endif-- withMVar lock $ \_ -> do- tryTakeMVar $ _readAvailable c- tryTakeMVar $ _writeAvailable c- evAsyncSend loop asy-- where-#if defined(HAS_SENDFILE)- go off bytes fd- | bytes == 0 = return ()- | otherwise = do- sent <- SF.sendFile sfd fd off bytes- if sent < bytes- then tickleTimeout c >> go (off+sent) (bytes-sent) fd- else return ()-- sfd = Fd $ _rawSocket c-#endif- io = _connWriteIOObj c- b = _backend c- loop = _evLoop b- lock = _loopLock b- asy = _asyncObj b----------------------------------------------------------------------------------enumerate :: (MonadIO m)- => Connection- -> NetworkSession- -> Enumerator ByteString m a-enumerate conn session = loop- where- dbg s = debug $ "Libev.enumerate(" ++ show (_socket session)- ++ "): " ++ s-- loop (Continue k) = do- m <- liftIO $ recvData- let s = fromMaybe "" m- sendOne k s- loop x = returnI x-- sendOne k s | S.null s = do- dbg "sending EOF to continuation"- enumEOF $ Continue k-- | otherwise = do- dbg $ "sending " ++ show s ++ " to continuation"- step <- lift $ runIteratee $ k $ Chunks [s]- case step of- (Yield x st) -> do- dbg $ "got yield, remainder is " ++ show st- yield x st- r@(Continue _) -> do- dbg $ "got continue"- loop r- (Error e) -> throwError e-- recvData = Listen.recv (_listenSocket conn)- (waitForLock True conn) session----------------------------------------------------------------------------------writeOut :: (MonadIO m)- => Connection- -> NetworkSession- -> Iteratee ByteString m ()-writeOut conn session = loop- where- loop = continue k-- k EOF = yield () EOF- k (Chunks xs) = do- liftIO $ sendData $ S.concat xs- loop-- sendData = Listen.send (_listenSocket conn)- (tickleTimeout conn)- (waitForLock False conn)- session--#endif
− src/Snap/Internal/Http/Server/ListenHelpers.hs
@@ -1,84 +0,0 @@-{-# LANGUAGE CPP #-}--module Snap.Internal.Http.Server.ListenHelpers where----------------------------------------------------------------------------------import Data.ByteString (ByteString)-import Foreign.C-import Network.Socket (Socket, sClose)-import Snap.Internal.Http.Server.Backend-import qualified Snap.Internal.Http.Server.HttpPort as Http-import qualified Snap.Internal.Http.Server.GnuTLS as TLS----------------------------------------------------------------------------------listenSocket :: ListenSocket -> Socket-listenSocket (ListenHttp s) = s-listenSocket (ListenHttps s _ _) = s----------------------------------------------------------------------------------isSecure :: ListenSocket -> Bool-isSecure (ListenHttp _) = False-isSecure (ListenHttps _ _ _) = True----------------------------------------------------------------------------------closeSocket :: ListenSocket -> IO ()-closeSocket (ListenHttp s) = sClose s-closeSocket p@(ListenHttps s _ _) = do TLS.freePort p- sClose s----------------------------------------------------------------------------------createSession :: ListenSocket -> Int -> CInt -> IO () -> IO NetworkSession-createSession (ListenHttp _) = Http.createSession-createSession p@(ListenHttps _ _ _) = TLS.createSession p----------------------------------------------------------------------------------endSession :: ListenSocket -> NetworkSession -> IO ()-endSession (ListenHttp _) = Http.endSession-endSession (ListenHttps _ _ _) = TLS.endSession---#ifdef PORTABLE----- For portable builds, we can't call read/write directly so we need the--- original haskell socket to use with network-bytestring package.--- Only the simple backend creates sockets in haskell so the following--- functions only work with the simple backend.----------------------------------------------------------------------------------recv :: ListenSocket -> Socket -> IO () -> NetworkSession- -> IO (Maybe ByteString)-recv (ListenHttp _) s = Http.recv s-recv (ListenHttps _ _ _) _ = TLS.recv----------------------------------------------------------------------------------send :: ListenSocket -> Socket -> IO () -> IO () -> NetworkSession- -> ByteString -> IO ()-send (ListenHttp _) s = Http.send s-send (ListenHttps _ _ _) _ = TLS.send---#else----------------------------------------------------------------------------------recv :: ListenSocket -> IO () -> NetworkSession -> IO (Maybe ByteString)-recv (ListenHttp _) = Http.recv-recv (ListenHttps _ _ _) = TLS.recv----------------------------------------------------------------------------------send :: ListenSocket -> IO () -> IO () -> NetworkSession -> ByteString- -> IO ()-send (ListenHttp _) = Http.send-send (ListenHttps _ _ _) = TLS.send--#endif
+ src/Snap/Internal/Http/Server/Parser.hs view
@@ -0,0 +1,460 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE UnboxedTuples #-}++module Snap.Internal.Http.Server.Parser+ ( IRequest(..)+ , HttpParseException(..)+ , readChunkedTransferEncoding+ , writeChunkedTransferEncoding+ , parseRequest+ , parseFromStream+ , parseCookie+ , parseUrlEncoded+ , getStdContentLength+ , getStdHost+ , getStdTransferEncoding+ , getStdCookie+ , getStdContentType+ , getStdConnection+ ) where++------------------------------------------------------------------------------+#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif+import Control.Exception (Exception, throwIO)+import Control.Monad (void, when)+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.Attoparsec.ByteString.Char8 (Parser, hexadecimal, takeTill)+import qualified Data.ByteString.Char8 as S+import Data.ByteString.Internal (ByteString (..), c2w, memchr, w2c)+#if MIN_VERSION_bytestring(0, 10, 6)+import Data.ByteString.Internal (accursedUnutterablePerformIO)+#else+import Data.ByteString.Internal (inlinePerformIO)+#endif+import qualified Data.ByteString.Unsafe as S+import Data.List (sort)+import Data.Typeable (Typeable)+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Ptr (minusPtr, nullPtr, plusPtr)+import Prelude hiding (take)+------------------------------------------------------------------------------+import Blaze.ByteString.Builder.HTTP (chunkedTransferEncoding, chunkedTransferTerminator)+import Data.ByteString.Builder (Builder)+import System.IO.Streams (InputStream, OutputStream, Generator)+import qualified System.IO.Streams as Streams+import System.IO.Streams.Attoparsec (parseFromStream)+------------------------------------------------------------------------------+import Snap.Internal.Http.Types (Method (..))+import Snap.Internal.Parsing (crlf, parseCookie, parseUrlEncoded, unsafeFromNat)+import Snap.Types.Headers (Headers)+import qualified Snap.Types.Headers as H+++------------------------------------------------------------------------------+newtype StandardHeaders = StandardHeaders (V.Vector (Maybe ByteString))+type MStandardHeaders = MV.IOVector (Maybe ByteString)+++------------------------------------------------------------------------------+contentLengthTag, hostTag, transferEncodingTag, cookieTag, contentTypeTag,+ connectionTag, nStandardHeaders :: Int+contentLengthTag = 0+hostTag = 1+transferEncodingTag = 2+cookieTag = 3+contentTypeTag = 4+connectionTag = 5+nStandardHeaders = 6+++------------------------------------------------------------------------------+findStdHeaderIndex :: ByteString -> Int+findStdHeaderIndex "content-length" = contentLengthTag+findStdHeaderIndex "host" = hostTag+findStdHeaderIndex "transfer-encoding" = transferEncodingTag+findStdHeaderIndex "cookie" = cookieTag+findStdHeaderIndex "content-type" = contentTypeTag+findStdHeaderIndex "connection" = connectionTag+findStdHeaderIndex _ = -1+++------------------------------------------------------------------------------+getStdContentLength, getStdHost, getStdTransferEncoding, getStdCookie,+ getStdConnection, getStdContentType :: StandardHeaders -> Maybe ByteString+getStdContentLength (StandardHeaders v) = V.unsafeIndex v contentLengthTag+getStdHost (StandardHeaders v) = V.unsafeIndex v hostTag+getStdTransferEncoding (StandardHeaders v) = V.unsafeIndex v transferEncodingTag+getStdCookie (StandardHeaders v) = V.unsafeIndex v cookieTag+getStdContentType (StandardHeaders v) = V.unsafeIndex v contentTypeTag+getStdConnection (StandardHeaders v) = V.unsafeIndex v connectionTag+++------------------------------------------------------------------------------+newMStandardHeaders :: IO MStandardHeaders+newMStandardHeaders = MV.replicate nStandardHeaders Nothing+++------------------------------------------------------------------------------+-- | an internal version of the headers part of an HTTP request+data IRequest = IRequest+ { iMethod :: !Method+ , iRequestUri :: !ByteString+ , iHttpVersion :: (Int, Int)+ , iRequestHeaders :: Headers+ , iStdHeaders :: StandardHeaders+ }++------------------------------------------------------------------------------+instance Eq IRequest where+ a == b =+ and [ iMethod a == iMethod b+ , iRequestUri a == iRequestUri b+ , iHttpVersion a == iHttpVersion b+ , sort (H.toList (iRequestHeaders a))+ == sort (H.toList (iRequestHeaders b))+ ]++------------------------------------------------------------------------------+instance Show IRequest where+ show (IRequest m u (major, minor) hdrs _) =+ concat [ show m+ , " "+ , show u+ , " "+ , show major+ , "."+ , show minor+ , " "+ , show hdrs+ ]+++------------------------------------------------------------------------------+data HttpParseException = HttpParseException String deriving (Typeable, Show)+instance Exception HttpParseException+++------------------------------------------------------------------------------+{-# INLINE parseRequest #-}+parseRequest :: InputStream ByteString -> IO IRequest+parseRequest input = do+ line <- pLine input+ let (!mStr, !s) = bSp line+ let (!uri, !vStr) = bSp s+ let method = methodFromString mStr+ let !version = pVer vStr+ let (host, uri') = getHost uri+ let uri'' = if S.null uri' then "/" else uri'++ stdHdrs <- newMStandardHeaders+ MV.unsafeWrite stdHdrs hostTag host+ hdrs <- pHeaders stdHdrs input+ outStd <- StandardHeaders <$> V.unsafeFreeze stdHdrs+ return $! IRequest method uri'' version hdrs outStd++ where+ getHost s | "http://" `S.isPrefixOf` s+ = let s' = S.unsafeDrop 7 s+ (!host, !uri) = breakCh '/' s'+ in (Just $! host, uri)+ | "https://" `S.isPrefixOf` s+ = let s' = S.unsafeDrop 8 s+ (!host, !uri) = breakCh '/' s'+ in (Just $! host, uri)+ | otherwise = (Nothing, s)++ pVer s = if "HTTP/" `S.isPrefixOf` s+ then pVers (S.unsafeDrop 5 s)+ else (1, 0)++ bSp = splitCh ' '++ pVers s = (c, d)+ where+ (!a, !b) = splitCh '.' s+ !c = unsafeFromNat a+ !d = unsafeFromNat b+++------------------------------------------------------------------------------+pLine :: InputStream ByteString -> IO ByteString+pLine input = go []+ where+ throwNoCRLF =+ throwIO $+ HttpParseException "parse error: expected line ending in crlf"++ throwBadCRLF =+ throwIO $+ HttpParseException "parse error: got cr without subsequent lf"++ go !l = do+ !mb <- Streams.read input+ !s <- maybe throwNoCRLF return mb++ let !i = elemIndex '\r' s+ if i < 0+ then noCRLF l s+ else case () of+ !_ | i+1 >= S.length s -> lastIsCR l s i+ | S.unsafeIndex s (i+1) == 10 -> foundCRLF l s i+ | otherwise -> throwBadCRLF++ foundCRLF l s !i1 = do+ let !i2 = i1 + 2+ let !a = S.unsafeTake i1 s+ when (i2 < S.length s) $ do+ let !b = S.unsafeDrop i2 s+ Streams.unRead b input++ -- Optimize for the common case: dl is almost always "id"+ let !out = if null l then a else S.concat (reverse (a:l))+ return out++ noCRLF l s = go (s:l)++ lastIsCR l s !idx = do+ !t <- Streams.read input >>= maybe throwNoCRLF return+ if S.null t+ then lastIsCR l s idx+ else do+ let !c = S.unsafeHead t+ if c /= 10+ then throwBadCRLF+ else do+ let !a = S.unsafeTake idx s+ let !b = S.unsafeDrop 1 t+ when (not $ S.null b) $ Streams.unRead b input+ let !out = if null l then a else S.concat (reverse (a:l))+ return out+++------------------------------------------------------------------------------+splitCh :: Char -> ByteString -> (ByteString, ByteString)+splitCh !c !s = if idx < 0+ then (s, S.empty)+ else let !a = S.unsafeTake idx s+ !b = S.unsafeDrop (idx + 1) s+ in (a, b)+ where+ !idx = elemIndex c s+{-# INLINE splitCh #-}+++------------------------------------------------------------------------------+breakCh :: Char -> ByteString -> (ByteString, ByteString)+breakCh !c !s = if idx < 0+ then (s, S.empty)+ else let !a = S.unsafeTake idx s+ !b = S.unsafeDrop idx s+ in (a, b)+ where+ !idx = elemIndex c s+{-# INLINE breakCh #-}+++------------------------------------------------------------------------------+splitHeader :: ByteString -> (ByteString, ByteString)+splitHeader !s = if idx < 0+ then (s, S.empty)+ else let !a = S.unsafeTake idx s+ in (a, skipSp (idx + 1))+ where+ !idx = elemIndex ':' s+ l = S.length s++ skipSp !i | i >= l = S.empty+ | otherwise = let c = S.unsafeIndex s i+ in if isLWS $ w2c c+ then skipSp $ i + 1+ else S.unsafeDrop i s++{-# INLINE splitHeader #-}++++------------------------------------------------------------------------------+isLWS :: Char -> Bool+isLWS c = c == ' ' || c == '\t'+{-# INLINE isLWS #-}+++------------------------------------------------------------------------------+pHeaders :: MStandardHeaders -> InputStream ByteString -> IO Headers+pHeaders stdHdrs input = do+ hdrs <- H.unsafeFromCaseFoldedList <$> go []+ return hdrs++ where+ go !list = do+ line <- pLine input+ if S.null line+ then return list+ else do+ let (!k0,!v) = splitHeader line+ let !k = toLower k0+ vf <- pCont id+ let vs = vf []+ let !v' = S.concat (v:vs)+ let idx = findStdHeaderIndex k+ when (idx >= 0) $ MV.unsafeWrite stdHdrs idx $! Just v'++ let l' = ((k, v'):list)+ go l'++ trimBegin = S.dropWhile isLWS++ pCont !dlist = do+ mbS <- Streams.peek input+ maybe (return dlist)+ (\s -> if not (S.null s)+ then if not $ isLWS $ w2c $ S.unsafeHead s+ then return dlist+ else procCont dlist+ else Streams.read input >> pCont dlist)+ mbS++ procCont !dlist = do+ line <- pLine input+ let !t = trimBegin line+ pCont (dlist . (" ":) . (t:))+++------------------------------------------------------------------------------+methodFromString :: ByteString -> Method+methodFromString "GET" = GET+methodFromString "POST" = POST+methodFromString "HEAD" = HEAD+methodFromString "PUT" = PUT+methodFromString "DELETE" = DELETE+methodFromString "TRACE" = TRACE+methodFromString "OPTIONS" = OPTIONS+methodFromString "CONNECT" = CONNECT+methodFromString "PATCH" = PATCH+methodFromString s = Method s+++------------------------------------------------------------------------------+readChunkedTransferEncoding :: InputStream ByteString+ -> IO (InputStream ByteString)+readChunkedTransferEncoding input =+ Streams.fromGenerator (consumeChunks input)++------------------------------------------------------------------------------+writeChunkedTransferEncoding :: OutputStream Builder+ -> IO (OutputStream Builder)+writeChunkedTransferEncoding os = Streams.makeOutputStream f+ where+ f Nothing = do+ Streams.write (Just chunkedTransferTerminator) os+ Streams.write Nothing os+ f x = Streams.write (chunkedTransferEncoding `fmap` x) os+++ ---------------------+ -- parse functions --+ ---------------------++------------------------------------------------------------------------------+{-+ For a response body in chunked transfer encoding, iterate over+ the individual chunks, reading the size parameter, then+ looping over that chunk in bites of at most bUFSIZ,+ yielding them to the receiveResponse InputStream accordingly.+-}+consumeChunks :: InputStream ByteString -> Generator ByteString ()+consumeChunks i1 = do+ !n <- parseSize+ if n > 0+ then do+ -- read one or more bytes, then loop to next chunk+ go n+ skipCRLF+ consumeChunks i1+ else do+ -- NB: snap-server doesn't yet support chunked trailer parts+ -- (see RFC7230#sec4.1.2)++ -- consume final CRLF+ skipCRLF++ where+ go 0 = return ()+ go !n = do+ (!x',!r) <- liftIO $ readN n i1+ Streams.yield x'+ go r++ parseSize = do+ liftIO $ parseFromStream transferChunkSize i1++ skipCRLF = do+ liftIO $ void (parseFromStream crlf i1)++ transferChunkSize :: Parser (Int)+ transferChunkSize = do+ !n <- hexadecimal+ -- skip over any chunk extensions (see RFC7230#sec4.1.1)+ void (takeTill (== '\r'))+ void crlf+ return n++ {-+ The chunk size coming down from the client is somewhat arbitrary;+ it's really just an indication of how many bytes need to be read+ before the next size marker or end marker - neither of which has+ anything to do with streaming on our side. Instead, we'll feed+ bytes into our InputStream at an appropriate intermediate size.+ -}+ bUFSIZ :: Int+ bUFSIZ = 32752++ {-+ Read the specified number of bytes up to a maximum of bUFSIZ,+ returning a resultant ByteString and the number of bytes remaining.+ -}+ readN :: Int -> InputStream ByteString -> IO (ByteString, Int)+ readN n input = do+ !x' <- Streams.readExactly p input+ return (x', r)+ where+ !d = n - bUFSIZ+ !p = if d > 0 then bUFSIZ else n+ !r = if d > 0 then d else 0++------------------------------------------------------------------------------+toLower :: ByteString -> ByteString+toLower = S.map lower+ where+ lower c0 = let !c = c2w c0+ in if 65 <= c && c <= 90+ then w2c $! c + 32+ else c0+++------------------------------------------------------------------------------+-- | A version of elemIndex that doesn't allocate a Maybe. (It returns -1 on+-- not found.)+elemIndex :: Char -> ByteString -> Int+#if MIN_VERSION_bytestring(0, 10, 6)+elemIndex c (PS !fp !start !len) = accursedUnutterablePerformIO $+#else+elemIndex c (PS !fp !start !len) = inlinePerformIO $+#endif+ withForeignPtr fp $ \p0 -> do+ let !p = plusPtr p0 start+ q <- memchr p w8 (fromIntegral len)+ return $! if q == nullPtr then (-1) else q `minusPtr` p+ where+ !w8 = c2w c+{-# INLINE elemIndex #-}
+ src/Snap/Internal/Http/Server/Session.hs view
@@ -0,0 +1,832 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Internal.Http.Server.Session+ ( httpAcceptLoop+ , httpSession+ , snapToServerHandler+ , BadRequestException(..)+ , LengthRequiredException(..)+ , TerminateSessionException(..)+ ) where++------------------------------------------------------------------------------+#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif+import Control.Arrow (first, second)+import Control.Concurrent (MVar, newEmptyMVar, putMVar, readMVar)+import Control.Exception (AsyncException, Exception, Handler (..), SomeException (..))+import qualified Control.Exception as E+import Control.Monad (join, unless, void, when, (>=>))+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Unsafe as S+import qualified Data.CaseInsensitive as CI+import Data.Int (Int64)+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import Data.List (foldl')+import qualified Data.Map as Map+import Data.Maybe (fromJust, fromMaybe, isNothing)+#if !MIN_VERSION_base(4,8,0)+import Data.Monoid (mconcat)+#endif+import Data.Monoid ((<>))+import Data.Time.Format (formatTime)+import Data.Typeable (Typeable)+import Data.Version (showVersion)+import Data.Word (Word64, Word8)+import Foreign.Marshal.Utils (copyBytes)+import Foreign.Ptr (Ptr, castPtr, plusPtr)+import Foreign.Storable (pokeByteOff)+#if MIN_VERSION_time(1,5,0)+import Data.Time.Format (defaultTimeLocale)+#else+import System.Locale (defaultTimeLocale)+#endif+------------------------------------------------------------------------------+import Data.ByteString.Builder (Builder, byteString, char8, stringUtf8)+import Data.ByteString.Builder.Extra (flush)+import Data.ByteString.Builder.Internal (Buffer, defaultChunkSize, newBuffer)+import Data.ByteString.Builder.Prim (FixedPrim, primFixed, (>$<), (>*<))+import Data.ByteString.Builder.Prim.Internal (fixedPrim, size)+import System.IO.Streams (InputStream, OutputStream)+import qualified System.IO.Streams as Streams+------------------------------------------------------------------------------+import qualified Paths_snap_server as V+import Snap.Core (EscapeSnap (..))+import Snap.Core (Snap, runSnap)+import Snap.Internal.Core (fixupResponse)+import Snap.Internal.Http.Server.Clock (getClockTime)+import Snap.Internal.Http.Server.Common (eatException)+import Snap.Internal.Http.Server.Date (getDateString)+import Snap.Internal.Http.Server.Parser (IRequest (..), getStdConnection, getStdContentLength, getStdContentType, getStdCookie, getStdHost, getStdTransferEncoding, parseCookie, parseRequest, parseUrlEncoded, readChunkedTransferEncoding, writeChunkedTransferEncoding)+import Snap.Internal.Http.Server.Thread (SnapThread)+import qualified Snap.Internal.Http.Server.Thread as Thread+import Snap.Internal.Http.Server.TimeoutManager (TimeoutManager)+import qualified Snap.Internal.Http.Server.TimeoutManager as TM+import Snap.Internal.Http.Server.Types (AcceptFunc (..), PerSessionData (..), SendFileHandler, ServerConfig (..), ServerHandler)+import Snap.Internal.Http.Types (Cookie (..), HttpVersion, Method (..), Request (..), Response (..), ResponseBody (..), StreamProc, getHeader, headers, rspBodyToEnum, updateHeaders)+import Snap.Internal.Parsing (unsafeFromNat)+import Snap.Types.Headers (Headers)+import qualified Snap.Types.Headers as H+import System.IO.Unsafe (unsafePerformIO)+++------------------------------------------------------------------------------+data TerminateSessionException = TerminateSessionException SomeException+ deriving (Typeable, Show)+instance Exception TerminateSessionException++data BadRequestException = BadRequestException+ deriving (Typeable, Show)+instance Exception BadRequestException++data LengthRequiredException = LengthRequiredException+ deriving (Typeable, Show)+instance Exception LengthRequiredException+++------------------------------------------------------------------------------+snapToServerHandler :: Snap a -> ServerHandler hookState+snapToServerHandler !snap !serverConfig !perSessionData !req =+ runSnap snap logErr tickle req+ where+ logErr = _logError serverConfig . byteString+ tickle = _twiddleTimeout perSessionData+++------------------------------------------------------------------------------+mAX_HEADERS_SIZE :: Int64+mAX_HEADERS_SIZE = 256 * 1024+++------------------------------------------------------------------------------+-- | For each cpu, we store:+-- * An accept thread+-- * A TimeoutManager+-- * An mvar to signal when the timeout thread is shutdown+data EventLoopCpu = EventLoopCpu+ { _acceptThread :: SnapThread+ , _timeoutManager :: TimeoutManager+ }+++------------------------------------------------------------------------------+-- | The main Snap webserver loop. Given a server handler, configuration, and a+-- function to accept new connections, runs an HTTP loop forever over N+-- threads, until a ThreadKilled exception is received.+httpAcceptLoop :: forall hookState .+ ServerHandler hookState -- ^ server handler+ -> ServerConfig hookState -- ^ server config+ -> AcceptFunc -- ^ accept function+ -> IO ()+httpAcceptLoop serverHandler serverConfig acceptFunc = runLoops+ where+ --------------------------------------------------------------------------+ logError = _logError serverConfig+ nLoops = _numAcceptLoops serverConfig+ defaultTimeout = _defaultTimeout serverConfig++ --------------------------------------------------------------------------+ logException :: Exception e => e -> IO ()+ logException e =+ logError $+ mconcat [ byteString "got exception in httpAcceptFunc: "+ , fromShow e+ ]++ --------------------------------------------------------------------------+ runLoops = E.bracket (mapM newLoop [0 .. (nLoops - 1)])+ (mapM_ killLoop)+ (mapM_ waitLoop)++ --------------------------------------------------------------------------+ loop :: TimeoutManager+ -> (forall a. IO a -> IO a)+ -> IO ()+ loop tm loopRestore = eatException go+ where+ ----------------------------------------------------------------------+ handlers =+ [ Handler $ \(e :: AsyncException) -> loopRestore (E.throwIO $! e)+ , Handler $ \(e :: SomeException) -> logException e >> go+ ]++ go = do+ (sendFileHandler, localAddress, localPort, remoteAddress,+ remotePort, readEnd, writeEnd,+ cleanup) <- runAcceptFunc acceptFunc loopRestore+ `E.catches` handlers+ let threadLabel = S.concat [ "snap-server: client "+ , remoteAddress+ , ":"+ , S.pack $ show remotePort+ ]+ thMVar <- newEmptyMVar+ th <- TM.register tm threadLabel $ \restore ->+ eatException $+ prep thMVar sendFileHandler localAddress localPort remoteAddress+ remotePort readEnd writeEnd cleanup restore+ putMVar thMVar th+ go++ prep :: MVar TM.TimeoutThread+ -> SendFileHandler+ -> ByteString+ -> Int+ -> ByteString+ -> Int+ -> InputStream ByteString+ -> OutputStream ByteString+ -> IO ()+ -> (forall a . IO a -> IO a)+ -> IO ()+ prep thMVar sendFileHandler localAddress localPort remoteAddress+ remotePort readEnd writeEnd cleanup restore =+ do+ connClose <- newIORef False+ newConn <- newIORef True+ let twiddleTimeout = unsafePerformIO $ do+ th <- readMVar thMVar+ return $! TM.modify th+ let cleanupTimeout = readMVar thMVar >>= TM.cancel++ let !psd = PerSessionData connClose+ twiddleTimeout+ newConn+ sendFileHandler+ localAddress+ localPort+ remoteAddress+ remotePort+ readEnd+ writeEnd+ restore (session psd)+ `E.finally` cleanup+ `E.finally` cleanupTimeout++ --------------------------------------------------------------------------+ session psd = do+ buffer <- newBuffer defaultChunkSize+ httpSession buffer serverHandler serverConfig psd++ --------------------------------------------------------------------------+ newLoop cpu = E.mask_ $ do+ -- TODO(greg): move constant into config+ tm <- TM.initialize (fromIntegral defaultTimeout) 2 getClockTime+ let threadLabel = S.concat [ "snap-server: accept loop #"+ , S.pack $ show cpu+ ]++ tid <- Thread.forkOn threadLabel cpu $ loop tm+ return $! EventLoopCpu tid tm++ --------------------------------------------------------------------------+ waitLoop (EventLoopCpu tid _) = Thread.wait tid++ --------------------------------------------------------------------------+ killLoop ev = E.uninterruptibleMask_ $ do+ Thread.cancelAndWait tid+ TM.stop tm+ where+ tid = _acceptThread ev+ tm = _timeoutManager ev++------------------------------------------------------------------------------+httpSession :: forall hookState .+ Buffer+ -> ServerHandler hookState+ -> ServerConfig hookState+ -> PerSessionData+ -> IO ()+httpSession !buffer !serverHandler !config !sessionData = loop+ where+ --------------------------------------------------------------------------+ defaultTimeout = _defaultTimeout config+ isSecure = _isSecure config+ localHostname = _localHostname config+ logAccess = _logAccess config+ logError = _logError config+ newRequestHook = _onNewRequest config+ parseHook = _onParse config+ userHandlerFinishedHook = _onUserHandlerFinished config+ dataFinishedHook = _onDataFinished config+ exceptionHook = _onException config+ escapeHook = _onEscape config++ --------------------------------------------------------------------------+ forceConnectionClose = _forceConnectionClose sessionData+ isNewConnection = _isNewConnection sessionData+ localAddress = _localAddress sessionData+ localPort = _localPort sessionData+ remoteAddress = _remoteAddress sessionData+ remotePort = _remotePort sessionData+ readEnd = _readEnd sessionData+ tickle f = _twiddleTimeout sessionData f+ writeEnd = _writeEnd sessionData+ sendfileHandler = _sendfileHandler sessionData++ --------------------------------------------------------------------------+ mkBuffer :: IO (OutputStream Builder)+ mkBuffer = Streams.unsafeBuilderStream (return buffer) writeEnd++ --------------------------------------------------------------------------+ -- Begin HTTP session processing.+ loop :: IO ()+ loop = do+ -- peek first to ensure startHook gets generated at the right time.+ readEndAtEof >>= (flip unless $ do+ hookState <- newRequestHook sessionData >>= newIORef+ -- parse HTTP request+ req <- receiveRequest+ parseHook hookState req+ processRequest hookState req)++ ------------------------------------------------------------------------------+ readEndAtEof = Streams.read readEnd >>=+ maybe (return True)+ (\c -> if S.null c+ then readEndAtEof+ else Streams.unRead c readEnd >> return False)+ {-# INLINE readEndAtEof #-}++ --------------------------------------------------------------------------+ -- Read the HTTP request from the socket, parse it, and pre-process it.+ receiveRequest :: IO Request+ receiveRequest = {-# SCC "httpSession/receiveRequest" #-} do+ readEnd' <- Streams.throwIfProducesMoreThan mAX_HEADERS_SIZE readEnd+ parseRequest readEnd' >>= toRequest+ {-# INLINE receiveRequest #-}++ --------------------------------------------------------------------------+ toRequest :: IRequest -> IO Request+ toRequest !ireq = {-# SCC "httpSession/toRequest" #-} do+ -- HTTP spec section 14.23: "All Internet-based HTTP/1.1 servers MUST+ -- respond with a 400 (Bad Request) status code to any HTTP/1.1 request+ -- message which lacks a Host header field."+ --+ -- Here we interpret this slightly more liberally: if an absolute URI+ -- including a hostname is given in the request line, we'll take that+ -- if there's no Host header.+ --+ -- For HTTP/1.0 requests, we pick the configured local hostname by+ -- default.+ host <- maybe (if isHttp11+ then badRequestWithNoHost+ else return localHostname)+ return mbHost++ -- Call setupReadEnd, which handles transfer-encoding: chunked or+ -- content-length restrictions, etc+ !readEnd' <- setupReadEnd++ -- Parse an application/x-www-form-urlencoded form, if it was sent+ (!readEnd'', postParams) <- parseForm readEnd'++ let allParams = Map.unionWith (++) queryParams postParams++ -- Decide whether the connection should be closed after the response is+ -- sent (stored in the forceConnectionClose IORef).+ checkConnectionClose version $ getStdConnection stdHdrs++ -- The request is now ready for processing.+ return $! Request host+ remoteAddress+ remotePort+ localAddress+ localPort+ localHost+ isSecure+ hdrs+ readEnd''+ mbCL+ method+ version+ cookies+ pathInfo+ contextPath+ uri+ queryString+ allParams+ queryParams+ postParams++ where+ ----------------------------------------------------------------------+ !method = iMethod ireq+ !version = iHttpVersion ireq+ !stdHdrs = iStdHeaders ireq+ !hdrs = iRequestHeaders ireq++ !isHttp11 = version >= (1, 1)++ !mbHost = getStdHost stdHdrs+ !localHost = fromMaybe localHostname mbHost+ mbCL = unsafeFromNat <$>+ getStdContentLength stdHdrs+ !isChunked = (CI.mk <$> getStdTransferEncoding stdHdrs)+ == Just "chunked"+ cookies = fromMaybe [] (getStdCookie stdHdrs >>= parseCookie)+ contextPath = "/"+ !uri = iRequestUri ireq+ queryParams = parseUrlEncoded queryString+ emptyParams = Map.empty++ ----------------------------------------------------------------------+ (pathInfo, queryString) = first dropLeadingSlash . second (S.drop 1)+ $ S.break (== '?') uri++ ----------------------------------------------------------------------+ dropLeadingSlash s = if S.null s+ then s+ else let !a = S.unsafeIndex s 0+ in if a == 47 -- 47 == '/'+ then S.unsafeDrop 1 s+ else s+ {-# INLINE dropLeadingSlash #-}++ ----------------------------------------------------------------------+ -- | We have to transform the read end of the socket, to limit the+ -- number of bytes read to the content-length, to decode chunked+ -- transfer encoding, or to immediately yield EOF if the request body+ -- is empty.+ setupReadEnd :: IO (InputStream ByteString)+ setupReadEnd =+ if isChunked+ then readChunkedTransferEncoding readEnd+ else maybe (const noContentLength)+ (Streams.takeBytes . fromIntegral) mbCL readEnd+ {-# INLINE setupReadEnd #-}++ ----------------------------------------------------------------------+ -- | If a request is not in chunked transfer encoding and lacks a+ -- content-length, the request body is null string.+ noContentLength :: IO (InputStream ByteString)+ noContentLength = do+ when (method == POST || method == PUT) return411+ Streams.fromList []++ ----------------------------------------------------------------------+ return411 = do+ let (major, minor) = version+ let resp = mconcat [ byteString "HTTP/"+ , fromShow major+ , char8 '.'+ , fromShow minor+ , byteString " 411 Length Required\r\n\r\n"+ , byteString "411 Length Required\r\n"+ , flush+ ]+ writeEndB <- mkBuffer+ Streams.write (Just resp) writeEndB+ Streams.write Nothing writeEndB+ terminateSession LengthRequiredException++ ----------------------------------------------------------------------+ parseForm readEnd' = if hasForm+ then getForm+ else return (readEnd', emptyParams)+ where+ trimIt = fst . S.spanEnd (== ' ') . S.takeWhile (/= ';')+ . S.dropWhile (== ' ')+ mbCT = trimIt <$> getStdContentType stdHdrs+ hasForm = mbCT == Just "application/x-www-form-urlencoded"++ mAX_POST_BODY_SIZE = 1024 * 1024++ getForm = do+ readEnd'' <- Streams.throwIfProducesMoreThan+ mAX_POST_BODY_SIZE readEnd'+ contents <- S.concat <$> Streams.toList readEnd''+ let postParams = parseUrlEncoded contents+ finalReadEnd <- Streams.fromList [contents]+ return (finalReadEnd, postParams)++ ----------------------------------------------------------------------+ checkConnectionClose version connection = do+ -- For HTTP/1.1: if there is an explicit Connection: close, we'll close+ -- the socket later.+ --+ -- For HTTP/1.0: if there is no explicit Connection: Keep-Alive,+ -- close the socket later.+ let v = CI.mk <$> connection+ when ((version == (1, 1) && v == Just "close") ||+ (version == (1, 0) && v /= Just "keep-alive")) $+ writeIORef forceConnectionClose True++ --------------------------------------------------------------------------+ {-# INLINE badRequestWithNoHost #-}+ badRequestWithNoHost :: IO a+ badRequestWithNoHost = do+ let msg = mconcat [+ byteString "HTTP/1.1 400 Bad Request\r\n\r\n"+ , byteString "400 Bad Request: HTTP/1.1 request with no "+ , byteString "Host header\r\n"+ , flush+ ]+ writeEndB <- mkBuffer+ Streams.write (Just msg) writeEndB+ Streams.write Nothing writeEndB+ terminateSession BadRequestException++ --------------------------------------------------------------------------+ {-# INLINE checkExpect100Continue #-}+ checkExpect100Continue req =+ when (getHeader "expect" req == Just "100-continue") $ do+ let v = if rqVersion req == (1,1) then "HTTP/1.1" else "HTTP/1.0"++ let hl = byteString v <>+ byteString " 100 Continue\r\n\r\n" <>+ flush+ os <- mkBuffer+ Streams.write (Just hl) os++ --------------------------------------------------------------------------+ {-# INLINE processRequest #-}+ processRequest !hookState !req = {-# SCC "httpSession/processRequest" #-} do+ -- successfully parsed a request, so restart the timer+ tickle $ max defaultTimeout++ -- check for Expect: 100-continue+ checkExpect100Continue req+ b <- runServerHandler hookState req+ `E.catches` [ Handler $ escapeSnapHandler hookState+ , Handler $+ catchUserException hookState "user handler" req+ ]+ if b+ then do writeIORef isNewConnection False+ -- the timer resets to its default value here.+ loop+ else return $! ()++ --------------------------------------------------------------------------+ {-# INLINE runServerHandler #-}+ runServerHandler !hookState !req = {-# SCC "httpSession/runServerHandler" #-} do+ (req0, rsp0) <- serverHandler config sessionData req+ userHandlerFinishedHook hookState req rsp0++ -- check whether we should close the connection after sending the+ -- response+ let v = rqVersion req+ let is_1_0 = (v == (1,0))+ cc <- if is_1_0 && (isNothing $ rspContentLength rsp0)+ then return $! True+ else readIORef forceConnectionClose++ -- skip unread portion of request body if rspTransformingRqBody is not+ -- true+ unless (rspTransformingRqBody rsp0) $ Streams.skipToEof (rqBody req)++ !date <- getDateString+ rsp1 <- fixupResponse req rsp0+ let (!hdrs, !cc') = addDateAndServerHeaders is_1_0 date cc $+ headers rsp1+ let rsp = updateHeaders (const hdrs) rsp1+ writeIORef forceConnectionClose cc'+ bytesSent <- sendResponse req rsp `E.catch`+ catchUserException hookState "sending-response" req+ dataFinishedHook hookState req rsp+ logAccess req0 rsp bytesSent+ return $! not cc'++ --------------------------------------------------------------------------+ addDateAndServerHeaders !is1_0 !date !cc !hdrs =+ {-# SCC "addDateAndServerHeaders" #-}+ let (!hdrs', !newcc) = go [("date",date)] False cc+ $ H.unsafeToCaseFoldedList hdrs+ in (H.unsafeFromCaseFoldedList hdrs', newcc)+ where+ -- N.B.: here we know the date header has already been removed by+ -- "fixupResponse".+ go !l !seenServer !connClose [] =+ let !l1 = if seenServer then l else (("server", sERVER_HEADER):l)+ !l2 = if connClose then (("connection", "close"):l1) else l1+ in (l2, connClose)+ go l _ c (x@("server",_):xs) = go (x:l) True c xs+ go l seenServer c (x@("connection", v):xs)+ | c = go l seenServer c xs+ | v == "close" || (is1_0 && v /= "keep-alive") =+ go l seenServer True xs+ | otherwise = go (x:l) seenServer c xs+ go l seenServer c (x:xs) = go (x:l) seenServer c xs++ --------------------------------------------------------------------------+ escapeSnapHandler hookState (EscapeHttp escapeHandler) = do+ escapeHook hookState+ mkBuffer >>= escapeHandler tickle readEnd+ return False+ escapeSnapHandler _ (TerminateConnection e) = terminateSession e++ --------------------------------------------------------------------------+ catchUserException :: IORef hookState+ -> ByteString+ -> Request+ -> SomeException+ -> IO a+ catchUserException hookState phase req e = do+ logError $ mconcat [+ byteString "Exception leaked to httpSession during phase '"+ , byteString phase+ , byteString "': \n"+ , requestErrorMessage req e+ ]+ -- Note: the handler passed to httpSession needs to catch its own+ -- exceptions if it wants to avoid an ungracious exit here.+ eatException $ exceptionHook hookState e+ terminateSession e++ --------------------------------------------------------------------------+ sendResponse :: Request -> Response -> IO Word64+ sendResponse !req !rsp = {-# SCC "httpSession/sendResponse" #-} do+ let !v = rqVersion req+ let !hdrs' = renderCookies rsp (headers rsp)+ let !code = rspStatus rsp+ let body = rspBody rsp+ let needChunked = rqMethod req /= HEAD+ && isNothing (rspContentLength rsp)+ && code /= 204+ && code /= 304++ let (hdrs'', body', shouldClose) = if needChunked+ then noCL req hdrs' body+ else (hdrs', body, False)++ when shouldClose $ writeIORef forceConnectionClose $! True+ let hdrPrim = mkHeaderPrim v rsp hdrs''+ let hlen = size hdrPrim+ let headerBuilder = primFixed hdrPrim $! ()++ nBodyBytes <- case body' of+ Stream s ->+ whenStream headerBuilder hlen rsp s+ SendFile f Nothing ->+ whenSendFile headerBuilder rsp f 0+ -- ignore end length here because we know we had a+ -- content-length, use that instead.+ SendFile f (Just (st, _)) ->+ whenSendFile headerBuilder rsp f st+ return $! nBodyBytes++ --------------------------------------------------------------------------+ noCL :: Request+ -> Headers+ -> ResponseBody+ -> (Headers, ResponseBody, Bool)+ noCL req hdrs body =+ if v == (1,1)+ then let origBody = rspBodyToEnum body+ body' = \os -> do+ os' <- writeChunkedTransferEncoding os+ origBody os'+ in ( H.set "transfer-encoding" "chunked" hdrs+ , Stream body'+ , False)+ else+ -- We've already noted that we have to close the socket earlier in+ -- runServerHandler.+ (hdrs, body, True)+ where+ v = rqVersion req+ {-# INLINE noCL #-}++ --------------------------------------------------------------------------+ -- | If the response contains a content-length, make sure the response body+ -- StreamProc doesn't yield more (or fewer) than the given number of bytes.+ limitRspBody :: Int -- ^ header length+ -> Response -- ^ response+ -> OutputStream ByteString -- ^ write end of socket+ -> IO (OutputStream ByteString)+ limitRspBody hlen rsp os = maybe (return os) f $ rspContentLength rsp+ where+ f cl = Streams.giveExactly (fromIntegral hlen + fromIntegral cl) os+ {-# INLINE limitRspBody #-}++ --------------------------------------------------------------------------+ whenStream :: Builder -- ^ headers+ -> Int -- ^ header length+ -> Response -- ^ response+ -> StreamProc -- ^ output body+ -> IO Word64 -- ^ returns number of bytes written+ whenStream headerString hlen rsp body = do+ -- note:+ --+ -- * precondition here is that we have a content-length and that we're+ -- not using chunked transfer encoding.+ --+ -- * "headerString" includes http status line.+ --+ -- If you're transforming the request body, you have to manage your own+ -- timeouts.+ let t = if rspTransformingRqBody rsp+ then return $! ()+ else tickle $ max defaultTimeout+ writeEnd0 <- Streams.ignoreEof writeEnd+ (writeEnd1, getCount) <- Streams.countOutput writeEnd0+ writeEnd2 <- limitRspBody hlen rsp writeEnd1+ writeEndB <- Streams.unsafeBuilderStream (return buffer) writeEnd2 >>=+ Streams.contramapM (\x -> t >> return x)++ Streams.write (Just headerString) writeEndB+ writeEnd' <- body writeEndB+ Streams.write Nothing writeEnd'+ -- Just in case the user handler didn't.+ Streams.write Nothing writeEnd1+ n <- getCount+ return $! fromIntegral n - fromIntegral hlen+ {-# INLINE whenStream #-}++ --------------------------------------------------------------------------+ whenSendFile :: Builder -- ^ headers+ -> Response -- ^ response+ -> FilePath -- ^ file to serve+ -> Word64 -- ^ file start offset+ -> IO Word64 -- ^ returns number of bytes written+ whenSendFile headerString rsp filePath offset = do+ let !cl = fromJust $ rspContentLength rsp+ sendfileHandler buffer headerString filePath offset cl+ return cl+ {-# INLINE whenSendFile #-}+++--------------------------------------------------------------------------+mkHeaderLine :: HttpVersion -> Response -> FixedPrim ()+mkHeaderLine outVer r =+ case outCode of+ 200 | outVer == (1, 1) ->+ -- typo in bytestring here+ fixedPrim 17 $ const (void . cpBS "HTTP/1.1 200 OK\r\n")+ 200 | otherwise ->+ fixedPrim 17 $ const (void . cpBS "HTTP/1.0 200 OK\r\n")+ _ -> fixedPrim len $ const (void . line)+ where+ outCode = rspStatus r++ v = if outVer == (1,1) then "HTTP/1.1 " else "HTTP/1.0 "++ outCodeStr = S.pack $ show outCode+ space !op = do+ pokeByteOff op 0 (32 :: Word8)+ return $! plusPtr op 1++ line = cpBS v >=> cpBS outCodeStr >=> space >=> cpBS reason+ >=> crlfPoke++ reason = rspStatusReason r+ len = 12 + S.length outCodeStr + S.length reason+++------------------------------------------------------------------------------+mkHeaderPrim :: HttpVersion -> Response -> Headers -> FixedPrim ()+mkHeaderPrim v r hdrs = mkHeaderLine v r <+> headersToPrim hdrs+++------------------------------------------------------------------------------+infixl 4 <+>+(<+>) :: FixedPrim () -> FixedPrim () -> FixedPrim ()+p1 <+> p2 = ignore >$< p1 >*< p2+ where+ ignore = join (,)+++------------------------------------------------------------------------------+{-# INLINE headersToPrim #-}+headersToPrim :: Headers -> FixedPrim ()+headersToPrim hdrs = fixedPrim len (const copy)+ where+ len = H.foldedFoldl' f 0 hdrs + 2+ where+ f l k v = l + S.length k + S.length v + 4++ copy = go $ H.unsafeToCaseFoldedList hdrs++ go [] !op = void $ crlfPoke op+ go ((k,v):xs) !op = do+ !op' <- cpBS k op+ pokeByteOff op' 0 (58 :: Word8) -- colon+ pokeByteOff op' 1 (32 :: Word8) -- space+ !op'' <- cpBS v $ plusPtr op' 2+ crlfPoke op'' >>= go xs+++{-# INLINE cpBS #-}+cpBS :: ByteString -> Ptr Word8 -> IO (Ptr Word8)+cpBS s !op = S.unsafeUseAsCStringLen s $ \(cstr, clen) -> do+ let !cl = fromIntegral clen+ copyBytes op (castPtr cstr) cl+ return $! plusPtr op cl++{-# INLINE crlfPoke #-}+crlfPoke :: Ptr Word8 -> IO (Ptr Word8)+crlfPoke !op = do+ pokeByteOff op 0 (13 :: Word8) -- cr+ pokeByteOff op 1 (10 :: Word8) -- lf+ return $! plusPtr op 2+++------------------------------------------------------------------------------+sERVER_HEADER :: ByteString+sERVER_HEADER = S.concat ["Snap/", snapServerVersion]+++------------------------------------------------------------------------------+snapServerVersion :: ByteString+snapServerVersion = S.pack $ showVersion $ V.version+++------------------------------------------------------------------------------+terminateSession :: Exception e => e -> IO a+terminateSession = E.throwIO . TerminateSessionException . SomeException+++------------------------------------------------------------------------------+requestErrorMessage :: Request -> SomeException -> Builder+requestErrorMessage req e =+ mconcat [ byteString "During processing of request from "+ , byteString $ rqClientAddr req+ , byteString ":"+ , fromShow $ rqClientPort req+ , byteString "\nrequest:\n"+ , fromShow $ show req+ , byteString "\n"+ , msgB+ ]+ where+ msgB = mconcat [+ byteString "A web handler threw an exception. Details:\n"+ , fromShow e+ ]+++------------------------------------------------------------------------------+-- | Convert 'Cookie' into 'ByteString' for output.+cookieToBS :: Cookie -> ByteString+cookieToBS (Cookie k v mbExpTime mbDomain mbPath isSec isHOnly) = cookie+ where+ cookie = S.concat [k, "=", v, path, exptime, domain, secure, hOnly]+ path = maybe "" (S.append "; path=") mbPath+ domain = maybe "" (S.append "; domain=") mbDomain+ exptime = maybe "" (S.append "; expires=" . fmt) mbExpTime+ secure = if isSec then "; Secure" else ""+ hOnly = if isHOnly then "; HttpOnly" else ""+ fmt = S.pack . formatTime defaultTimeLocale+ "%a, %d-%b-%Y %H:%M:%S GMT"+++------------------------------------------------------------------------------+renderCookies :: Response -> Headers -> Headers+renderCookies r hdrs+ | null cookies = hdrs+ | otherwise = foldl' (\m v -> H.unsafeInsert "set-cookie" v m) hdrs cookies++ where+ cookies = fmap cookieToBS . Map.elems $ rspCookies r++------------------------------------------------------------------------------+fromShow :: Show a => a -> Builder+fromShow = stringUtf8 . show
− src/Snap/Internal/Http/Server/SimpleBackend.hs
@@ -1,355 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Snap.Internal.Http.Server.SimpleBackend- ( simpleEventLoop- ) where----------------------------------------------------------------------------------import Control.Monad.Trans--import Control.Concurrent hiding (yield)-import Control.Exception-import Control.Monad-import Data.ByteString (ByteString)-import qualified Data.ByteString as S-import Data.ByteString.Internal (c2w)-import Data.Maybe-import Data.Typeable-import Data.Word-import Foreign hiding (new)-import Foreign.C-import GHC.Conc (labelThread, forkOnIO)-import Network.Socket-import Prelude hiding (catch)--------------------------------------------------------------------------------import Data.Concurrent.HashMap (hashString)-import Snap.Internal.Debug-import Snap.Internal.Http.Server.Date-import qualified Snap.Internal.Http.Server.TimeoutTable as TT-import Snap.Internal.Http.Server.TimeoutTable (TimeoutTable)-import Snap.Internal.Http.Server.Backend-import qualified Snap.Internal.Http.Server.ListenHelpers as Listen-import Snap.Iteratee hiding (map)--#if defined(HAS_SENDFILE)-import qualified System.SendFile as SF-import System.Posix.IO-import System.Posix.Types (Fd(..))-#endif------------------------------------------------------------------------------------ | For each cpu, we store:--- * A list of accept threads, one per port.--- * One timeout table and one timeout thread.--- These timeout the session threads.--- * An mvar to signal when the timeout thread is shutdown-data EventLoopCpu = EventLoopCpu- { _boundCpu :: Int- , _acceptThreads :: [ThreadId]- , _timeoutTable :: TimeoutTable- , _timeoutThread :: ThreadId- , _exitMVar :: !(MVar ())- }----------------------------------------------------------------------------------simpleEventLoop :: EventLoop-simpleEventLoop sockets cap elog handler = do- loops <- Prelude.mapM (newLoop sockets handler elog) [0..(cap-1)]-- debug "simpleEventLoop: waiting for mvars"-- --wait for all threads to exit- Prelude.mapM_ (takeMVar . _exitMVar) loops `finally` do- debug "simpleEventLoop: killing all threads"- mapM stopLoop loops- mapM Listen.closeSocket sockets----------------------------------------------------------------------------------newLoop :: [ListenSocket]- -> SessionHandler- -> (S.ByteString -> IO ())- -> Int- -> IO EventLoopCpu-newLoop sockets handler elog cpu = do- tt <- TT.new- exit <- newEmptyMVar- accThreads <- forM sockets $ \p -> forkOnIO cpu $- acceptThread handler tt elog cpu p- tid <- forkOnIO cpu $ timeoutThread tt exit-- return $ EventLoopCpu cpu accThreads tt tid exit----------------------------------------------------------------------------------stopLoop :: EventLoopCpu -> IO ()-stopLoop loop = block $ do- Prelude.mapM_ killThread $ _acceptThreads loop- killThread $ _timeoutThread loop----------------------------------------------------------------------------------acceptThread :: SessionHandler- -> TimeoutTable- -> (S.ByteString -> IO ())- -> Int- -> ListenSocket- -> IO ()-acceptThread handler tt elog cpu sock = loop- where- loop = do- debug $ "acceptThread: calling accept()"- (s,addr) <- accept $ Listen.listenSocket sock- debug $ "acceptThread: accepted connection from remote: " ++ show addr- forkOnIO cpu (go s addr `catches` cleanup)- loop-- go = runSession handler tt sock-- cleanup =- [- Handler $ \(e :: SomeException) -> elog- $ S.concat [ "SimpleBackend.acceptThread: "- , S.pack . map c2w $ show e]- ]----------------------------------------------------------------------------------timeoutThread :: TimeoutTable -> MVar () -> IO ()-timeoutThread table exitMVar = do- go `catch` (\(_::SomeException) -> killAll)- putMVar exitMVar ()-- where- go = do- debug "timeoutThread: waiting for activity on thread table"- TT.waitForActivity table- debug "timeoutThread: woke up, killing old connections"- killTooOld- go--- killTooOld = do- now <- getCurrentDateTime- TT.killOlderThan (now - tIMEOUT) table-- -- timeout = 30 seconds- tIMEOUT = 30-- killAll = do- debug "Backend.timeoutThread: shutdown, killing all connections"- TT.killAll table----------------------------------------------------------------------------------data AddressNotSupportedException = AddressNotSupportedException String- deriving (Typeable)--instance Show AddressNotSupportedException where- show (AddressNotSupportedException x) = "Address not supported: " ++ x--instance Exception AddressNotSupportedException----------------------------------------------------------------------------------runSession :: SessionHandler -> TimeoutTable -> ListenSocket -> Socket- -> SockAddr -> IO ()-runSession handler tt lsock sock addr = do- let fd = fdSocket sock- curId <- myThreadId-- debug $ "Backend.withConnection: running session: " ++ show addr- labelThread curId $ "connHndl " ++ show fd-- (rport,rhost) <-- case addr of- SockAddrInet p h -> do- h' <- inet_ntoa h- return (fromIntegral p, S.pack $ map c2w h')- x -> throwIO $ AddressNotSupportedException $ show x-- laddr <- getSocketName sock-- (lport,lhost) <-- case laddr of- SockAddrInet p h -> do- h' <- inet_ntoa h- return (fromIntegral p, S.pack $ map c2w h')- x -> throwIO $ AddressNotSupportedException $ show x-- let sinfo = SessionInfo lhost lport rhost rport $ Listen.isSecure lsock- let curHash = hashString $ show curId- let timeout = tickleTimeout tt curId curHash-- timeout-- bracket (Listen.createSession lsock 8192 fd- (threadWaitRead $ fromIntegral fd))- (\session -> block $ do- debug "thread killed, closing socket"-- -- remove thread from timeout table- TT.delete curHash curId tt-- eatException $ Listen.endSession lsock session- eatException $ shutdown sock ShutdownBoth- eatException $ sClose sock- )- (\s -> let writeEnd = writeOut lsock s sock timeout- in handler sinfo- (enumerate lsock s sock)- writeEnd- (sendFile lsock timeout fd writeEnd)- timeout- )----------------------------------------------------------------------------------eatException :: IO a -> IO ()-eatException act = (act >> return ()) `catch` \(_::SomeException) -> return ()----------------------------------------------------------------------------------sendFile :: ListenSocket- -> IO ()- -> CInt- -> Iteratee ByteString IO ()- -> FilePath- -> Int64- -> Int64- -> IO ()-#if defined(HAS_SENDFILE)-sendFile lsock tickle sock writeEnd fp start sz =- case lsock of- ListenHttp _ -> bracket (openFd fp ReadOnly Nothing defaultFileFlags)- (closeFd)- (go start sz)- _ -> do- step <- runIteratee writeEnd- run_ $ enumFilePartial fp (start,start+sz) step- where- go off bytes fd- | bytes == 0 = return ()- | otherwise = do- sent <- SF.sendFile sfd fd off bytes- if sent < bytes- then tickle >> go (off+sent) (bytes-sent) fd- else return ()-- sfd = Fd sock-#else-sendFile _ _ _ writeEnd fp start sz = do- -- no need to count bytes- step <- runIteratee writeEnd- run_ $ enumFilePartial fp (start,start+sz) step- return ()-#endif----------------------------------------------------------------------------------tickleTimeout :: TimeoutTable -> ThreadId -> Word -> IO ()-tickleTimeout table tid thash = do- debug "Backend.tickleTimeout"- now <- getCurrentDateTime- TT.insert thash tid now table----------------------------------------------------------------------------------enumerate :: (MonadIO m)- => ListenSocket- -> NetworkSession- -> Socket- -> Enumerator ByteString m a-enumerate port session sock = loop- where- dbg s = debug $ "SimpleBackend.enumerate(" ++ show (_socket session)- ++ "): " ++ s-- loop (Continue k) = do- dbg "reading from socket"- s <- liftIO $ timeoutRecv- case s of- Nothing -> do- dbg "got EOF from socket"- sendOne k ""- Just s' -> do- dbg $ "got " ++ Prelude.show (S.length s')- ++ " bytes from read end"- sendOne k s'-- loop x = returnI x--- sendOne k s | S.null s = do- dbg "sending EOF to continuation"- enumEOF $ Continue k-- | otherwise = do- dbg $ "sending " ++ show s ++ " to continuation"- step <- lift $ runIteratee $ k $ Chunks [s]- case step of- (Yield x st) -> do- dbg $ "got yield, remainder is " ++ show st- yield x st- r@(Continue _) -> do- dbg $ "got continue"- loop r- (Error e) -> throwError e-- fd = fdSocket sock-#ifdef PORTABLE- timeoutRecv = Listen.recv port sock (threadWaitRead $- fromIntegral fd) session-#else- timeoutRecv = Listen.recv port (threadWaitRead $- fromIntegral fd) session-#endif----------------------------------------------------------------------------------writeOut :: (MonadIO m)- => ListenSocket- -> NetworkSession- -> Socket- -> IO ()- -> Iteratee ByteString m ()-writeOut port session sock tickle = loop- where- dbg s = debug $ "SimpleBackend.writeOut(" ++ show (_socket session)- ++ "): " ++ s-- loop = continue k-- k EOF = yield () EOF- k (Chunks xs) = do- let s = S.concat xs- let n = S.length s- dbg $ "got chunk with " ++ show n ++ " bytes"- ee <- liftIO $ try $ timeoutSend s- case ee of- (Left (e::SomeException)) -> do- dbg $ "timeoutSend got error " ++ show e- throwError e- (Right _) -> do- let last10 = S.drop (n-10) s- dbg $ "wrote " ++ show n ++ " bytes, last 10=" ++ show last10- loop-- fd = fdSocket sock-#ifdef PORTABLE- timeoutSend = Listen.send port sock tickle- (threadWaitWrite $ fromIntegral fd) session-#else- timeoutSend = Listen.send port tickle- (threadWaitWrite $ fromIntegral fd) session-#endif
+ src/Snap/Internal/Http/Server/Socket.hs view
@@ -0,0 +1,208 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Snap.Internal.Http.Server.Socket+ ( bindSocket+ , bindSocketImpl+ , bindUnixSocket+ , httpAcceptFunc+ , haProxyAcceptFunc+ , sendFileFunc+ , acceptAndInitialize+ ) where++------------------------------------------------------------------------------+import Control.Exception (bracketOnError, finally, throwIO)+import Control.Monad (when)+import Data.Bits (complement, (.&.))+import Data.ByteString.Char8 (ByteString)+import Network.Socket (Socket, SocketOption (NoDelay, ReuseAddr), accept, close, getSocketName, setSocketOption, socket)+import qualified Network.Socket as N+#ifdef HAS_SENDFILE+import Network.Socket (fdSocket)+import System.Posix.IO (OpenMode (..), closeFd, defaultFileFlags, openFd)+import System.Posix.Types (Fd (..))+import System.SendFile (sendFile, sendHeaders)+#else+import Data.ByteString.Builder (byteString)+import Data.ByteString.Builder.Extra (flush)+import Network.Socket.ByteString (sendAll)+#endif+#ifdef HAS_UNIX_SOCKETS+import Control.Exception (bracket)+import qualified Control.Exception as E (catch)+import System.FilePath (isRelative)+import System.IO.Error (isDoesNotExistError)+import System.Posix.Files (accessModes, removeLink, setFileCreationMask)+#endif++------------------------------------------------------------------------------+import qualified System.IO.Streams as Streams+------------------------------------------------------------------------------+import Snap.Internal.Http.Server.Address (AddressNotSupportedException (..), getAddress, getSockAddr)+import Snap.Internal.Http.Server.Types (AcceptFunc (..), SendFileHandler)+import qualified System.IO.Streams.Network.HAProxy as HA+++------------------------------------------------------------------------------+bindSocket :: ByteString -> Int -> IO Socket+bindSocket = bindSocketImpl setSocketOption bind N.listen+ where+#if MIN_VERSION_network(2,7,0)+ bind = N.bind+#else+ bind = N.bindSocket+#endif+{-# INLINE bindSocket #-}+++------------------------------------------------------------------------------+bindSocketImpl+ :: (Socket -> SocketOption -> Int -> IO ()) -- ^ mock setSocketOption+ -> (Socket -> N.SockAddr -> IO ()) -- ^ bindSocket+ -> (Socket -> Int -> IO ()) -- ^ listen+ -> ByteString+ -> Int+ -> IO Socket+bindSocketImpl _setSocketOption _bindSocket _listen bindAddr bindPort = do+ (family, addr) <- getSockAddr bindPort bindAddr+ bracketOnError (socket family N.Stream 0) N.close $ \sock -> do+ _setSocketOption sock ReuseAddr 1+ _setSocketOption sock NoDelay 1+ _bindSocket sock addr+ _listen sock 150+ return $! sock++bindUnixSocket :: Maybe Int -> String -> IO Socket+#if HAS_UNIX_SOCKETS+bindUnixSocket mode path = do+ when (isRelative path) $+ throwIO $ AddressNotSupportedException+ $! "Refusing to bind unix socket to non-absolute path: " ++ path++ bracketOnError (socket N.AF_UNIX N.Stream 0) N.close $ \sock -> do+ E.catch (removeLink path) $ \e -> when (not $ isDoesNotExistError e) $ throwIO e+ case mode of+ Nothing -> bind sock (N.SockAddrUnix path)+ Just mode' -> bracket (setFileCreationMask $ modeToMask mode')+ setFileCreationMask+ (const $ bind sock (N.SockAddrUnix path))+ N.listen sock 150+ return $! sock+ where+#if MIN_VERSION_network(2,7,0)+ bind = N.bind+#else+ bind = N.bindSocket+#endif+ modeToMask p = accessModes .&. complement (fromIntegral p)+#else+bindUnixSocket _ path = throwIO (AddressNotSupportedException $ "unix:" ++ path)+#endif++------------------------------------------------------------------------------+-- TODO(greg): move buffer size configuration into config+bUFSIZ :: Int+bUFSIZ = 4064+++------------------------------------------------------------------------------+acceptAndInitialize :: Socket -- ^ bound socket+ -> (forall b . IO b -> IO b)+ -> ((Socket, N.SockAddr) -> IO a)+ -> IO a+acceptAndInitialize boundSocket restore f =+ bracketOnError (restore $ accept boundSocket)+ (close . fst)+ f+++------------------------------------------------------------------------------+haProxyAcceptFunc :: Socket -- ^ bound socket+ -> AcceptFunc+haProxyAcceptFunc boundSocket =+ AcceptFunc $ \restore ->+ acceptAndInitialize boundSocket restore $ \(sock, saddr) -> do+ (readEnd, writeEnd) <- Streams.socketToStreamsWithBufferSize+ bUFSIZ sock+ localPInfo <- HA.socketToProxyInfo sock saddr+ pinfo <- HA.decodeHAProxyHeaders localPInfo readEnd+ (localPort, localHost) <- getAddress $ HA.getDestAddr pinfo+ (remotePort, remoteHost) <- getAddress $ HA.getSourceAddr pinfo+ let cleanup = Streams.write Nothing writeEnd+ `finally` close sock+ return $! ( sendFileFunc sock+ , localHost+ , localPort+ , remoteHost+ , remotePort+ , readEnd+ , writeEnd+ , cleanup+ )+++------------------------------------------------------------------------------+httpAcceptFunc :: Socket -- ^ bound socket+ -> AcceptFunc+httpAcceptFunc boundSocket =+ AcceptFunc $ \restore ->+ acceptAndInitialize boundSocket restore $ \(sock, remoteAddr) -> do+ localAddr <- getSocketName sock+ (localPort, localHost) <- getAddress localAddr+ (remotePort, remoteHost) <- getAddress remoteAddr+ (readEnd, writeEnd) <- Streams.socketToStreamsWithBufferSize bUFSIZ+ sock+ let cleanup = Streams.write Nothing writeEnd+ `finally` close sock+ return $! ( sendFileFunc sock+ , localHost+ , localPort+ , remoteHost+ , remotePort+ , readEnd+ , writeEnd+ , cleanup+ )+++------------------------------------------------------------------------------+sendFileFunc :: Socket -> SendFileHandler+#ifdef HAS_SENDFILE+sendFileFunc sock !_ builder fPath offset nbytes = bracket acquire closeFd go+ where+#if MIN_VERSION_unix(2,8,0)+ acquire = openFd fPath ReadOnly defaultFileFlags+#else+ acquire = openFd fPath ReadOnly Nothing defaultFileFlags+#endif++#if MIN_VERSION_network(3,0,0)+ go fileFd = do sockFd <- Fd `fmap` fdSocket sock+ sendHeaders builder sockFd+ sendFile sockFd fileFd offset nbytes+#else+ go fileFd = do let sockFd = Fd $ fdSocket sock+ sendHeaders builder sockFd+ sendFile sockFd fileFd offset nbytes+#endif++#else+sendFileFunc sock buffer builder fPath offset nbytes =+ Streams.unsafeWithFileAsInputStartingAt (fromIntegral offset) fPath $+ \fileInput0 -> do+ fileInput <- Streams.takeBytes (fromIntegral nbytes) fileInput0 >>=+ Streams.map byteString+ input <- Streams.fromList [builder] >>=+ flip Streams.appendInputStream fileInput+ output <- Streams.makeOutputStream sendChunk >>=+ Streams.unsafeBuilderStream (return buffer)+ Streams.supply input output+ Streams.write (Just flush) output++ where+ sendChunk (Just s) = sendAll sock s+ sendChunk Nothing = return $! ()+#endif
+ src/Snap/Internal/Http/Server/TLS.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++------------------------------------------------------------------------------+module Snap.Internal.Http.Server.TLS+ ( TLSException(..)+ , withTLS+ , bindHttps+ , httpsAcceptFunc+ , sendFileFunc+ ) where++------------------------------------------------------------------------------+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import Data.Typeable (Typeable)+import Network.Socket (Socket)+#ifdef OPENSSL+import Control.Exception (Exception, bracketOnError, finally, onException, throwIO)+import Control.Monad (when)+import Data.ByteString.Builder (byteString)+import qualified Network.Socket as Socket+import OpenSSL (withOpenSSL)+import OpenSSL.Session (SSL, SSLContext)+import qualified OpenSSL.Session as SSL+import Prelude (Bool, FilePath, IO, Int, Maybe (..), Monad (..), Show, flip, fromIntegral, not, ($), ($!))+import Snap.Internal.Http.Server.Address (getAddress)+import Snap.Internal.Http.Server.Socket (acceptAndInitialize, bindSocket)+import qualified System.IO.Streams as Streams+import qualified System.IO.Streams.SSL as SStreams++#else+import Control.Exception (Exception, throwIO)+import Prelude (Bool, FilePath, IO, Int, Show, id, ($))+#endif+------------------------------------------------------------------------------+import Snap.Internal.Http.Server.Types (AcceptFunc (..), SendFileHandler)+------------------------------------------------------------------------------++data TLSException = TLSException S.ByteString+ deriving (Show, Typeable)+instance Exception TLSException++#ifndef OPENSSL+type SSLContext = ()+type SSL = ()++------------------------------------------------------------------------------+sslNotSupportedException :: TLSException+sslNotSupportedException = TLSException $ S.concat [+ "This version of snap-server was not built with SSL "+ , "support.\n"+ , "Please compile snap-server with -fopenssl to enable it."+ ]+++------------------------------------------------------------------------------+withTLS :: IO a -> IO a+withTLS = id+++------------------------------------------------------------------------------+barf :: IO a+barf = throwIO sslNotSupportedException+++------------------------------------------------------------------------------+bindHttps :: ByteString -> Int -> FilePath -> Bool -> FilePath+ -> IO (Socket, SSLContext)+bindHttps _ _ _ _ _ = barf+++------------------------------------------------------------------------------+httpsAcceptFunc :: Socket -> SSLContext -> AcceptFunc+httpsAcceptFunc _ _ = AcceptFunc $ \restore -> restore barf+++------------------------------------------------------------------------------+sendFileFunc :: SSL -> Socket -> SendFileHandler+sendFileFunc _ _ _ _ _ _ _ = barf+++#else+------------------------------------------------------------------------------+withTLS :: IO a -> IO a+withTLS = withOpenSSL+++------------------------------------------------------------------------------+bindHttps :: ByteString+ -> Int+ -> FilePath+ -> Bool+ -> FilePath+ -> IO (Socket, SSLContext)+bindHttps bindAddress bindPort cert chainCert key =+ withTLS $+ bracketOnError+ (bindSocket bindAddress bindPort)+ Socket.close+ $ \sock -> do+ ctx <- SSL.context+ SSL.contextSetPrivateKeyFile ctx key+ if chainCert+ then SSL.contextSetCertificateChainFile ctx cert+ else SSL.contextSetCertificateFile ctx cert+ certOK <- SSL.contextCheckPrivateKey ctx+ when (not certOK) $ do+ throwIO $ TLSException certificateError+ return (sock, ctx)+ where+ certificateError =+ "OpenSSL says that the certificate doesn't match the private key!"+++------------------------------------------------------------------------------+httpsAcceptFunc :: Socket+ -> SSLContext+ -> AcceptFunc+httpsAcceptFunc boundSocket ctx =+ AcceptFunc $ \restore ->+ acceptAndInitialize boundSocket restore $ \(sock, remoteAddr) -> do+ localAddr <- Socket.getSocketName sock+ (localPort, localHost) <- getAddress localAddr+ (remotePort, remoteHost) <- getAddress remoteAddr+ ssl <- restore (SSL.connection ctx sock)++ restore (SSL.accept ssl) `onException` Socket.close sock++ (readEnd, writeEnd) <- SStreams.sslToStreams ssl++ let cleanup = (do Streams.write Nothing writeEnd+ SSL.shutdown ssl $! SSL.Unidirectional)+ `finally` Socket.close sock++ return $! ( sendFileFunc ssl+ , localHost+ , localPort+ , remoteHost+ , remotePort+ , readEnd+ , writeEnd+ , cleanup+ )+++------------------------------------------------------------------------------+sendFileFunc :: SSL -> SendFileHandler+sendFileFunc ssl buffer builder fPath offset nbytes = do+ Streams.unsafeWithFileAsInputStartingAt (fromIntegral offset) fPath $ \fileInput0 -> do+ fileInput <- Streams.takeBytes (fromIntegral nbytes) fileInput0 >>=+ Streams.map byteString+ input <- Streams.fromList [builder] >>=+ flip Streams.appendInputStream fileInput+ output <- Streams.makeOutputStream sendChunk >>=+ Streams.unsafeBuilderStream (return buffer)+ Streams.supply input output+ Streams.write Nothing output++ where+ sendChunk (Just s) = SSL.write ssl s+ sendChunk Nothing = return $! ()+#endif
+ src/Snap/Internal/Http/Server/Thread.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE RankNTypes #-}++module Snap.Internal.Http.Server.Thread+ ( SnapThread+ , fork+ , forkOn+ , cancel+ , wait+ , cancelAndWait+ , isFinished+ ) where++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<$>))+#endif+import Control.Concurrent (MVar, ThreadId, killThread, newEmptyMVar, putMVar, readMVar)+#if MIN_VERSION_base(4,7,0)+import Control.Concurrent (tryReadMVar)+#else+import Control.Concurrent (tryTakeMVar)+import Control.Monad (when)+import Data.Maybe (fromJust, isJust)+#endif+import Control.Concurrent.Extended (forkIOLabeledWithUnmaskBs, forkOnLabeledWithUnmaskBs)+import qualified Control.Exception as E+import Control.Monad (void)+import qualified Data.ByteString.Char8 as B+import GHC.Exts (inline)++#if !MIN_VERSION_base(4,7,0)+tryReadMVar :: MVar a -> IO (Maybe a)+tryReadMVar mv = do+ m <- tryTakeMVar mv+ when (isJust m) $ putMVar mv (fromJust m)+ return m+#endif++------------------------------------------------------------------------------+data SnapThread = SnapThread {+ _snapThreadId :: {-# UNPACK #-} !ThreadId+ , _snapThreadFinished :: {-# UNPACK #-} !(MVar ())+ }++instance Show SnapThread where+ show = show . _snapThreadId+++------------------------------------------------------------------------------+forkOn :: B.ByteString -- ^ thread label+ -> Int -- ^ capability+ -> ((forall a . IO a -> IO a) -> IO ()) -- ^ user thread action, taking+ -- a restore function+ -> IO SnapThread+forkOn label cap action = do+ mv <- newEmptyMVar+ E.uninterruptibleMask_ $ do+ tid <- forkOnLabeledWithUnmaskBs label cap (wrapAction mv action)+ return $! SnapThread tid mv+++------------------------------------------------------------------------------+fork :: B.ByteString -- ^ thread label+ -> ((forall a . IO a -> IO a) -> IO ()) -- ^ user thread action, taking+ -- a restore function+ -> IO SnapThread+fork label action = do+ mv <- newEmptyMVar+ E.uninterruptibleMask_ $ do+ tid <- forkIOLabeledWithUnmaskBs label (wrapAction mv action)+ return $! SnapThread tid mv+++------------------------------------------------------------------------------+cancel :: SnapThread -> IO ()+cancel = killThread . _snapThreadId+++------------------------------------------------------------------------------+wait :: SnapThread -> IO ()+wait = void . readMVar . _snapThreadFinished+++------------------------------------------------------------------------------+cancelAndWait :: SnapThread -> IO ()+cancelAndWait t = cancel t >> wait t+++------------------------------------------------------------------------------+isFinished :: SnapThread -> IO Bool+isFinished t =+ maybe False (const True) <$> tryReadMVar (_snapThreadFinished t)+++------------------------------------------------------------------------------+-- Internal functions follow+------------------------------------------------------------------------------+wrapAction :: MVar ()+ -> ((forall a . IO a -> IO a) -> IO ())+ -> ((forall a . IO a -> IO a) -> IO ())+wrapAction mv action restore = (action restore >> inline exit) `E.catch` onEx+ where+ onEx :: E.SomeException -> IO ()+ onEx !_ = inline exit++ exit = E.uninterruptibleMask_ (putMVar mv $! ())
+ src/Snap/Internal/Http/Server/TimeoutManager.hs view
@@ -0,0 +1,229 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Internal.Http.Server.TimeoutManager+ ( TimeoutManager+ , TimeoutThread+ , initialize+ , stop+ , register+ , tickle+ , set+ , modify+ , cancel+ ) where++------------------------------------------------------------------------------+import Control.Exception (evaluate, finally)+import qualified Control.Exception as E+import Control.Monad (Monad (return, (>>=)), mapM_, void, when)+import qualified Data.ByteString.Char8 as S+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import Prelude (Bool, Double, IO, Int, Show (..), const, fromIntegral, max, null, otherwise, round, ($), ($!), (+), (++), (-), (.), (<=), (==))+------------------------------------------------------------------------------+import Control.Concurrent (MVar, newEmptyMVar, putMVar, readMVar, takeMVar, tryPutMVar)+------------------------------------------------------------------------------+import Snap.Internal.Http.Server.Clock (ClockTime)+import qualified Snap.Internal.Http.Server.Clock as Clock+import Snap.Internal.Http.Server.Common (atomicModifyIORef', eatException)+import qualified Snap.Internal.Http.Server.Thread as T+++------------------------------------------------------------------------------+type State = ClockTime++canceled :: State+canceled = 0++isCanceled :: State -> Bool+isCanceled = (== 0)+++------------------------------------------------------------------------------+data TimeoutThread = TimeoutThread {+ _thread :: !T.SnapThread+ , _state :: !(IORef State)+ , _hGetTime :: !(IO ClockTime)+ }++instance Show TimeoutThread where+ show = show . _thread+++------------------------------------------------------------------------------+-- | Given a 'State' value and the current time, apply the given modification+-- function to the amount of time remaining.+--+smap :: ClockTime -> (ClockTime -> ClockTime) -> State -> State+smap now f deadline | isCanceled deadline = deadline+ | otherwise = t'+ where+ remaining = max 0 (deadline - now)+ newremaining = f remaining+ t' = now + newremaining+++------------------------------------------------------------------------------+data TimeoutManager = TimeoutManager {+ _defaultTimeout :: !ClockTime+ , _pollInterval :: !ClockTime+ , _getTime :: !(IO ClockTime)+ , _threads :: !(IORef [TimeoutThread])+ , _morePlease :: !(MVar ())+ , _managerThread :: !(MVar T.SnapThread)+ }+++------------------------------------------------------------------------------+-- | Create a new TimeoutManager.+initialize :: Double -- ^ default timeout+ -> Double -- ^ poll interval+ -> IO ClockTime -- ^ function to get current time+ -> IO TimeoutManager+initialize defaultTimeout interval getTime = E.uninterruptibleMask_ $ do+ conns <- newIORef []+ mp <- newEmptyMVar+ mthr <- newEmptyMVar++ let tm = TimeoutManager (Clock.fromSecs defaultTimeout)+ (Clock.fromSecs interval)+ getTime+ conns+ mp+ mthr++ thr <- T.fork "snap-server: timeout manager" $ managerThread tm+ putMVar mthr thr+ return tm+++------------------------------------------------------------------------------+-- | Stop a TimeoutManager.+stop :: TimeoutManager -> IO ()+stop tm = readMVar (_managerThread tm) >>= T.cancelAndWait+++------------------------------------------------------------------------------+wakeup :: TimeoutManager -> IO ()+wakeup tm = void $ tryPutMVar (_morePlease tm) $! ()+++------------------------------------------------------------------------------+-- | Register a new thread with the TimeoutManager.+register :: TimeoutManager -- ^ manager to register+ -- with+ -> S.ByteString -- ^ thread label+ -> ((forall a . IO a -> IO a) -> IO ()) -- ^ thread action to run+ -> IO TimeoutThread+register tm label action = do+ now <- getTime+ let !state = now + defaultTimeout+ stateRef <- newIORef state+ th <- E.uninterruptibleMask_ $ do+ t <- T.fork label action+ let h = TimeoutThread t stateRef getTime+ atomicModifyIORef' threads (\x -> (h:x, ())) >>= evaluate+ return $! h+ wakeup tm+ return th++ where+ getTime = _getTime tm+ threads = _threads tm+ defaultTimeout = _defaultTimeout tm+++------------------------------------------------------------------------------+-- | Tickle the timeout on a connection to be at least N seconds into the+-- future. If the existing timeout is set for M seconds from now, where M > N,+-- then the timeout is unaffected.+tickle :: TimeoutThread -> Int -> IO ()+tickle th = modify th . max+{-# INLINE tickle #-}+++------------------------------------------------------------------------------+-- | Set the timeout on a connection to be N seconds into the future.+set :: TimeoutThread -> Int -> IO ()+set th = modify th . const+{-# INLINE set #-}+++------------------------------------------------------------------------------+-- | Modify the timeout with the given function.+modify :: TimeoutThread -> (Int -> Int) -> IO ()+modify th f = do+ now <- getTime+ state <- readIORef stateRef+ let !state' = smap now f' state+ writeIORef stateRef state'++ where+ f' !x = Clock.fromSecs $! fromIntegral $ f $ round $ Clock.toSecs x+ getTime = _hGetTime th+ stateRef = _state th+{-# INLINE modify #-}+++------------------------------------------------------------------------------+-- | Cancel a timeout.+cancel :: TimeoutThread -> IO ()+cancel h = E.uninterruptibleMask_ $ do+ writeIORef (_state h) canceled+ T.cancel $ _thread h+{-# INLINE cancel #-}+++------------------------------------------------------------------------------+managerThread :: TimeoutManager -> (forall a. IO a -> IO a) -> IO ()+managerThread tm restore = restore loop `finally` cleanup+ where+ cleanup = E.uninterruptibleMask_ $+ eatException (readIORef threads >>= destroyAll)++ --------------------------------------------------------------------------+ getTime = _getTime tm+ morePlease = _morePlease tm+ pollInterval = _pollInterval tm+ threads = _threads tm++ --------------------------------------------------------------------------+ loop = do+ now <- getTime+ E.uninterruptibleMask $ \restore' -> do+ handles <- atomicModifyIORef' threads (\x -> ([], x))+ if null handles+ then do restore' $ takeMVar morePlease+ else do+ handles' <- processHandles now handles+ atomicModifyIORef' threads (\x -> (handles' ++ x, ()))+ >>= evaluate+ Clock.sleepFor pollInterval+ loop++ --------------------------------------------------------------------------+ processHandles now handles = go handles []+ where+ go [] !kept = return $! kept++ go (x:xs) !kept = do+ !state <- readIORef $ _state x+ !kept' <-+ if isCanceled state+ then do b <- T.isFinished (_thread x)+ return $! if b+ then kept+ else (x:kept)+ else do when (state <= now) $ do+ T.cancel (_thread x)+ writeIORef (_state x) canceled+ return (x:kept)+ go xs kept'++ --------------------------------------------------------------------------+ destroyAll xs = do+ mapM_ (T.cancel . _thread) xs+ mapM_ (T.wait . _thread) xs
− src/Snap/Internal/Http/Server/TimeoutTable.hs
@@ -1,139 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE TemplateHaskell #-}--module Snap.Internal.Http.Server.TimeoutTable- ( TimeoutTable- , new- , null- , insert- , delete- , killAll- , killOlderThan- , waitForActivity- )-where----------------------------------------------------------------------------------import Control.Concurrent-import Control.Monad-import Data.Bits-import qualified Data.PSQueue as PSQ-import Data.PSQueue (PSQ)-import qualified Data.Vector as V-import Data.Vector (Vector)-import Data.Word-import Foreign.C.Types (CTime)-import GHC.Conc (numCapabilities)-import Prelude hiding (null)--------------------------------------------------------------------------------import Data.Concurrent.HashMap (nextHighestPowerOf2)----------------------------------------------------------------------------------type TT = PSQ ThreadId CTime----------------------------------------------------------------------------------data TimeoutTable = TimeoutTable {- _maps :: !(Vector (MVar TT))- , _activity :: !(MVar ())-}----------------------------------------------------------------------------------defaultNumberOfLocks :: Word-defaultNumberOfLocks = nextHighestPowerOf2 $ toEnum $ 8 * numCapabilities----------------------------------------------------------------------------------hashToBucket :: Word -> Word-hashToBucket x = x .&. (defaultNumberOfLocks-1)----------------------------------------------------------------------------------new :: IO TimeoutTable-new = do- vector <- V.replicateM (fromEnum defaultNumberOfLocks) (newMVar PSQ.empty)- act <- newEmptyMVar- return $ TimeoutTable vector act----------------------------------------------------------------------------------null :: TimeoutTable -> IO Bool-null (TimeoutTable maps _) = do- nulls <- V.mapM (\mv -> withMVar mv $ return . PSQ.null) maps- return $ V.and nulls----------------------------------------------------------------------------------insert :: Word -> ThreadId -> CTime -> TimeoutTable -> IO ()-insert thash tid time (TimeoutTable maps act) = do- modifyMVar_ psqMv $ \psq -> do- let !psq' = PSQ.insert tid time psq- return $! psq'-- tryPutMVar act ()- return ()-- where- bucket = hashToBucket thash- psqMv = V.unsafeIndex maps $ fromEnum bucket----------------------------------------------------------------------------------delete :: Word -> ThreadId -> TimeoutTable -> IO ()-delete thash tid (TimeoutTable maps act) = do- modifyMVar_ psqMv $ \psq -> do- let !psq' = PSQ.delete tid psq- return $! psq'-- tryPutMVar act ()- return ()-- where- bucket = hashToBucket thash- psqMv = V.unsafeIndex maps $ fromEnum bucket----------------------------------------------------------------------------------killAll :: TimeoutTable -> IO ()-killAll (TimeoutTable maps _) = do- V.mapM_ k maps-- where- k psqMV = modifyMVar_ psqMV $ \psq -> do- mapM_ killThread $ PSQ.keys psq- return PSQ.empty----------------------------------------------------------------------------------killOlderThan :: CTime -> TimeoutTable -> IO ()-killOlderThan time (TimeoutTable maps _) = do- V.mapM_ processPSQ maps-- where- processPSQ psqMV = modifyMVar_ psqMV $ \psq -> do- let (psq', threads) = findOlder psq []- mapM_ killThread threads- return psq'-- findOlder psq l =- let mmin = PSQ.findMin psq- in maybe (psq,l)- (\m -> if PSQ.prio m <= time- then findOlder (PSQ.deleteMin psq) ((PSQ.key m):l)- else (psq,l))- mmin----------------------------------------------------------------------------------waitForActivity :: TimeoutTable -> IO ()-waitForActivity t@(TimeoutTable _ act) = do- takeMVar act- b <- null t-- -- if the table is not empty, put the activity mvar back- unless b $ (tryPutMVar act () >> return ())-- threadDelay 2500000
+ src/Snap/Internal/Http/Server/Types.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE RankNTypes #-}+------------------------------------------------------------------------------+-- | Types internal to the implementation of the Snap HTTP server.+module Snap.Internal.Http.Server.Types+ ( ServerConfig(..)+ , PerSessionData(..)+ , DataFinishedHook+ , EscapeSnapHook+ , ExceptionHook+ , ParseHook+ , NewRequestHook+ , UserHandlerFinishedHook++ -- * Handlers+ , SendFileHandler+ , ServerHandler+ , AcceptFunc(..)++ -- * Socket types+ , SocketConfig(..)+ ) where++------------------------------------------------------------------------------+import Control.Exception (SomeException)+import Data.ByteString (ByteString)+import Data.IORef (IORef)+import Data.Word (Word64)+import Network.Socket (Socket)+------------------------------------------------------------------------------+import Data.ByteString.Builder (Builder)+import Data.ByteString.Builder.Internal (Buffer)+import System.IO.Streams (InputStream, OutputStream)+------------------------------------------------------------------------------+import Snap.Core (Request, Response)+++------------------------------------------------------------------------------+-- | The 'NewRequestHook' is called once processing for an HTTP request begins,+-- i.e. after the connection has been accepted and we know that there's data+-- available to read from the socket. The IORef passed to the hook initially+-- contains a bottom value that will throw an exception if evaluated.+type NewRequestHook hookState = PerSessionData -> IO hookState++-- | The 'ParseHook' is called after the HTTP Request has been parsed by the+-- server, but before the user handler starts running.+type ParseHook hookState = IORef hookState -> Request -> IO ()++-- | The 'UserHandlerFinishedHook' is called once the user handler has finished+-- running, but before the data for the HTTP response starts being sent to the+-- client.+type UserHandlerFinishedHook hookState =+ IORef hookState -> Request -> Response -> IO ()++-- | The 'DataFinishedHook' is called once the server has finished sending the+-- HTTP response to the client.+type DataFinishedHook hookState =+ IORef hookState -> Request -> Response -> IO ()++-- | The 'ExceptionHook' is called if an exception reaches the toplevel of the+-- server, i.e. if an exception leaks out of the user handler or if an+-- exception is raised during the sending of the HTTP response data.+type ExceptionHook hookState = IORef hookState -> SomeException -> IO ()++-- | The 'EscapeSnapHook' is called if the user handler escapes the HTTP+-- session, e.g. for websockets.+type EscapeSnapHook hookState = IORef hookState -> IO ()+++ ---------------------+ -- data structures --+ ---------------------+------------------------------------------------------------------------------+-- | Data and services that all HTTP response handlers share.+--+data ServerConfig hookState = ServerConfig+ { _logAccess :: !(Request -> Response -> Word64 -> IO ())+ , _logError :: !(Builder -> IO ())+ , _onNewRequest :: !(NewRequestHook hookState)+ , _onParse :: !(ParseHook hookState)+ , _onUserHandlerFinished :: !(UserHandlerFinishedHook hookState)+ , _onDataFinished :: !(DataFinishedHook hookState)+ , _onException :: !(ExceptionHook hookState)+ , _onEscape :: !(EscapeSnapHook hookState)++ -- | will be overridden by a @Host@ header if it appears.+ , _localHostname :: !ByteString+ , _defaultTimeout :: {-# UNPACK #-} !Int+ , _isSecure :: !Bool++ -- | Number of accept loops to spawn.+ , _numAcceptLoops :: {-# UNPACK #-} !Int+ }+++------------------------------------------------------------------------------+-- | All of the things a session needs to service a single HTTP request.+data PerSessionData = PerSessionData+ { -- | If the bool stored in this IORef becomes true, the server will close+ -- the connection after the current request is processed.+ _forceConnectionClose :: {-# UNPACK #-} !(IORef Bool)++ -- | An IO action to modify the current request timeout.+ , _twiddleTimeout :: !((Int -> Int) -> IO ())++ -- | The value stored in this IORef is True if this request is the first+ -- on a new connection, and False if it is a subsequent keep-alive+ -- request.+ , _isNewConnection :: !(IORef Bool)++ -- | The function called when we want to use @sendfile().@+ , _sendfileHandler :: !SendFileHandler++ -- | The server's idea of its local address.+ , _localAddress :: !ByteString++ -- | The listening port number.+ , _localPort :: {-# UNPACK #-} !Int++ -- | The address of the remote user.+ , _remoteAddress :: !ByteString++ -- | The remote user's port.+ , _remotePort :: {-# UNPACK #-} !Int++ -- | The read end of the socket connection.+ , _readEnd :: !(InputStream ByteString)++ -- | The write end of the socket connection.+ , _writeEnd :: !(OutputStream ByteString)+ }+++------------------------------------------------------------------------------+newtype AcceptFunc = AcceptFunc {+ runAcceptFunc :: (forall a . IO a -> IO a) -- exception restore function+ -> IO ( SendFileHandler -- what to do on sendfile+ , ByteString -- local address+ , Int -- local port+ , ByteString -- remote address+ , Int -- remote port+ , InputStream ByteString -- socket read end+ , OutputStream ByteString -- socket write end+ , IO () -- cleanup action+ )+ }++ --------------------+ -- function types --+ --------------------+------------------------------------------------------------------------------+-- | This function, provided to the web server internals from the outside, is+-- responsible for producing a 'Response' once the server has parsed the+-- 'Request'.+--+type ServerHandler hookState =+ ServerConfig hookState -- ^ global server config+ -> PerSessionData -- ^ per-connection data+ -> Request -- ^ HTTP request object+ -> IO (Request, Response)+++------------------------------------------------------------------------------+-- | A 'SendFileHandler' is called if the user handler requests that a file be+-- sent using @sendfile()@ on systems that support it (Linux, Mac OSX, and+-- FreeBSD).+type SendFileHandler =+ Buffer -- ^ builder buffer+ -> Builder -- ^ status line and headers+ -> FilePath -- ^ file to send+ -> Word64 -- ^ start offset+ -> Word64 -- ^ number of bytes+ -> IO ()++++ -------------------------------+ -- types for server backends --+ -------------------------------++------------------------------------------------------------------------------+-- | Either the server should start listening on the given interface \/ port+-- combination, or the server should start up with a 'Socket' that has already+-- had @bind()@ and @listen()@ called on it.+data SocketConfig = StartListening ByteString Int+ | PreBound Socket
− src/Snap/Internal/Http/Server/gnutls_helpers.c
@@ -1,17 +0,0 @@-#include <gnutls/gnutls.h>-#include <gcrypt.h>-#include <errno.h>-#include <pthread.h>-GCRY_THREAD_OPTION_PTHREAD_IMPL;--/* See http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html */--static int threading_init = 0;- -void gnutls_set_threading_helper()-{- if (!threading_init) {- gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);- threading_init = 1;- }-}
src/System/FastLogger.hs view
@@ -1,46 +1,52 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} module System.FastLogger-( Logger-, timestampedLogEntry-, combinedLogEntry-, newLogger-, logMsg-, stopLogger-) where-+ ( Logger+ , timestampedLogEntry+ , combinedLogEntry+ , newLogger+ , newLoggerWithCustomErrorFunction+ , withLogger+ , withLoggerWithCustomErrorFunction+ , stopLogger+ , logMsg+ ) where -------------------------------------------------------------------------------import Control.Concurrent-import Control.Exception-import Control.Monad-import Data.ByteString.Char8 (ByteString)-import qualified Data.ByteString.Char8 as S-import qualified Data.ByteString.Lazy.Char8 as L-import Data.ByteString.Internal (c2w)-import Data.DList (DList)-import qualified Data.DList as D-import Data.Int-import Data.IORef-import Data.Maybe-import Data.Serialize.Put-import Prelude hiding (catch, show)-import qualified Prelude-import System.IO-import Text.Show.ByteString hiding (runPut)--import Snap.Internal.Http.Server.Date+import Control.Concurrent (MVar, ThreadId, killThread, newEmptyMVar, putMVar, takeMVar, threadDelay, tryPutMVar, withMVar)+import Control.Concurrent.Extended (forkIOLabeledWithUnmaskBs)+import Control.Exception (AsyncException, Handler (..), IOException, SomeException, bracket, catch, catches, mask_)+import Control.Monad (unless, void, when)+import Data.ByteString.Builder (Builder, byteString, char8, stringUtf8, toLazyByteString, toLazyByteString)+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import Data.Monoid (mappend, mconcat, mempty)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Word (Word64)+import Prelude (Eq (..), FilePath, IO, Int, Maybe, Monad (..), Num (..), Ord (..), Show (..), mapM_, maybe, ($), ($!), (++), (.), (||))+import System.IO (IOMode (AppendMode), hClose, hFlush, openFile, stderr, stdout)+import System.PosixCompat.Time (epochTime)+------------------------------------------------------------------------------+import Snap.Internal.Http.Server.Common (atomicModifyIORef')+import Snap.Internal.Http.Server.Date (getLogDateString) ------------------------------------------------------------------------------ -- | Holds the state for a logger. data Logger = Logger- { _queuedMessages :: !(IORef (DList ByteString))+ { _queuedMessages :: !(IORef Builder) , _dataWaiting :: !(MVar ()) , _loggerPath :: !(FilePath)- , _loggingThread :: !(MVar ThreadId) }+ , _loggingThread :: !(MVar ThreadId)+ , _errAction :: ByteString -> IO ()+ } ------------------------------------------------------------------------------@@ -48,77 +54,123 @@ -- \"-\", then log to stdout; if it's \"stderr\" then we log to stderr, -- otherwise we log to a regular file in append mode. The file is closed and -- re-opened every 15 minutes to facilitate external log rotation.-newLogger :: FilePath -> IO Logger-newLogger fp = do- q <- newIORef D.empty+newLogger :: FilePath -- ^ log file to use+ -> IO Logger+newLogger = newLoggerWithCustomErrorFunction+ (\s -> S.hPutStr stderr s >> hFlush stderr)+++------------------------------------------------------------------------------+-- | Like 'newLogger', but uses a custom error action if the logger needs to+-- print an error message of its own (for instance, if it can't open the+-- output file.)+newLoggerWithCustomErrorFunction :: (ByteString -> IO ())+ -- ^ logger uses this action to log any+ -- error messages of its own+ -> FilePath -- ^ log file to use+ -> IO Logger+newLoggerWithCustomErrorFunction errAction fp = do+ q <- newIORef mempty dw <- newEmptyMVar th <- newEmptyMVar - let lg = Logger q dw fp th+ let lg = Logger q dw fp th errAction - tid <- forkIO $ loggingThread lg- putMVar th tid+ mask_ $ do+ tid <- forkIOLabeledWithUnmaskBs "snap-server: logging" $+ loggingThread lg+ putMVar th tid return lg ------------------------------------------------------------------------------+-- | Creates a Logger and passes it into the given function, cleaning up+-- with \"stopLogger\" afterwards.+withLogger :: FilePath -- ^ log file to use+ -> (Logger -> IO a)+ -> IO a+withLogger f = bracket (newLogger f) stopLogger+++------------------------------------------------------------------------------+-- | Creates a Logger with \"newLoggerWithCustomErrorFunction\" and passes it+-- into the given function, cleaning up with \"stopLogger\" afterwards.+withLoggerWithCustomErrorFunction :: (ByteString -> IO ())+ -- ^ logger uses this action to log any+ -- error messages of its own+ -> FilePath -- ^ log file to use+ -> (Logger -> IO a)+ -> IO a+withLoggerWithCustomErrorFunction e f =+ bracket (newLoggerWithCustomErrorFunction e f) stopLogger+++------------------------------------------------------------------------------+-- FIXME: can be a builder, and we could even use the same trick we use for+-- HTTP+-- -- | Prepares a log message with the time prepended. timestampedLogEntry :: ByteString -> IO ByteString timestampedLogEntry msg = do timeStr <- getLogDateString - return $! runPut $! do- putWord8 $ c2w '['- putByteString timeStr- putByteString "] "- putByteString msg+ return $! S.concat+ $ L.toChunks+ $ toLazyByteString+ $ mconcat [ char8 '['+ , byteString timeStr+ , byteString "] "+ , byteString msg ] ------------------------------------------------------------------------------+-- FIXME: builder+-- -- | Prepares a log message in \"combined\" format. combinedLogEntry :: ByteString -- ^ remote host -> Maybe ByteString -- ^ remote user -> ByteString -- ^ request line (up to you to ensure -- there are no quotes in here) -> Int -- ^ status code- -> Maybe Int64 -- ^ num bytes sent+ -> Word64 -- ^ num bytes sent -> Maybe ByteString -- ^ referer (up to you to ensure -- there are no quotes in here) -> ByteString -- ^ user agent (up to you to ensure -- there are no quotes in here) -> IO ByteString-combinedLogEntry !host !mbUser !req !status !mbNumBytes !mbReferer !ua = do- let user = fromMaybe "-" mbUser- let numBytes = maybe "-" (\s -> strict $ show s) mbNumBytes- let referer = maybe "-" (\s -> S.concat ["\"", s, "\""]) mbReferer-+combinedLogEntry !host !mbUser !req !status !numBytes !mbReferer !ua = do timeStr <- getLogDateString - let !p = [ host- , " - "+ let !l = [ byteString host+ , byteString " - " , user- , " ["- , timeStr- , "] \""- , req- , "\" "- , strict $ show status- , " "- , numBytes- , " "+ , byteString " ["+ , byteString timeStr+ , byteString "] \""+ , byteString req+ , byteString "\" "+ , fromShow status+ , space+ , fromShow numBytes+ , space , referer- , " \""- , ua- , "\"" ]-- let !output = S.concat p-- return $! output+ , byteString " \""+ , byteString ua+ , quote ] + return $! S.concat . L.toChunks $ toLazyByteString $ mconcat l where- strict = S.concat . L.toChunks+ dash = char8 '-'+ quote = char8 '\"'+ space = char8 ' '+ user = maybe dash byteString mbUser+ referer = maybe dash+ (\s -> mconcat [ quote+ , byteString s+ , quote ])+ mbReferer ------------------------------------------------------------------------------@@ -127,73 +179,88 @@ -- (or use 'combinedLogEntry'). logMsg :: Logger -> ByteString -> IO () logMsg !lg !s = do- let !s' = S.snoc s '\n'- atomicModifyIORef (_queuedMessages lg) $ \d -> (D.snoc d s',())- tryPutMVar (_dataWaiting lg) () >> return ()+ let !s' = byteString s `mappend` char8 '\n'+ atomicModifyIORef' (_queuedMessages lg) $ \d -> (d `mappend` s',())+ void $ tryPutMVar (_dataWaiting lg) () -------------------------------------------------------------------------------loggingThread :: Logger -> IO ()-loggingThread (Logger queue notifier filePath _) = do+loggingThread :: Logger -> (forall a. IO a -> IO a) -> IO ()+loggingThread (Logger queue notifier filePath _ errAct) unmask = do initialize >>= go where- openIt = if filePath == "-"- then return stdout- else if filePath == "stderr"- then return stderr- else openFile filePath AppendMode+ openIt =+ if filePath == "-"+ then return stdout+ else+ if filePath == "stderr"+ then return stderr+ else openFile filePath AppendMode `catch`+ \(e::IOException) -> do+ logInternalError $ "Can't open log file \"" +++ filePath ++ "\".\n"+ logInternalError $ "Exception: " ++ show e ++ "\n"+ logInternalError $ "Logging to stderr instead. " +++ "**THIS IS BAD, YOU OUGHT TO " +++ "FIX THIS**\n\n"+ return stderr - closeIt h = if filePath == "-" || filePath == "stderr"- then return ()- else hClose h+ closeIt h = unless (h == stdout || h == stderr) $+ hClose h - go (href, lastOpened) =- (loop (href, lastOpened))- `catches`+ logInternalError = errAct . T.encodeUtf8 . T.pack++ --------------------------------------------------------------------------+ go (href, lastOpened) = unmask loop `catches` [ Handler $ \(_::AsyncException) -> killit (href, lastOpened) , Handler $ \(e::SomeException) -> do- hPutStrLn stderr $ "logger got exception: " ++ Prelude.show e+ logInternalError $ "logger got exception: "+ ++ Prelude.show e ++ "\n" threadDelay 20000000 go (href, lastOpened) ]-+ where+ loop = waitFlushDelay (href, lastOpened) >> loop + -------------------------------------------------------------------------- initialize = do lh <- openIt href <- newIORef lh- t <- getCurrentDateTime+ t <- epochTime tref <- newIORef t return (href, tref) + -------------------------------------------------------------------------- killit (href, lastOpened) = do flushIt (href, lastOpened) h <- readIORef href closeIt h -+ -------------------------------------------------------------------------- flushIt (!href, !lastOpened) = do- dl <- atomicModifyIORef queue $ \x -> (D.empty,x)+ dl <- atomicModifyIORef' queue $ \x -> (mempty,x) - let !msgs = D.toList dl- let !s = L.fromChunks msgs+ let !msgs = toLazyByteString dl h <- readIORef href- L.hPut h s- hFlush h+ (do L.hPut h msgs+ hFlush h) `catch` \(e::IOException) -> do+ logInternalError $ "got exception writing to log " +++ filePath ++ ": " ++ show e ++ "\n"+ logInternalError "writing log entries to stderr.\n"+ mapM_ errAct $ L.toChunks msgs -- close the file every 15 minutes (for log rotation)- t <- getCurrentDateTime+ t <- epochTime old <- readIORef lastOpened - if t-old > 900- then do- closeIt h- openIt >>= writeIORef href- writeIORef lastOpened t- else return ()+ when (t-old > 900) $ do+ closeIt h+ mask_ $ openIt >>= writeIORef href+ writeIORef lastOpened t - loop !d = do+ waitFlushDelay !d = do -- wait on the notification mvar _ <- takeMVar notifier @@ -202,7 +269,6 @@ -- at least five seconds between log dumps threadDelay 5000000- loop d ------------------------------------------------------------------------------@@ -210,3 +276,8 @@ -- flushed out to disk stopLogger :: Logger -> IO () stopLogger lg = withMVar (_loggingThread lg) killThread+++------------------------------------------------------------------------------+fromShow :: Show a => a -> Builder+fromShow = stringUtf8 . show
− src/System/SendFile.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE CPP #-}---- | Snap's unified interface to sendfile.--- Modified from sendfile 0.6.1--module System.SendFile- ( sendFile- , sendFileMode- ) where--#if defined(LINUX)-import System.SendFile.Linux (sendFile)--sendFileMode :: String-sendFileMode = "LINUX_SENDFILE"-#elif defined(FREEBSD)-import System.SendFile.FreeBSD (sendFile)--sendFileMode :: String-sendFileMode = "FREEBSD_SENDFILE"-#elif defined(OSX)-import System.SendFile.Darwin (sendFile)--sendFileMode :: String-sendFileMode = "DARWIN_SENDFILE"-#endif
+ src/System/SendFile.hsc view
@@ -0,0 +1,105 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}++-- | Snap's unified interface to sendfile.+-- Modified from sendfile 0.6.1++module System.SendFile+ ( sendFile+ , sendFileMode+ , sendHeaders+ , sendHeadersImpl+ ) where++#include <sys/socket.h>++------------------------------------------------------------------------------+import Control.Concurrent (threadWaitWrite)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.ByteString.Unsafe as S+import Data.Word (Word64)+import Foreign.C.Error (throwErrnoIfMinus1RetryMayBlock)+#if __GLASGOW_HASKELL__ >= 703+import Foreign.C.Types (CChar (..), CInt (..), CSize (..))+#else+import Foreign.C.Types (CChar, CInt, CSize)+#endif+import Foreign.Ptr (Ptr, plusPtr)+#if __GLASGOW_HASKELL__ >= 703+import System.Posix.Types (Fd (..))+#else+import System.Posix.Types (COff, CSsize, Fd)+#endif+------------------------------------------------------------------------------+import Data.ByteString.Builder (Builder, toLazyByteString)+------------------------------------------------------------------------------+#if defined(LINUX)+import qualified System.SendFile.Linux as SF+#elif defined(FREEBSD)+import qualified System.SendFile.FreeBSD as SF+#elif defined(OSX)+import qualified System.SendFile.Darwin as SF+#endif+++------------------------------------------------------------------------------+sendFile :: Fd -- ^ out fd (i.e. the socket)+ -> Fd -- ^ in fd (i.e. the file)+ -> Word64 -- ^ offset in bytes+ -> Word64 -- ^ count in bytes+ -> IO ()+sendFile out_fd in_fd = go+ where+ go offs count | offs `seq` count <= 0 = return $! ()+ | otherwise = do+ nsent <- fromIntegral `fmap`+ SF.sendFile out_fd in_fd+ offs count+ go (offs + nsent)+ (count - nsent)+++------------------------------------------------------------------------------+sendFileMode :: String+sendFileMode = SF.sendFileMode+++------------------------------------------------------------------------------+{-# INLINE sendHeaders #-}+sendHeaders :: Builder -> Fd -> IO ()+sendHeaders = sendHeadersImpl c_send threadWaitWrite+++------------------------------------------------------------------------------+{-# INLINE sendHeadersImpl #-}+sendHeadersImpl :: (Fd -> Ptr CChar -> CSize -> CInt -> IO CSize)+ -> (Fd -> IO ())+ -> Builder+ -> Fd+ -> IO ()+sendHeadersImpl sendFunc waitFunc headers fd =+ sendFunc `seq` waitFunc `seq`+ S.unsafeUseAsCStringLen (S.concat $ L.toChunks+ $ toLazyByteString headers) $+ \(cstr, clen) -> go cstr (fromIntegral clen)+ where+#if defined(LINUX)+ flags = (#const MSG_MORE)+#else+ flags = 0+#endif++ go cstr clen | cstr `seq` clen <= 0 = return $! ()+ | otherwise = do+ nsent <- throwErrnoIfMinus1RetryMayBlock+ "sendHeaders"+ (sendFunc fd cstr clen flags)+ (waitFunc fd)+ let cstr' = plusPtr cstr (fromIntegral nsent)+ go cstr' (clen - nsent)+++------------------------------------------------------------------------------+foreign import ccall unsafe "sys/socket.h send" c_send+ :: Fd -> Ptr CChar -> CSize -> CInt -> IO CSize
− src/System/SendFile/Darwin.hsc
@@ -1,41 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}--- | Darwin system-dependent code for 'sendfile'.-module System.SendFile.Darwin (sendFile) where--import Data.Int-import Foreign.C.Error (eAGAIN, eINTR, getErrno, throwErrno)-import Foreign.C.Types (CInt)-import Foreign.Marshal (alloca)-import Foreign.Ptr (Ptr, nullPtr)-import Foreign.Storable (peek, poke)-import System.Posix.Types (Fd, COff)--sendFile :: Fd -> Fd -> Int64 -> Int64 -> IO Int64-sendFile out_fd in_fd off count- | count == 0 = return 0- | otherwise = alloca $ \pbytes -> do- poke pbytes $ min maxBytes (fromIntegral count)- sbytes <- sendfile out_fd in_fd (fromIntegral off) pbytes- return $ fromIntegral sbytes--sendfile :: Fd -> Fd -> COff -> Ptr COff -> IO COff-sendfile out_fd in_fd off pbytes = do- status <- c_sendfile out_fd in_fd off pbytes- nsent <- peek pbytes- if status == 0- then return nsent- else do errno <- getErrno- if (errno == eAGAIN) || (errno == eINTR)- then return nsent- else throwErrno "System.SendFile.Darwin"---- max num of bytes in one send-maxBytes :: COff-maxBytes = maxBound :: COff---- in Darwin sendfile gives LFS support (no sendfile64 routine)-foreign import ccall unsafe "sys/uio.h sendfile" c_sendfile_darwin- :: Fd -> Fd -> COff -> Ptr COff -> Ptr () -> CInt -> IO CInt--c_sendfile :: Fd -> Fd -> COff -> Ptr COff -> IO CInt-c_sendfile out_fd in_fd off pbytes = c_sendfile_darwin in_fd out_fd off pbytes nullPtr 0
src/System/SendFile/FreeBSD.hsc view
@@ -1,39 +1,79 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE ForeignFunctionInterface #-} -- | FreeBSD system-dependent code for 'sendfile'.-module System.SendFile.FreeBSD (sendFile) where+module System.SendFile.FreeBSD+ ( sendFile+ , sendFileImpl+ , sendFileMode+ ) where -import Control.Concurrent (threadWaitWrite)-import Data.Int-import Foreign.C.Error (eAGAIN, eINTR, getErrno, throwErrno)-import Foreign.C.Types (CInt, CSize)-import Foreign.Marshal.Alloc (alloca)-import Foreign.Ptr (Ptr, nullPtr)-import Foreign.Storable (peek)-import System.Posix.Types (COff, Fd)+------------------------------------------------------------------------------+import Control.Concurrent (threadWaitWrite)+import Data.Int+import Data.Word+import Foreign.C.Error (throwErrnoIfMinus1RetryMayBlock_)+#if __GLASGOW_HASKELL__ >= 703+import Foreign.C.Types (CInt (..), CSize (..))+#else+import Foreign.C.Types (CInt, CSize)+#endif+import Foreign.Marshal.Alloc (alloca)+import Foreign.Ptr (Ptr, nullPtr)+import Foreign.Storable (peek)+#if __GLASGOW_HASKELL__ >= 703+import System.Posix.Types (COff (..), Fd (..))+#else+import System.Posix.Types (COff, Fd)+#endif+------------------------------------------------------------------------------ -sendFile :: Fd -> Fd -> Int64 -> Int64 -> IO Int64-sendFile out_fd in_fd off count++------------------------------------------------------------------------------+sendFile :: Fd -> Fd -> Word64 -> Word64 -> IO Int64+sendFile = sendFileImpl c_sendfile_freebsd threadWaitWrite+{-# INLINE sendFile #-}+++------------------------------------------------------------------------------+sendFileImpl :: (Fd -> Fd -> COff -> CSize -> Ptr () -> Ptr COff -> CInt+ -> IO CInt)+ -> (Fd -> IO ())+ -> Fd -> Fd -> Word64 -> Word64 -> IO Int64+sendFileImpl !rawSendFile !wait out_fd in_fd off count | count == 0 = return 0 | otherwise = alloca $ \pbytes -> do- sbytes <- sendfile out_fd in_fd (fromIntegral off)- (fromIntegral count) pbytes+ sbytes <- sendfile rawSendFile wait out_fd in_fd+ (fromIntegral off)+ (fromIntegral count)+ pbytes return $ fromIntegral sbytes -sendfile :: Fd -> Fd -> COff -> CSize -> Ptr COff -> IO COff-sendfile out_fd in_fd off count pbytes =- do threadWaitWrite out_fd- res <- c_sendfile_freebsd in_fd out_fd off count nullPtr pbytes 0- nsent <- peek pbytes- if (res == 0)- then return nsent- else do errno <- getErrno- if (errno == eAGAIN) || (errno == eINTR)- then return nsent- else throwErrno "System.SendFile.FreeBSD.sendfile" +------------------------------------------------------------------------------+sendfile :: (Fd -> Fd -> COff -> CSize -> Ptr () -> Ptr COff -> CInt+ -> IO CInt)+ -> (Fd -> IO ())+ -> Fd -> Fd -> COff -> CSize -> Ptr COff -> IO COff+sendfile rawSendFile wait out_fd in_fd off count pbytes = do+ throwErrnoIfMinus1RetryMayBlock_+ "sendfile"+ (rawSendFile in_fd out_fd off count nullPtr pbytes 0)+ (wait out_fd)+ peek pbytes+++------------------------------------------------------------------------------ -- max num of bytes in one send maxBytes :: CSize maxBytes = maxBound :: CSize ++------------------------------------------------------------------------------ foreign import ccall unsafe "sys/uio.h sendfile" c_sendfile_freebsd :: Fd -> Fd -> COff -> CSize -> Ptr () -> Ptr COff -> CInt -> IO CInt+++------------------------------------------------------------------------------+sendFileMode :: String+sendFileMode = "FREEBSD_SENDFILE"
src/System/SendFile/Linux.hsc view
@@ -1,42 +1,77 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE ForeignFunctionInterface #-}++------------------------------------------------------------------------------ -- | Linux system-dependent code for 'sendfile'.-module System.SendFile.Linux (sendFile) where+module System.SendFile.Linux+ ( sendFile+ , sendFileImpl+ , sendFileMode+ ) where -import Data.Int-import Foreign.C.Error (eAGAIN, getErrno, throwErrno)-import Foreign.C.Types (CSize)-import Foreign.Marshal (alloca)-import Foreign.Ptr (Ptr, nullPtr)-import Foreign.Storable (poke)-import System.Posix.Types (Fd, COff, CSsize)+------------------------------------------------------------------------------+import Control.Concurrent (threadWaitWrite)+import Data.Int (Int64)+import Data.Word (Word64)+import Foreign.C.Error (throwErrnoIfMinus1RetryMayBlock)+#if __GLASGOW_HASKELL__ >= 703+import Foreign.C.Types (CInt (..), CSize (..))+#else+import Foreign.C.Types (CSize)+#endif+import Foreign.Marshal (alloca)+import Foreign.Ptr (Ptr, nullPtr)+import Foreign.Storable (poke)+#if __GLASGOW_HASKELL__ >= 703+import System.Posix.Types (COff (..), CSsize (..), Fd (..))+#else+import System.Posix.Types (COff, CSsize, Fd)+#endif -sendFile :: Fd -> Fd -> Int64 -> Int64 -> IO Int64-sendFile out_fd in_fd off count- | count == 0 = return 0- | off == 0 = do- sbytes <- sendfile out_fd in_fd nullPtr bytes- return $ fromIntegral sbytes++------------------------------------------------------------------------------+sendFile :: Fd -> Fd -> Word64 -> Word64 -> IO Int64+sendFile = sendFileImpl c_sendfile threadWaitWrite+{-# INLINE sendFile #-}+++------------------------------------------------------------------------------+sendFileImpl :: (Fd -> Fd -> Ptr COff -> CSize -> IO CSsize)+ -> (Fd -> IO ())+ -> Fd -> Fd -> Word64 -> Word64 -> IO Int64+sendFileImpl !raw_sendfile !wait out_fd in_fd off count+ | count <= 0 = return 0+ | off == 0 = do+ nsent <- sendfile raw_sendfile wait out_fd in_fd nullPtr bytes+ return $! fromIntegral nsent | otherwise = alloca $ \poff -> do poke poff (fromIntegral off)- sbytes <- sendfile out_fd in_fd poff bytes- return $ fromIntegral sbytes+ nsent <- sendfile raw_sendfile wait out_fd in_fd poff bytes+ return $! fromIntegral nsent where- bytes = min (fromIntegral count) maxBytes+ bytes = fromIntegral count+{-# INLINE sendFileImpl #-} -sendfile :: Fd -> Fd -> Ptr COff -> CSize -> IO CSsize-sendfile out_fd in_fd poff bytes = do- nsent <- c_sendfile out_fd in_fd poff bytes- if nsent <= -1- then do errno <- getErrno- if errno == eAGAIN- then sendfile out_fd in_fd poff bytes- else throwErrno "System.SendFile.Linux"- else return nsent --- max num of bytes in one send-maxBytes :: CSize-maxBytes = maxBound :: CSize+------------------------------------------------------------------------------+sendfile :: (Fd -> Fd -> Ptr COff -> CSize -> IO CSsize)+ -> (Fd -> IO ())+ -> Fd -> Fd -> Ptr COff -> CSize -> IO CSsize+sendfile raw_sendfile wait out_fd in_fd poff bytes =+ throwErrnoIfMinus1RetryMayBlock+ "sendfile"+ (raw_sendfile out_fd in_fd poff bytes)+ (wait out_fd)+{-# INLINE sendfile #-} ++------------------------------------------------------------------------------ -- sendfile64 gives LFS support foreign import ccall unsafe "sys/sendfile.h sendfile64" c_sendfile :: Fd -> Fd -> Ptr COff -> CSize -> IO CSsize+++------------------------------------------------------------------------------+sendFileMode :: String+sendFileMode = "LINUX_SENDFILE"
+ test/Snap/Internal/Http/Server/Address/Tests.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Internal.Http.Server.Address.Tests (tests) where++------------------------------------------------------------------------------+import Network.Socket (Family (AF_INET, AF_INET6), SockAddr (SockAddrInet, SockAddrInet6, SockAddrUnix))+------------------------------------------------------------------------------+import Test.Framework (Test)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit (assertEqual)+------------------------------------------------------------------------------+import Snap.Internal.Http.Server.Address (AddressNotSupportedException (..), getAddress, getAddressImpl, getHostAddrImpl, getSockAddr, getSockAddrImpl)+import Snap.Test.Common (coverShowInstance, coverTypeableInstance, expectException)+++------------------------------------------------------------------------------+tests :: [Test]+tests = [ testGetNameInfoFails+ , testGetAddressUnix+ , testGetAddressIPv6+ , testGetSockAddr+ , testTrivials+ ]+++------------------------------------------------------------------------------+testGetNameInfoFails :: Test+testGetNameInfoFails = testCase "address/getNameInfo-fails" $ do+ x <- getHostAddrImpl (\_ _ _ _ -> return (Nothing, Nothing)) undefined+ assertEqual "when getNameInfo fails, getHostAddr should return empty" "" x+++------------------------------------------------------------------------------+testGetAddressUnix :: Test+testGetAddressUnix = testCase "address/getAddress-unix-socket" $ do+ (port, addr) <- getAddress $ SockAddrUnix "/foo/bar"+ assertEqual "unix port" (-1) port+ assertEqual "unix address" "unix:/foo/bar" addr+++------------------------------------------------------------------------------+testGetAddressIPv6 :: Test+testGetAddressIPv6 = testCase "address/getAddress-IPv6" $ do+ let x = SockAddrInet6 10 0 (0,0,0,0) 0+ (y, _) <- getAddressImpl (const $ return "") x+ assertEqual "ipv6 port" 10 y+++------------------------------------------------------------------------------+testGetSockAddr :: Test+testGetSockAddr = testCase "address/getSockAddr" $ do+ (f1, a1) <- getSockAddr 10 "*"+ assertEqual "" f1 AF_INET+ assertEqual "" a1 $ SockAddrInet 10 iNADDR_ANY++ (f2, a2) <- getSockAddr 10 "::"+ assertEqual "" f2 AF_INET6+ assertEqual "" a2 $ SockAddrInet6 10 0 iN6ADDR_ANY 0++ expectException $ getSockAddrImpl (\_ _ _ -> return []) 10 "foo"+ where+ iNADDR_ANY = 0+ iN6ADDR_ANY = (0,0,0,0)++++------------------------------------------------------------------------------+testTrivials :: Test+testTrivials = testCase "address/trivials" $ do+ coverTypeableInstance (undefined :: AddressNotSupportedException)+ coverShowInstance (AddressNotSupportedException "ok")
+ test/Snap/Internal/Http/Server/Parser/Tests.hs view
@@ -0,0 +1,249 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Internal.Http.Server.Parser.Tests (tests) where++------------------------------------------------------------------------------+import Control.Monad (liftM)+import Control.Parallel.Strategies (rdeepseq, using)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import Data.List (sort)+import qualified Data.Map as Map+import Data.Monoid (mconcat)+import Text.Printf (printf)+------------------------------------------------------------------------------+import Data.ByteString.Builder (byteString, toLazyByteString)+import Test.Framework (Test)+import Test.Framework.Providers.HUnit (testCase)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.HUnit (assertEqual)+import Test.QuickCheck (Arbitrary (arbitrary))+import Test.QuickCheck.Monadic (forAllM, monadicIO)+import qualified Test.QuickCheck.Monadic as QC+------------------------------------------------------------------------------+import Snap.Internal.Debug (debug)+import Snap.Internal.Http.Server.Parser (HttpParseException (..), IRequest (IRequest, iMethod, iRequestHeaders, iStdHeaders), getStdHost, parseCookie, parseRequest, parseUrlEncoded, readChunkedTransferEncoding, writeChunkedTransferEncoding)+import Snap.Internal.Http.Types (Cookie (Cookie), Method (CONNECT, DELETE, GET, HEAD, Method, OPTIONS, PATCH, POST, PUT, TRACE))+import Snap.Test.Common (coverEqInstance, coverShowInstance, coverTypeableInstance, expectException)+import qualified Snap.Types.Headers as H+import qualified System.IO.Streams as Streams+++------------------------------------------------------------------------------+tests :: [Test]+tests = [ testShow+ , testCookie+ , testChunked+ , testNull+ , testPartial+ , testParseError+ , testFormEncoded+ , testTrivials+ , testMethods+ , testSimpleParse+ , testSimpleParseErrors+ , testWriteChunkedTransferEncoding+ ]+++------------------------------------------------------------------------------+testShow :: Test+testShow = testCase "parser/show" $ do+ let i = IRequest GET "/" (1, 1) H.empty undefined+ let !b = show i `using` rdeepseq+ return $ b `seq` ()+++------------------------------------------------------------------------------+testNull :: Test+testNull = testCase "parser/shortParse" $+ expectException (Streams.fromList [] >>= parseRequest)+++------------------------------------------------------------------------------+testPartial :: Test+testPartial = testCase "parser/partial" $+ expectException (Streams.fromList ["GET / "] >>= parseRequest)+++------------------------------------------------------------------------------+testParseError :: Test+testParseError = testCase "parser/error" $ do+ expectException (Streams.fromList ["ZZZZZZZZZ"] >>= parseRequest)+ expectException (Streams.fromList ["GET / HTTP/1.1"] >>= parseRequest)+ expectException (Streams.fromList ["GET / HTTP/x.z\r\n\r\n"] >>=+ parseRequest)+++------------------------------------------------------------------------------+-- | convert a bytestring to chunked transfer encoding+transferEncodingChunked :: L.ByteString -> L.ByteString+transferEncodingChunked = f . L.toChunks+ where+ toChunk s = L.concat [ len, "\r\n", L.fromChunks [s], "\r\n" ]+ where+ len = L.pack $ printf "%x" $ S.length s++ f l = L.concat $ (map toChunk l ++ ["0\r\n\r\n"])+++------------------------------------------------------------------------------+-- | ensure that running 'readChunkedTransferEncoding' against+-- 'transferEncodingChunked' returns the original string+testChunked :: Test+testChunked = testProperty "parser/chunkedTransferEncoding" $+ monadicIO $ forAllM arbitrary prop_chunked+ where+ prop_chunked s = QC.run $ do+ debug "=============================="+ debug $ "input is " ++ show s+ debug $ "chunked is " ++ show chunked+ debug "------------------------------"++ out <- Streams.fromList (L.toChunks chunked) >>=+ readChunkedTransferEncoding >>=+ Streams.toList >>=+ return . L.fromChunks++ assertEqual "chunked" s out+ debug "==============================\n"++ where+ chunked = transferEncodingChunked s+++------------------------------------------------------------------------------+testWriteChunkedTransferEncoding :: Test+testWriteChunkedTransferEncoding = testCase "parser/writeChunked" $ do+ (os, getList) <- Streams.listOutputStream+ os' <- writeChunkedTransferEncoding os+ Streams.fromList [byteString "ok"] >>= Streams.connectTo os'+ Streams.write Nothing os'+ s <- liftM (toLazyByteString . mconcat) getList+ assertEqual "chunked" "002\r\nok\r\n0\r\n\r\n" s++------------------------------------------------------------------------------+testCookie :: Test+testCookie =+ testCase "parser/parseCookie" $ do+ assertEqual "cookie parsing" (Just [cv]) cv2++ where+ cv = Cookie nm v Nothing Nothing Nothing False False+ cv2 = parseCookie ct++ nm = "foo"+ v = "bar"++ ct = S.concat [ nm , "=" , v ]+++------------------------------------------------------------------------------+testFormEncoded :: Test+testFormEncoded = testCase "parser/formEncoded" $ do+ let bs = "foo1=bar1&foo2=bar2+baz2;foo3=foo%20bar"+ let mp = parseUrlEncoded bs++ assertEqual "foo1" (Just ["bar1"] ) $ Map.lookup "foo1" mp+ assertEqual "foo2" (Just ["bar2 baz2"]) $ Map.lookup "foo2" mp+ assertEqual "foo3" (Just ["foo bar"] ) $ Map.lookup "foo3" mp+++------------------------------------------------------------------------------+testTrivials :: Test+testTrivials = testCase "parser/trivials" $ do+ coverTypeableInstance (undefined :: HttpParseException)+ coverShowInstance (HttpParseException "ok")+ coverEqInstance (IRequest GET "" (0, 0) H.empty undefined)+++------------------------------------------------------------------------------+testMethods :: Test+testMethods = testCase "parser/methods" $ mapM_ testOne ms+ where+ ms = [ GET, POST, HEAD, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH+ , Method "ZZZ" ]++ mToStr (Method m) = m+ mToStr m = S.pack $ show m++ restOfRequest = [ " / HTTP/1.1\r\nz:b\r\nq:\r\nw\r\n", "foo: ", "bar"+ , "\r\n baz\r\n\r\n" ]++ testOne m = let s = mToStr m+ in Streams.fromList (s:restOfRequest) >>=+ parseRequest >>=+ checkMethod m++ checkMethod m i = do+ assertEqual "method" m $ iMethod i+ let expected = sort [ ("z", "b")+ , ("q", "")+ , ("w", "")+ , ("foo", "bar baz")+ ]+ assertEqual "hdrs" expected $ sort $ H.toList $ iRequestHeaders i+++------------------------------------------------------------------------------+testSimpleParse :: Test+testSimpleParse = testCase "parser/simpleParse" $ do+ Streams.fromList ["GET / HTTP/1.1\r\n\r\n"] >>=+ parseRequest >>=+ assertEqual "simple0" (IRequest GET "/" (1, 1) H.empty undefined)++ Streams.fromList ["GET http://foo.com/ HTTP/1.1\r\n\r\n"] >>=+ parseRequest >>=+ assertEqual "simple1" (IRequest GET "/" (1, 1) H.empty undefined)++ z <- Streams.fromList ["GET http://foo.com HTTP/1.1\r\n\r\n"] >>=+ parseRequest++ assertEqual "simple2" z (IRequest GET "/" (1, 1) H.empty undefined)+ assertEqual "simple2-host" (Just "foo.com") (getStdHost $ iStdHeaders z)++ z2 <- Streams.fromList ["GET https://foo.com/ HTTP/1.1\r\n\r\n"] >>=+ parseRequest+ assertEqual "simpleHttps" (IRequest GET "/" (1, 1) H.empty undefined) z2+ assertEqual "simpleHttps-2" (Just "foo.com") (getStdHost $ iStdHeaders z2)++ Streams.fromList ["GET / HTTP/1.1\r\nz:b\r\n", "", "\r\n"] >>=+ parseRequest >>=+ assertEqual "simple4" (IRequest GET "/" (1, 1)+ (H.fromList [("z", "b")]) undefined)++ Streams.fromList [ "GET / HTTP/1.1\r\na:a\r", "\nz:b\r\n", ""+ , "\r\n" ] >>=+ parseRequest >>=+ assertEqual "simple5" (IRequest GET "/" (1, 1)+ (H.fromList [("a", "a"), ("z", "b")]) undefined)++ Streams.fromList ["GET /\r\n\r\n"] >>=+ parseRequest >>=+ assertEqual "simple6" (IRequest GET "/" (1, 0) H.empty undefined)++ Streams.fromList ["G", "ET", " /\r", "\n\r", "", "\n"] >>=+ parseRequest >>=+ assertEqual "simple7" (IRequest GET "/" (1, 0) H.empty undefined)+++------------------------------------------------------------------------------+testSimpleParseErrors :: Test+testSimpleParseErrors = testCase "parser/simpleParseErrors" $ do+ expectException (+ Streams.fromList ["\r\nGET / HTTP/1.1\r\nz:b\r\n \r\n"] >>=+ parseRequest)++ expectException (+ Streams.fromList ["\r\nGET / HTTP/1.1\r\nz:b\r "] >>=+ parseRequest)++ expectException (+ Streams.fromList ["\r\nGET / HTTP/1.1\r"] >>=+ parseRequest)++ expectException (+ Streams.fromList ["\r\nGET / HTTP/1.1\r", "", "foo\nz:b\r "] >>=+ parseRequest)
+ test/Snap/Internal/Http/Server/Session/Tests.hs view
@@ -0,0 +1,1018 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Internal.Http.Server.Session.Tests (tests) where++------------------------------------------------------------------------------+#if !MIN_VERSION_base(4,6,0)+import Prelude hiding (catch)+#endif+import Control.Concurrent (MVar, forkIO, killThread, modifyMVar_, myThreadId, newChan, newEmptyMVar, newMVar, putMVar, readMVar, takeMVar, threadDelay, throwTo, withMVar)+import Control.Exception.Lifted (AsyncException (ThreadKilled), Exception, SomeException (..), bracket, catch, evaluate, mask, throwIO, try)+import Control.Monad (forM_, liftM, replicateM_, void, when, (>=>))+import Control.Monad.State.Class (modify)+import Data.ByteString.Builder (Builder, byteString, char8, toLazyByteString)+import Data.ByteString.Builder.Extra (flush)+import Data.ByteString.Builder.Internal (newBuffer)+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.CaseInsensitive as CI+import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import qualified Data.Map as Map+import Data.Maybe (isNothing)+import Data.Monoid (mappend)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import Data.Typeable (Typeable)+import Data.Word (Word64)+import qualified Network.Http.Client as Http+import System.IO.Streams (InputStream, OutputStream)+import qualified System.IO.Streams as Streams+import qualified System.IO.Streams.Concurrent as Streams+import qualified System.IO.Streams.Debug as Streams+import System.Timeout (timeout)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import qualified Test.Framework.Runners.Console as Console+import Test.HUnit (assertBool, assertEqual)+------------------------------------------------------------------------------+import Snap.Core (Cookie (Cookie, cookieName, cookieValue), Request (rqContentLength, rqCookies, rqHostName, rqLocalHostname, rqPathInfo, rqQueryString, rqURI), Snap, addResponseCookie, escapeHttp, getHeader, getRequest, getsRequest, modifyResponse, readRequestBody, rqParam, rqPostParam, rqQueryParam, sendFile, sendFilePartial, setContentLength, setHeader, setResponseBody, setResponseStatus, terminateConnection, writeBS, writeBuilder, writeLBS)+import Snap.Http.Server.Types (emptyServerConfig, getDefaultTimeout, getIsSecure, getLocalAddress, getLocalHostname, getLocalPort, getLogAccess, getLogError, getNumAcceptLoops, getOnDataFinished, getOnEscape, getOnException, getOnNewRequest, getOnParse, getOnUserHandlerFinished, getRemoteAddress, getRemotePort, getTwiddleTimeout, isNewConnection, setDefaultTimeout, setIsSecure, setLocalHostname, setLogAccess, setLogError, setNumAcceptLoops, setOnDataFinished, setOnEscape, setOnException, setOnNewRequest, setOnParse, setOnUserHandlerFinished)+import Snap.Internal.Http.Server.Date (getLogDateString)+import Snap.Internal.Http.Server.Session (BadRequestException (..), LengthRequiredException (..), TerminateSessionException (..), httpAcceptLoop, httpSession, snapToServerHandler)+import qualified Snap.Internal.Http.Server.TLS as TLS+import Snap.Internal.Http.Server.Types (AcceptFunc (AcceptFunc), PerSessionData (PerSessionData, _isNewConnection), SendFileHandler, ServerConfig (_logError))+import Snap.Test (RequestBuilder)+import qualified Snap.Test as T+import Snap.Test.Common (coverShowInstance, coverTypeableInstance, expectException)+#ifdef OPENSSL+import qualified Network.Socket as N+#endif+++------------------------------------------------------------------------------+tests :: [Test]+tests = [ testPong+ , testPong1_0+ , testDateHeaderDeleted+ , testServerHeader+ , testBadParses+ , testEof+ , testHttp100+ , testNoHost+ , testNoHost1_0+ , testChunkedRequest+ , testQueryParams+ , testPostParams+ , testPostParamsReplacementBody+ , testCookie+ , testSetCookie+ , testUserException+ , testUserBodyException+ , testEscape+ , testPostWithoutLength+ , testWeirdMissingSlash+ , testOnlyQueryString+ , testConnectionClose+ , testUserTerminate+ , testSendFile+ , testBasicAcceptLoop+ , testTrivials+#ifdef OPENSSL+ , testTLSKeyMismatch+#else+ , testCoverTLSStubs+#endif+ ]+++------------------------------------------------------------------------------+#ifdef OPENSSL+testTLSKeyMismatch :: Test+testTLSKeyMismatch = testCase "session/tls-key-mismatch" $ do+ expectException $ bracket (TLS.bindHttps "127.0.0.1"+ (fromIntegral N.aNY_PORT)+ "test/cert.pem"+ False+ "test/bad_key.pem")+ (N.close . fst)+ (const $ return ())+ expectException $ bracket (TLS.bindHttps "127.0.0.1"+ (fromIntegral N.aNY_PORT)+ "test/cert.pem"+ True+ "test/bad_key.pem")+ (N.close . fst)+ (const $ return ())+#else+testCoverTLSStubs :: Test+testCoverTLSStubs = testCase "session/tls-stubs" $ do+ expectException $ TLS.bindHttps "127.0.0.1" 9999+ "test/cert.pem" False "test/key.pem"+ expectException $ TLS.bindHttps "127.0.0.1" 9999+ "test/cert.pem" True "test/key.pem"+ let (AcceptFunc afunc) = TLS.httpsAcceptFunc undefined undefined+ expectException $ mask $ \restore -> afunc restore+ let u = undefined+ expectException $ TLS.sendFileFunc u u u u u u u+#endif+++------------------------------------------------------------------------------+testPong :: Test+testPong = testCase "session/pong" $ do+ do+ [(resp, body)] <- runRequestPipeline [return ()] snap1+ assertEqual "code1" 200 $ Http.getStatusCode resp+ assertEqual "body1" pong body+ assertEqual "chunked1" Nothing $+ Http.getHeader resp "Transfer-Encoding"+ do+ [(resp, body)] <- runRequestPipeline [return ()] snap2+ assertEqual "code2" 200 $ Http.getStatusCode resp+ assertEqual "body2" pong body+ assertEqual "chunked2" (Just $ CI.mk "chunked") $+ fmap CI.mk $+ Http.getHeader resp "Transfer-Encoding"+ -- test pipelining+ do+ [_, (resp, body)] <- runRequestPipeline [return (), return ()] snap3+ assertEqual "code3" 233 $ Http.getStatusCode resp+ assertEqual "reason3" "ZOMG" $ Http.getStatusMessage resp+ assertEqual "body3" pong body+ assertEqual "chunked3" Nothing $ Http.getHeader resp "Transfer-Encoding"++ do+ [_, (resp, body)] <- runRequestPipeline [http_1_0, http_1_0] snap3+ assertEqual "code4" 233 $ Http.getStatusCode resp+ assertEqual "reason4" "ZOMG" $ Http.getStatusMessage resp+ assertEqual "body4" pong body+ assertEqual "chunked4" Nothing $ Http.getHeader resp "Transfer-Encoding"++ where+ http_1_0 = do+ T.setHttpVersion (1, 0)+ T.setHeader "Connection" "keep-alive"+ pong = "PONG"++ snap1 = writeBS pong >> modifyResponse (setContentLength 4)+ snap2 = do+ cookies <- getsRequest rqCookies+ if null cookies+ then writeBS pong+ else writeBS "wat"++ snap3 = do+ modifyResponse (setResponseStatus 233 "ZOMG" . setContentLength 4)+ writeBS pong++------------------------------------------------------------------------------+testPong1_0 :: Test+testPong1_0 = testCase "session/pong1_0" $ do+ req <- makeRequest (T.setHttpVersion (1, 0) >>+ T.setHeader "Connection" "zzz")+ out <- getSessionOutput [req] $ writeBS "PONG"+ assertBool "200 ok" $ S.isPrefixOf "HTTP/1.0 200 OK\r\n" out+ assertBool "PONG" $ S.isSuffixOf "\r\n\r\nPONG" out+++------------------------------------------------------------------------------+testDateHeaderDeleted :: Test+testDateHeaderDeleted = testCase "session/dateHeaderDeleted" $ do+ [(resp, _)] <- runRequestPipeline [mkRq] snap+ assertBool "date header" $ Just "plop" /= Http.getHeader resp "Date"++ [_, (resp2, _)] <- runRequestPipeline [mkRq2, mkRq2] snap+ assertBool "date header 2" $ Just "plop" /= Http.getHeader resp2 "Date"++ where+ snap = do+ modifyResponse (setHeader "Date" "plop" .+ setHeader "Connection" "ok" .+ setContentLength 4)+ writeBS "PONG"++ mkRq = do+ T.setHttpVersion (1,0)+ T.setHeader "fnargle" "plop"+ T.setHeader "Content-Length" "0"+ T.setHeader "Connection" "keep-alive"++ mkRq2 = do+ T.setHeader "fnargle" "plop"+ T.setHeader "Content-Length" "0"+ T.setHeader "Connection" "keep-alive"+++------------------------------------------------------------------------------+testServerHeader :: Test+testServerHeader = testCase "session/serverHeader" $ do+ [(resp, _)] <- runRequestPipeline [return ()] snap+ assertEqual "server" (Just "blah") $ Http.getHeader resp "Server"+ where+ snap = modifyResponse $ setHeader "Server" "blah"+++------------------------------------------------------------------------------+testBadParses :: Test+testBadParses = testGroup "session/badParses" [+ check 1 "Not an HTTP Request"+ , check 2 $ S.concat [ "GET / HTTP/1.1\r\n"+ , "&*%^(*&*@YS\r\n\r324932\n)"+ ]+ , check 3 "\n"+ ]++ where+ check :: Int -> ByteString -> Test+ check n txt = testCase ("session/badParses/" ++ show n) $+ expectException $ getSessionOutput [txt] (return ())+++------------------------------------------------------------------------------+testEof :: Test+testEof = testCase "session/eof" $ do+ l <- runRequestPipeline [] snap+ assertBool "eof1" $ null l++ out <- getSessionOutput [""] snap+ assertEqual "eof2" "" out+ where+ snap = writeBS "OK"+++------------------------------------------------------------------------------+testHttp100 :: Test+testHttp100 = testCase "session/expect100" $ do+ req <- makeRequest expect100+ out <- getSessionOutput [req] (writeBS "OK")++ assertBool "100-continue" $+ S.isPrefixOf "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK" out++ req2 <- makeRequest expect100_2+ out2 <- getSessionOutput [req2] (writeBS "OK")++ assertBool "100-continue-2" $+ S.isPrefixOf "HTTP/1.0 100 Continue\r\n\r\nHTTP/1.0 200 OK" out2++ where+ expect100 = do+ queryGetParams+ T.setHeader "Expect" "100-continue"++ expect100_2 = do+ T.setHttpVersion (1, 0)+ queryGetParams+ T.setHeader "Expect" "100-continue"+++------------------------------------------------------------------------------+testNoHost :: Test+testNoHost = testCase "session/noHost" $+ expectException $+ getSessionOutput ["GET / HTTP/1.1\r\n\r\n"] (writeBS "OK")+++------------------------------------------------------------------------------+testNoHost1_0 :: Test+testNoHost1_0 = testCase "session/noHost1_0" $ do+ out <- getSessionOutput ["GET / HTTP/1.0\r\n\r\n"] snap1+ assertBool "no host 1.0" $ S.isSuffixOf "\r\nbackup-localhost" out+ out2 <- getSessionOutput ["GET / HTTP/1.0\r\n\r\n"] snap2+ assertBool "no host 1.0-2" $ S.isSuffixOf "\r\nbackup-localhost" out2+ where+ snap1 = getRequest >>= writeBS . rqHostName+ snap2 = getRequest >>= writeBS . rqLocalHostname+++------------------------------------------------------------------------------+testChunkedRequest :: Test+testChunkedRequest = testCase "session/chunkedRequest" $ do+ [(_, body)] <- runRequestPipeline [chunked] snap+ assertEqual "chunked" "ok" body+ where+ snap = do+ m <- liftM (getHeader "Transfer-Encoding") getRequest+ if m == Just "chunked"+ then readRequestBody 2048 >>= writeLBS+ else writeBS "not ok"++ chunked = do+ T.put "/" "text/plain" "ok"+ T.setHeader "Transfer-Encoding" "chunked"+++------------------------------------------------------------------------------+testQueryParams :: Test+testQueryParams = testCase "session/queryParams" $ do+ [(_, body)] <- runRequestPipeline [queryGetParams] snap+ assertEqual "queryParams" expected body++ where+ expected = S.unlines [+ "param1=abc,def"+ , "param2=def"+ , "param1=abc,def"+ , "ok"+ ]+ snap = do+ rq <- getRequest+ let (Just l) = rqParam "param1" rq+ writeBS $ S.concat [ "param1="+ , S.intercalate "," l+ , "\n" ]+ let (Just m) = rqParam "param2" rq+ writeBS $ S.concat [ "param2="+ , S.intercalate "," m+ , "\n"]+ let (Just l') = rqQueryParam "param1" rq+ writeBS $ S.concat [ "param1="+ , S.intercalate "," l'+ , "\n" ]+ let z = if isNothing $ rqPostParam "param1" rq+ then "ok\n" else "bad\n"+ writeBS z++ return ()+++------------------------------------------------------------------------------+testPostParams :: Test+testPostParams = testCase "session/postParams" $ do+ [(_, body)] <- runRequestPipeline [queryPostParams] snap+ assertEqual "postParams" expected body++ where+ expected = S.unlines [+ "param1=abc,abc"+ , "param2=def ,zzz"+ , "param1=abc,abc"+ , "ok"+ , "param2=zzz"+ ]+ snap = do+ rq <- getRequest+ let (Just l) = rqParam "param1" rq+ writeBS $ S.concat [ "param1="+ , S.intercalate "," l+ , "\n" ]+ let (Just m) = rqParam "param2" rq+ writeBS $ S.concat [ "param2="+ , S.intercalate "," m+ , "\n"]+ let (Just l') = rqQueryParam "param1" rq+ writeBS $ S.concat [ "param1="+ , S.intercalate "," l'+ , "\n" ]+ let z = if isNothing $ rqPostParam "param1" rq+ then "ok\n" else "bad\n"+ writeBS z++ let (Just p) = rqPostParam "param2" rq+ writeBS $ S.concat [ "param2="+ , S.intercalate "," p+ , "\n" ]++ return ()+++------------------------------------------------------------------------------+testPostParamsReplacementBody :: Test+testPostParamsReplacementBody =+ testCase "session/postParamsReplacementBody" $ do+ [(_, body)] <- runRequestPipeline [queryPostParams] snap+ assertEqual "postParams" expected body++ where+ expected = "param2=zzz"+ snap = readRequestBody 2048 >>= writeLBS+++------------------------------------------------------------------------------+testCookie :: Test+testCookie = testCase "session/cookie" $ do+ [(_, body)] <- runRequestPipeline [queryGetParams] snap+ assertEqual "cookie" expected body+ where+ expected = S.unlines [ "foo"+ , "bar"+ ]+ snap = do+ cookies <- liftM rqCookies getRequest+ forM_ cookies $ \cookie -> do+ writeBS $ S.unlines [ cookieName cookie+ , cookieValue cookie+ ]+++------------------------------------------------------------------------------+testSetCookie :: Test+testSetCookie = testCase "session/setCookie" $ do+ mapM_ runTest $ zip3 [1..] expecteds cookies+ where+ runTest (n, expected, cookie) = do+ [(resp, _)] <- runRequestPipeline [queryGetParams] $ snap cookie+ assertEqual ("cookie" ++ show (n :: Int))+ (Just expected)+ (Http.getHeader resp "Set-Cookie")++ expecteds = [ S.intercalate "; "+ [ "foo=bar"+ , "path=/"+ , "expires=Thu, 01-Jan-1970 00:16:40 GMT"+ , "domain=localhost"+ ]+ , "foo=bar"+ , "foo=bar; Secure; HttpOnly"+ ]++ cookies = [ Cookie "foo" "bar" (Just $ posixSecondsToUTCTime 1000)+ (Just "localhost") (Just "/") False False+ , Cookie "foo" "bar" Nothing Nothing Nothing False False+ , Cookie "foo" "bar" Nothing Nothing Nothing True True+ ]++ snap cookie = do+ modifyResponse $ addResponseCookie cookie+++------------------------------------------------------------------------------+testUserException :: Test+testUserException = testCase "session/userException" $ do+ expectException $ runRequestPipeline [queryGetParams] snap+ where+ snap = throwIO TestException+++------------------------------------------------------------------------------+testUserBodyException :: Test+testUserBodyException = testCase "session/userBodyException" $ do+ expectException $ runRequestPipeline [queryGetParams] snap+ where+ snap = modifyResponse $ setResponseBody $ \os -> do+ Streams.write (Just (byteString "hi" `mappend` flush)) os+ throwIO TestException+++------------------------------------------------------------------------------+testEscape :: Test+testEscape = testCase "session/testEscape" $ do+ req <- makeRequest (return ())+ out <- getSessionOutput [req, "OK?"] snap+ assertEqual "escape" "OK" out+ where+ snap = escapeHttp $ \tickle readEnd writeEnd -> do+ l <- Streams.toList readEnd+ tickle (max 20)+ let s = if l == ["OK?"]+ then "OK"+ else S.append "BAD: " $ S.pack $ show l+ Streams.write (Just $ byteString s) writeEnd+ Streams.write Nothing writeEnd+++------------------------------------------------------------------------------+testPostWithoutLength :: Test+testPostWithoutLength = testCase "session/postWithoutLength" $ do+ let req = S.concat [ "POST / HTTP/1.1\r\nHost: localhost\r\n\r\n"+ , "Blah blah blah blah blah"+ ]++ is <- Streams.fromList [req]+ (os, getInput) <- listOutputStream+ expectException $ runSession is os (return ())+ out <- liftM S.concat getInput+ assertBool "post without length" $+ S.isPrefixOf "HTTP/1.1 411 Length Required" out+++------------------------------------------------------------------------------+testWeirdMissingSlash :: Test+testWeirdMissingSlash = testCase "session/weirdMissingSlash" $ do+ do+ let req = "GET foo/bar?z HTTP/1.0\r\n\r\n"+ out <- getSessionOutput [req] snap+ assertBool "missing slash" $ expected1 `S.isSuffixOf` out+ do+ let req = "GET /foo/bar?z HTTP/1.0\r\n\r\n"+ out <- getSessionOutput [req] snap+ assertBool "with slash" $ expected2 `S.isSuffixOf` out++ where+ expected1 = S.concat [ "\r\n\r\n"+ , "foo/bar?z\n"+ , "foo/bar\n"+ , "z\n"+ ]+ expected2 = S.concat [ "\r\n\r\n"+ , "/foo/bar?z\n"+ , "foo/bar\n"+ , "z\n"+ ]+ p s = writeBuilder $ byteString s `mappend` char8 '\n'+ snap = do+ rq <- getRequest+ p $ rqURI rq+ p $ rqPathInfo rq+ p $ rqQueryString rq+++------------------------------------------------------------------------------+testOnlyQueryString :: Test+testOnlyQueryString = testCase "session/onlyQueryString" $ do+ do+ let req = "GET ?z HTTP/1.0\r\n\r\n"+ out <- getSessionOutput [req] snap+ assertBool "missing slash" $ expected `S.isSuffixOf` out+ where+ expected = S.concat [ "\r\n\r\n"+ , "?z\n"+ , "\n"+ , "z\n"+ ]+ p s = writeBuilder $ byteString s `mappend` char8 '\n'+ snap = do+ rq <- getRequest+ p $ rqURI rq+ p $ rqPathInfo rq+ p $ rqQueryString rq+++------------------------------------------------------------------------------+testConnectionClose :: Test+testConnectionClose = testCase "session/connectionClose" $ do+ do+ [(resp, _)] <- runRequestPipeline [return (), return ()] snap+ assertEqual "close1" (Just $ CI.mk "close") $+ fmap CI.mk $+ Http.getHeader resp "Connection"+ do+ [(resp, _)] <- runRequestPipeline [http1_0, http1_0] snap+ assertEqual "close2" (Just $ CI.mk "close") $+ fmap CI.mk $+ Http.getHeader resp "Connection"++ do+ [(resp, _)] <- runRequestPipeline [http1_0_2, http1_0] (return ())+ assertEqual "close3" (Just $ CI.mk "close") $+ fmap CI.mk $+ Http.getHeader resp "Connection"++ where+ http1_0 = T.setHttpVersion (1, 0)+ http1_0_2 = T.setHttpVersion (1, 0) >> T.setHeader "Connection" "fnargle"+ snap = modifyResponse $ setHeader "Connection" "close"+++------------------------------------------------------------------------------+testUserTerminate :: Test+testUserTerminate = testCase "session/userTerminate" $ do+ expectException $ runRequestPipeline [return ()] snap+ where+ snap = terminateConnection TestException+++------------------------------------------------------------------------------+testSendFile :: Test+testSendFile = testCase "session/sendFile" $ do+ [(_, out1)] <- runRequestPipeline [return ()] snap1+ [(_, out2)] <- runRequestPipeline [return ()] snap2+ assertEqual "sendfile1" "TESTING 1-2-3\n" out1+ assertEqual "sendfile2" "EST" out2+ where+ snap1 = sendFile "test/dummy.txt"+ snap2 = sendFilePartial "test/dummy.txt" (1,4)+++------------------------------------------------------------------------------+testBasicAcceptLoop :: Test+testBasicAcceptLoop = testCase "session/basicAcceptLoop" $+ replicateM_ 1000 $ do+ outputs <- runAcceptLoop [return ()] (return ())+ let [Output out] = outputs+ void (evaluate out) `catch` \(e::SomeException) -> do+ throwIO e+ assertBool "basic accept" $ S.isPrefixOf "HTTP/1.1 200 OK\r\n" out+++------------------------------------------------------------------------------+testTrivials :: Test+testTrivials = testCase "session/trivials" $ do+ coverShowInstance $ TerminateSessionException+ $ SomeException BadRequestException+ coverShowInstance LengthRequiredException+ coverShowInstance BadRequestException+ coverShowInstance $ TLS.TLSException "ok"+ coverTypeableInstance (undefined :: TerminateSessionException)+ coverTypeableInstance (undefined :: BadRequestException)+ coverTypeableInstance (undefined :: LengthRequiredException)+ coverTypeableInstance (undefined :: TLS.TLSException)++ expectException (getOnNewRequest emptyServerConfig undefined >>= evaluate)+ is <- Streams.fromList []+ (os, _) <- Streams.listOutputStream+ psd <- makePerSessionData is os+ isNewConnection psd >>= assertEqual "new connection" False++ -- cover getters+ let !_ = getTwiddleTimeout psd+ let !_ = getRemotePort psd+ let !_ = getRemoteAddress psd+ let !_ = getLocalPort psd+ let !_ = getLocalAddress psd+ getOnParse emptyServerConfig undefined undefined+ getOnEscape emptyServerConfig undefined+ getOnException emptyServerConfig undefined undefined+ getOnDataFinished emptyServerConfig undefined undefined undefined+ getOnUserHandlerFinished emptyServerConfig undefined undefined undefined+ getLogError emptyServerConfig undefined+ getLogAccess emptyServerConfig undefined undefined undefined+ let !_ = getLogError emptyServerConfig+ let !_ = getLocalHostname emptyServerConfig+ let !_ = getDefaultTimeout emptyServerConfig+ let !_ = getNumAcceptLoops emptyServerConfig+ let !_ = getIsSecure emptyServerConfig++ !x <- getLogDateString+ threadDelay $ 2 * seconds+ !y <- getLogDateString+ assertBool (concat ["log dates: ", show x, ", ", show y]) $ x /= y+++ ---------------------+ -- query fragments --+ ---------------------++------------------------------------------------------------------------------+queryGetParams :: RequestBuilder IO ()+queryGetParams = do+ T.get "/foo/bar.html" $ Map.fromList [ ("param1", ["abc", "def"])+ , ("param2", ["def"])+ ]+ T.addCookies [ Cookie "foo" "bar" Nothing (Just "localhost") (Just "/")+ False False ]+ modify $ \rq -> rq { rqContentLength = Just 0 }+++------------------------------------------------------------------------------+queryPostParams :: RequestBuilder IO ()+queryPostParams = do+ T.postUrlEncoded "/" $ Map.fromList [ ("param2", ["zzz"]) ]+ T.setQueryStringRaw "param1=abc¶m2=def%20+¶m1=abc"+++ -----------------------+ -- utility functions --+ -----------------------++------------------------------------------------------------------------------+_run :: [Test] -> IO ()+_run l = Console.defaultMainWithArgs l ["--plain"]+++------------------------------------------------------------------------------+-- | Given a request builder, produce the HTTP request as a ByteString.+makeRequest :: RequestBuilder IO a -> IO ByteString+makeRequest = (T.buildRequest . void) >=> T.requestToString+++------------------------------------------------------------------------------+mockSendFileHandler :: OutputStream ByteString -> SendFileHandler+mockSendFileHandler os !_ hdrs fp start nbytes = do+ let hstr = toByteString hdrs+ Streams.write (Just hstr) os++ Streams.withFileAsInputStartingAt (fromIntegral start) fp $+ Streams.takeBytes (fromIntegral nbytes) >=> Streams.supplyTo os++ Streams.write Nothing os+++------------------------------------------------------------------------------+-- | Fill in a 'PerSessionData' with some dummy values.+makePerSessionData :: InputStream ByteString+ -> OutputStream ByteString+ -> IO PerSessionData+makePerSessionData readEnd writeEnd = do+ forceConnectionClose <- newIORef False+ let twiddleTimeout f = let z = f 0 in z `seq` return $! ()+ let localAddress = "127.0.0.1"+ let remoteAddress = "127.0.0.1"+ let remotePort = 43321+ newConnectionRef <- newIORef False++ let psd = PerSessionData forceConnectionClose+ twiddleTimeout+ newConnectionRef+ (mockSendFileHandler writeEnd)+ localAddress+ 80+ remoteAddress+ remotePort+ readEnd+ writeEnd++ return psd+++------------------------------------------------------------------------------+-- | Make a pipe -- the two Input/OutputStream pairs will communicate with each+-- other from separate threads by using 'Chan's.+makePipe :: PipeFunc+makePipe = do+ chan1 <- newChan+ chan2 <- newChan++ clientReadEnd <- Streams.chanToInput chan1+ clientWriteEnd <- Streams.chanToOutput chan2 >>=+ Streams.contramapM (evaluate . S.copy)+ serverReadEnd <- Streams.chanToInput chan2+ serverWriteEnd <- Streams.chanToOutput chan1 >>=+ Streams.contramapM (evaluate . S.copy)++ return ((clientReadEnd, clientWriteEnd), (serverReadEnd, serverWriteEnd))+++------------------------------------------------------------------------------+-- | Make a pipe -- the two Input/OutputStream pairs will communicate with each+-- other from separate threads by using 'Chan's. Data moving through the+-- streams will be logged to stdout.+_makeDebugPipe :: ByteString -> PipeFunc+_makeDebugPipe name = do+ chan1 <- newChan+ chan2 <- newChan++ clientReadEnd <- Streams.chanToInput chan1 >>=+ Streams.debugInputBS (S.append name "/client-rd")+ Streams.stderr+ clientWriteEnd <- Streams.chanToOutput chan2 >>=+ Streams.debugOutputBS (S.append name "/client-wr")+ Streams.stderr >>=+ Streams.contramapM (evaluate . S.copy)+ serverReadEnd <- Streams.chanToInput chan2 >>=+ Streams.debugInputBS (S.append name "/server-rd")+ Streams.stderr+ serverWriteEnd <- Streams.chanToOutput chan1 >>=+ Streams.debugOutputBS (S.append name "/server-wr")+ Streams.stderr >>=+ Streams.contramapM (evaluate . S.copy)++ return ((clientReadEnd, clientWriteEnd), (serverReadEnd, serverWriteEnd))+++------------------------------------------------------------------------------+type PipeFunc = IO ( (InputStream ByteString, OutputStream ByteString)+ , (InputStream ByteString, OutputStream ByteString)+ )++------------------------------------------------------------------------------+-- | Given a bunch of requests, convert them to bytestrings and pipeline them+-- into the 'httpSession' code, recording the results.+runRequestPipeline :: [T.RequestBuilder IO ()]+ -> Snap b+ -> IO [(Http.Response, ByteString)]+runRequestPipeline = runRequestPipelineDebug makePipe+++------------------------------------------------------------------------------+-- | Given a bunch of requests, convert them to bytestrings and pipeline them+-- into the 'httpSession' code, recording the results.+runRequestPipelineDebug :: PipeFunc+ -> [T.RequestBuilder IO ()]+ -> Snap b+ -> IO [(Http.Response, ByteString)]+runRequestPipelineDebug pipeFunc rbs handler = dieIfTimeout $ do+ ((clientRead, clientWrite), (serverRead, serverWrite)) <- pipeFunc++ sigClient <- newEmptyMVar+ results <- newMVar []++ forM_ rbs $ makeRequest >=> flip Streams.write clientWrite . Just+ Streams.write Nothing clientWrite++ myTid <- myThreadId+ conn <- Http.makeConnection "localhost"+ (return ())+ clientWrite+ clientRead++ bracket (do ctid <- mask $ \restore ->+ forkIO $ clientThread restore myTid clientRead conn+ results sigClient+ stid <- forkIO $ serverThread myTid serverRead serverWrite+ return (ctid, stid))+ (\(ctid, stid) -> mapM_ killThread [ctid, stid])+ (\_ -> await sigClient)+ readMVar results++ where+ await sig = takeMVar sig >>= either throwIO (const $ return ())++ serverThread myTid serverRead serverWrite = do+ runSession serverRead serverWrite handler+ `catch` \(e :: SomeException) -> throwTo myTid e++ clientThread restore myTid clientRead conn results sig =+ (try (restore loop) >>= putMVar (sig :: MVar (Either SomeException ())))+ `catch` \(e :: SomeException) -> throwTo myTid e++ where+ loop = do+ eof <- Streams.atEOF clientRead+ if eof+ then return ()+ else do+ (resp, body) <- Http.receiveResponse conn $ \rsp istr -> do+ !out <- liftM S.concat $ Streams.toList istr+ return (rsp, out)+ modifyMVar_ results (return . (++ [(resp, body)]))+ loop+++------------------------------------------------------------------------------+getSessionOutput :: [ByteString]+ -> Snap a+ -> IO ByteString+getSessionOutput input snap = do+ is <- Streams.fromList input >>= Streams.mapM (evaluate . S.copy)+ (os0, getList) <- Streams.listOutputStream+ os <- Streams.contramapM (evaluate . S.copy) os0+ runSession is os snap+ liftM S.concat getList+++------------------------------------------------------------------------------+runSession :: InputStream ByteString+ -> OutputStream ByteString+ -> Snap a+ -> IO ()+runSession readEnd writeEnd handler = do+ buffer <- newBuffer 64000+ perSessionData <- makePerSessionData readEnd writeEnd+ httpSession buffer (snapToServerHandler handler)+ (makeServerConfig ())+ perSessionData+ Streams.write Nothing writeEnd+++------------------------------------------------------------------------------+makeServerConfig :: hookState -> ServerConfig hookState+makeServerConfig hs = setOnException onEx .+ setOnNewRequest onStart .+ setLogError logErr .+ setLogAccess logAccess .+ setOnDataFinished onDataFinished .+ setOnEscape onEscape .+ setOnUserHandlerFinished onUserHandlerFinished .+ setDefaultTimeout 10 .+ setLocalHostname "backup-localhost" .+ setIsSecure False .+ setNumAcceptLoops 1 .+ setOnParse onParse $+ emptyServerConfig+ where+ onStart !psd = do+ void $ readIORef (_isNewConnection psd) >>= evaluate+ return hs++ logAccess !_ !_ !_ = return $! ()+ logErr !e = void $ evaluate $ toByteString e+ onParse !_ !_ = return $! ()+ onUserHandlerFinished !_ !_ !_ = return $! ()+ onDataFinished !_ !_ !_ = return $! ()+ onEx !_ !e = throwIO e+ onEscape !_ = return $! ()+++------------------------------------------------------------------------------+listOutputStream :: IO (OutputStream ByteString, IO [ByteString])+listOutputStream = do+ (os, out) <- Streams.listOutputStream+ os' <- Streams.contramapM (evaluate . S.copy) os+ return (os', out)+++------------------------------------------------------------------------------+data TestException = TestException+ deriving (Typeable, Show)+instance Exception TestException+++------------------------------------------------------------------------------+data Result = SendFile ByteString FilePath Word64 Word64+ | Output ByteString+ deriving (Eq, Ord, Show)+++------------------------------------------------------------------------------+runAcceptLoop :: [T.RequestBuilder IO ()]+ -> Snap a+ -> IO [Result]+runAcceptLoop requests snap = dieIfTimeout $ do+ -- make sure we don't log error on ThreadKilled.+ (_, errs') <- run afuncSuicide+ assertBool ("errs': " ++ show errs') $ null errs'++ -- make sure we gobble IOException.+ count <- newIORef 0+ (_, errs'') <- run $ afuncIOException count+ assertBool ("errs'': " ++ show errs'') $ length errs'' == 2++ liftM fst $ run acceptFunc++ where+ --------------------------------------------------------------------------+ run afunc = do+ reqStreams <- Streams.fromList requests >>=+ Streams.mapM makeRequest >>=+ Streams.lockingInputStream++ outputs <- newMVar []+ lock <- newMVar ()+ err <- newMVar []++ httpAcceptLoop (snapToServerHandler snap) (config err) $+ afunc reqStreams outputs lock++ out <- takeMVar outputs+ errs <- takeMVar err+ return (out, errs)++ --------------------------------------------------------------------------+ config mvar = (makeServerConfig ()) {+ _logError = \b -> let !s = toByteString b+ in modifyMVar_ mvar $ \xs -> do+ void (evaluate s)+ return (xs ++ [s])+ }++ --------------------------------------------------------------------------+ afuncSuicide :: InputStream ByteString+ -> MVar [Result]+ -> MVar ()+ -> AcceptFunc+ afuncSuicide _ _ lock = AcceptFunc $ \restore ->+ restore $ withMVar lock (\_ -> throwIO ThreadKilled)++ --------------------------------------------------------------------------+ afuncIOException :: IORef Int+ -> InputStream ByteString+ -> MVar [Result]+ -> MVar ()+ -> AcceptFunc+ afuncIOException ref _ _ lock = AcceptFunc $ \restore ->+ restore $ withMVar lock $ const $ do+ x <- readIORef ref+ writeIORef ref $! x + 1+ if x >= 2+ then throwIO ThreadKilled+ else throwIO $ userError "hello"++ --------------------------------------------------------------------------+ acceptFunc :: InputStream ByteString+ -> MVar [Result]+ -> MVar ()+ -> AcceptFunc+ acceptFunc inputStream output lock = AcceptFunc $ \restore -> restore $ do+ void $ takeMVar lock+ b <- atEOF+ when b $ myThreadId >>= killThread+ os <- Streams.makeOutputStream out >>=+ Streams.contramap S.copy+ return (sendFileFunc, "localhost", 80, "localhost", 55555, inputStream,+ os, putMVar lock ())++ where+ atEOF = Streams.peek inputStream >>= maybe (return True) f+ where+ f x | S.null x = do void $ Streams.read inputStream+ atEOF+ | otherwise = return False++ out (Just s) | S.null s = return ()+ out (Just s) = modifyMVar_ output $ return . (++ [Output s])+ out Nothing = return ()++ sendFileFunc !_ !bldr !fp !st !end =+ modifyMVar_ output $+ return . (++ [(SendFile (toByteString bldr) fp st end)])+++------------------------------------------------------------------------------+dieIfTimeout :: IO a -> IO a+dieIfTimeout m = timeout (10 * seconds) m >>= maybe (error "timeout") return+++------------------------------------------------------------------------------+seconds :: Int+seconds = (10::Int) ^ (6::Int)++------------------------------------------------------------------------------+toByteString :: Builder -> S.ByteString+toByteString = S.concat . L.toChunks . toLazyByteString
+ test/Snap/Internal/Http/Server/Socket/Tests.hs view
@@ -0,0 +1,171 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Snap.Internal.Http.Server.Socket.Tests (tests) where++------------------------------------------------------------------------------+import Control.Applicative ((<$>))+import qualified Network.Socket as N+------------------------------------------------------------------------------+import Control.Concurrent (forkIO, killThread, newEmptyMVar, putMVar, readMVar, takeMVar)+import qualified Control.Exception as E+import Data.IORef (newIORef, readIORef, writeIORef)+import Test.Framework (Test)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit (assertEqual)+------------------------------------------------------------------------------+import qualified Snap.Internal.Http.Server.Socket as Sock+import Snap.Test.Common (eatException, expectException, withSock)+------------------------------------------------------------------------------+#ifdef HAS_UNIX_SOCKETS+import System.Directory (getTemporaryDirectory)+import System.FilePath ((</>))+import qualified System.Posix as Posix+# if !MIN_VERSION_unix(2,6,0)+import Control.Monad.State (replicateM)+import Control.Monad.Trans.State.Strict as State+import qualified Data.Vector.Unboxed as V+import System.Directory (createDirectoryIfMissing)+import System.Random (StdGen, newStdGen, randomR)+# endif+#else+import Snap.Internal.Http.Server.Address (AddressNotSupportedException)+#endif++------------------------------------------------------------------------------+#ifdef HAS_UNIX_SOCKETS+mkdtemp :: String -> IO FilePath+# if MIN_VERSION_unix(2,6,0)+mkdtemp = Posix.mkdtemp++# else++tMPCHARS :: V.Vector Char+tMPCHARS = V.fromList $! ['a'..'z'] ++ ['0'..'9']++mkdtemp template = do+ suffix <- newStdGen >>= return . State.evalState (chooseN 8 tMPCHARS)+ let dir = template ++ suffix+ createDirectoryIfMissing False dir+ return dir+ where+ choose :: V.Vector Char -> State.State StdGen Char+ choose v = do let sz = V.length v+ idx <- State.state $ randomR (0, sz - 1)+ return $! (V.!) v idx++ chooseN :: Int -> V.Vector Char -> State.State StdGen String+ chooseN n v = replicateM n $ choose v+#endif+#endif++------------------------------------------------------------------------------+tests :: [Test]+tests = [+ testUnixSocketBind+#if !MIN_VERSION_network(3,0,0)+ , testAcceptFailure+ , testSockClosedOnListenException+#endif+ ]++------------------------------------------------------------------------------+-- TODO: fix these tests which rely on deprecated socket apis+#if !MIN_VERSION_network(3,0,0)+testSockClosedOnListenException :: Test+testSockClosedOnListenException = testCase "socket/closedOnListenException" $ do+ ref <- newIORef Nothing+ expectException $ Sock.bindSocketImpl (sso ref) bs ls "127.0.0.1" 4444+ (Just sock) <- readIORef ref+ let (N.MkSocket _ _ _ _ mvar) = sock+ readMVar mvar >>= assertEqual "socket closed" N.Closed++ where+ sso ref sock _ _ = do+ let (N.MkSocket _ _ _ _ mvar) = sock+ readMVar mvar >>= assertEqual "socket not connected" N.NotConnected+ writeIORef ref (Just sock) >> fail "set socket option"+ bs _ _ = fail "bindsocket"+ ls _ _ = fail "listen"++------------------------------------------------------------------------------+testAcceptFailure :: Test+testAcceptFailure = testCase "socket/acceptAndInitialize" $ do+ sockmvar <- newEmptyMVar+ donemvar <- newEmptyMVar+ E.bracket (Sock.bindSocket "127.0.0.1" $ fromIntegral N.aNY_PORT)+ (N.close)+ (\s -> do+ p <- fromIntegral <$> N.socketPort s+ forkIO $ server s sockmvar donemvar+ E.bracket (forkIO $ client p)+ (killThread)+ (\_ -> do+ csock <- takeMVar sockmvar+ takeMVar donemvar+ N.isConnected csock >>=+ assertEqual "closed" False+ )+ )+ where+ server sock sockmvar donemvar = serve `E.finally` putMVar donemvar ()+ where+ serve = eatException $ E.mask $ \restore ->+ Sock.acceptAndInitialize sock restore $ \(csock, _) -> do+ putMVar sockmvar csock+ fail "error"++ client port = withSock port (const $ return ())+#endif++testUnixSocketBind :: Test+#ifdef HAS_UNIX_SOCKETS+testUnixSocketBind = testCase "socket/unixSocketBind" $+ withSocketPath $ \path -> do+#if !MIN_VERSION_network(3,0,0)+ E.bracket (Sock.bindUnixSocket Nothing path) N.close $ \sock -> do+ N.isListening sock >>= assertEqual "listening" True+#endif++ expectException $ E.bracket (Sock.bindUnixSocket Nothing "a/relative/path")+ N.close doNothing++ expectException $ E.bracket (Sock.bindUnixSocket Nothing "/relative/../path")+ N.close doNothing++ expectException $ E.bracket (Sock.bindUnixSocket Nothing "/hopefully/not/existing/path")+ N.close doNothing++#ifdef LINUX+ -- Most (all?) BSD systems ignore access mode on unix sockets.+ -- Should we still check it?++ -- This is pretty much for 100% coverage+ expectException $ E.bracket (Sock.bindUnixSocket Nothing "/")+ N.close doNothing++ let mode = 0o766+ E.bracket (Sock.bindUnixSocket (Just mode) path) N.close $ \_ -> do+ -- Should check sockFd instead of path?+ sockMode <- fmap Posix.fileMode $ Posix.getFileStatus path+ assertEqual "access mode" (fromIntegral mode) $+ Posix.intersectFileModes Posix.accessModes sockMode+#endif+ where+ doNothing _ = return ()+ withSocketPath act = do+ tmpRoot <- getTemporaryDirectory+ tmpDir <- mkdtemp $ tmpRoot </> "snap-server-test-"+ let path = tmpDir </> "unixSocketBind.sock"+ E.finally (act path) $ do+ eatException $ Posix.removeLink path+ eatException $ Posix.removeDirectory tmpDir++#else+testUnixSocketBind = testCase "socket/unixSocketBind" $ do+ caught <- E.catch (Sock.bindUnixSocket Nothing "/tmp/snap-sock.sock" >> return False)+ $ \(e :: AddressNotSupportedException) -> length (show e) `seq` return True+ assertEqual "not supported" True caught++#endif
+ test/Snap/Internal/Http/Server/TimeoutManager/Tests.hs view
@@ -0,0 +1,136 @@+{-# LANGUAGE OverloadedStrings #-}++module Snap.Internal.Http.Server.TimeoutManager.Tests+ ( tests ) where++------------------------------------------------------------------------------+import Control.Concurrent (newEmptyMVar, putMVar, takeMVar)+import Control.Concurrent.Thread (forkIO, result)+import qualified Control.Exception as E+import Control.Monad (replicateM)+import Data.IORef (newIORef, readIORef, writeIORef)+import Data.Maybe (isJust)+------------------------------------------------------------------------------+import qualified Snap.Internal.Http.Server.Clock as Clock+import qualified Snap.Internal.Http.Server.TimeoutManager as TM+import System.Timeout (timeout)+import Test.Framework (Test)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit (assertBool, assertEqual)++------------------------------------------------------------------------------+tests :: [Test]+tests = [ testOneTimeout+ , testSlowToDie+ , testOneTimeoutAfterInactivity+ , testCancel+ , testTickle ]+++------------------------------------------------------------------------------+register :: IO () -> TM.TimeoutManager -> IO TM.TimeoutThread+register m t = TM.register t "test" $+ \restore -> restore (Clock.sleepSecs 9000)+ `E.finally` m+++------------------------------------------------------------------------------+testOneTimeout :: Test+testOneTimeout = testCase "timeout/oneTimeout" $ repeatedly $ do+ mgr <- TM.initialize 1 0.1 Clock.getClockTime+ oneTimeout mgr++------------------------------------------------------------------------------+testSlowToDie :: Test+testSlowToDie = testCase "timeout/slowToDie" $ repeatedly $ do+ mgr <- TM.initialize 1 0.1 Clock.getClockTime+ r <- newIORef False+ s <- newIORef False+ _ <- register (writeIORef r True >> Clock.sleepSecs 3 >> writeIORef s True) mgr+ Clock.sleepSecs 1.5+ readIORef r >>= assertEqual "started to die" True+ readIORef s >>= assertEqual "not dead yet" False+ Clock.sleepSecs 3+ readIORef s >>= assertEqual "dead" True+++------------------------------------------------------------------------------+testOneTimeoutAfterInactivity :: Test+testOneTimeoutAfterInactivity =+ testCase "timeout/oneTimeoutAfterInactivity" $ repeatedly $ do+ mgr <- TM.initialize 1 0.1 Clock.getClockTime+ Clock.sleepSecs 3+ oneTimeout mgr++------------------------------------------------------------------------------+repeatedly :: IO () -> IO ()+repeatedly m = dieIfTimeout $ do+ results <- replicateM 40 (forkIO m) >>= sequence . map snd+ mapM_ result results+++------------------------------------------------------------------------------+oneTimeout :: TM.TimeoutManager -> IO ()+oneTimeout mgr = do+ mv <- newEmptyMVar+ _ <- register (putMVar mv ()) mgr+ m <- timeout (3*seconds) $ takeMVar mv+ assertBool "timeout fired" $ isJust m+ Clock.sleepSecs 2+ TM.stop mgr+++------------------------------------------------------------------------------+testTickle :: Test+testTickle = testCase "timeout/tickle" $ repeatedly $ do+ mgr <- TM.initialize 5 0.1 Clock.getClockTime+ ref <- newIORef (0 :: Int)+ h <- register (writeIORef ref 1) mgr+ E.evaluate (length $ show h)+ Clock.sleepSecs 1+ b0 <- readIORef ref+ assertEqual "b0" 0 b0+ TM.tickle h 3+ Clock.sleepSecs 1+ b1 <- readIORef ref+ assertEqual "b1" 0 b1+ Clock.sleepSecs 5+ b2 <- readIORef ref+ assertEqual "b2" 1 b2+ TM.stop mgr+++------------------------------------------------------------------------------+testCancel :: Test+testCancel = testCase "timeout/cancel" $ repeatedly $ do+ mgr <- TM.initialize 3 0.1 Clock.getClockTime+ ref <- newIORef (0 :: Int)+ h <- register (writeIORef ref 1) mgr+ Clock.sleepSecs 1+ readIORef ref >>= assertEqual "b0" 0+ TM.cancel h+ TM.tickle h 10 -- make sure tickle ignores cancelled times+ Clock.sleepSecs 2+ readIORef ref >>= assertEqual "b1" 1+ Clock.sleepSecs 2+ h' <- register (writeIORef ref 2) mgr+ _ <- register (return ()) mgr+ TM.set h' 1+ Clock.sleepSecs 2+ readIORef ref >>= assertEqual "b2" 2+ _ <- register (writeIORef ref 3) mgr+ hs <- replicateM 1000 $! register (return ()) mgr+ mapM TM.cancel hs+ TM.stop mgr+ Clock.sleepSecs 1+ readIORef ref >>= assertEqual "b3" 3+++------------------------------------------------------------------------------+seconds :: Int+seconds = (10::Int) ^ (6::Int)+++------------------------------------------------------------------------------+dieIfTimeout :: IO a -> IO a+dieIfTimeout m = timeout (30 * seconds) m >>= maybe (error "timeout") return
+ test/Snap/Test/Common.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++------------------------------------------------------------------------------+module Snap.Test.Common where++------------------------------------------------------------------------------+import Control.DeepSeq (deepseq)+import Control.Exception.Lifted (SomeException (..), catch, evaluate, finally, try)+import Control.Monad (liftM, replicateM)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Trans.Control (MonadBaseControl)+import Data.ByteString.Builder (byteString, toLazyByteString)+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy as L+import Data.Monoid (Monoid (mappend, mempty))+import Data.Typeable (Typeable, typeOf)+import Network.Socket (Socket)+import qualified Network.Socket as N hiding (recv)+import System.Timeout (timeout)+import Test.HUnit (assertFailure)+import Test.QuickCheck (Arbitrary (arbitrary), choose)++import qualified Network.Socket.ByteString as N+#if !(MIN_VERSION_base(4,6,0))+import Prelude hiding (catch)+#endif+------------------------------------------------------------------------------+instance Arbitrary S.ByteString where+ arbitrary = liftM S.pack arbitrary++instance Arbitrary L.ByteString where+ arbitrary = do+ n <- choose(0,5)+ chunks <- replicateM n arbitrary+ return $! L.fromChunks chunks+++------------------------------------------------------------------------------+expectException :: IO a -> IO ()+expectException m = do+ e <- try m+ case e of+ Left (z::SomeException) -> length (show z) `seq` return ()+ Right _ -> assertFailure "expected exception, didn't get it"+++------------------------------------------------------------------------------+expectExceptionBeforeTimeout :: IO a -- ^ action to run+ -> Int -- ^ number of seconds to expect+ -- exception by+ -> IO Bool+expectExceptionBeforeTimeout act nsecs = do+ x <- timeout (nsecs * (10::Int)^(6::Int)) f+ case x of+ Nothing -> return False+ (Just y) -> return y++ where+ f = (act >> return False) `catch` \(e::SomeException) -> do+ if show e == "<<timeout>>"+ then return False+ else return True+++------------------------------------------------------------------------------+withSock :: Int -> (Socket -> IO a) -> IO a+withSock port go = do+ addr <- liftM (N.addrAddress . Prelude.head) $+ N.getAddrInfo (Just myHints)+ (Just "127.0.0.1")+ (Just $ show port)++ sock <- N.socket N.AF_INET N.Stream N.defaultProtocol+ N.connect sock addr++ go sock `finally` close sock++ where+#if MIN_VERSION_network(2,7,0)+ close = N.close+#else+ close = N.sClose+#endif+ myHints = N.defaultHints { N.addrFlags = [ N.AI_NUMERICHOST ] }+++------------------------------------------------------------------------------+recvAll :: Socket -> IO ByteString+recvAll sock = do+ b <- f mempty sock+ return $! S.concat $ L.toChunks $ toLazyByteString b++ where+ f b sk = do+ s <- N.recv sk 100000+ if S.null s+ then return b+ else f (b `mappend` byteString s) sk+++------------------------------------------------------------------------------+ditchHeaders :: [ByteString] -> [ByteString]+ditchHeaders ("":xs) = xs+ditchHeaders ("\r":xs) = xs+ditchHeaders (_:xs) = ditchHeaders xs+ditchHeaders [] = []+++------------------------------------------------------------------------------+forceSameType :: a -> a -> a+forceSameType _ a = a+++------------------------------------------------------------------------------+-- | Kill the false negative on derived show instances.+coverShowInstance :: (Monad m, Show a) => a -> m ()+coverShowInstance x = a `deepseq` b `deepseq` c `deepseq` return ()+ where+ a = showsPrec 0 x ""+ b = show x+ c = showList [x] ""+++------------------------------------------------------------------------------+coverReadInstance :: (MonadIO m, Read a) => a -> m ()+coverReadInstance x = do+ liftIO $ eatException $ evaluate $ forceSameType [(x,"")] $ readsPrec 0 ""+ liftIO $ eatException $ evaluate $ forceSameType [([x],"")] $ readList ""+++------------------------------------------------------------------------------+coverEqInstance :: (Monad m, Eq a) => a -> m ()+coverEqInstance x = a `seq` b `seq` return ()+ where+ a = x == x+ b = x /= x+++------------------------------------------------------------------------------+coverOrdInstance :: (Monad m, Ord a) => a -> m ()+coverOrdInstance x = a `deepseq` b `deepseq` return ()+ where+ a = [ x < x+ , x >= x+ , x > x+ , x <= x+ , compare x x == EQ ]++ b = min a $ max a a+++------------------------------------------------------------------------------+coverTypeableInstance :: (Monad m, Typeable a) => a -> m ()+coverTypeableInstance a = typeOf a `seq` return ()+++------------------------------------------------------------------------------+eatException :: (MonadBaseControl IO m) => m a -> m ()+eatException a = (a >> return ()) `catch` handler+ where+ handler :: (MonadBaseControl IO m) => SomeException -> m ()+ handler _ = return ()+++------------------------------------------------------------------------------+timeoutIn :: Int -> IO a -> IO a+timeoutIn n m = timeout (n * 1000000) m >>= maybe (fail "timeout") return
+ test/System/SendFile/Tests.hs view
@@ -0,0 +1,262 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE OverloadedStrings #-}+module System.SendFile.Tests (tests) where++------------------------------------------------------------------------------+import Control.Concurrent.MVar (MVar, modifyMVar, modifyMVar_, newMVar, readMVar)+import Control.Exception (evaluate)+import Data.ByteString.Builder (byteString)+import qualified Data.ByteString.Char8 as S+import Foreign.C.Error (Errno (..), eAGAIN, eCONNRESET, eOK)+import Foreign.C.Types (CChar, CInt (..), CSize)+import Foreign.Storable (peek)+import Test.Framework (Test)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit (assertEqual)+------------------------------------------------------------------------------+import Snap.Test.Common (expectException)+import qualified System.SendFile as SF++#if defined(LINUX)+import Control.Monad (void)+import Foreign.Ptr (Ptr, nullPtr)+import System.Posix.Types (COff, CSsize, Fd)+import qualified System.SendFile.Linux as SFI+#elif defined(FREEBSD)+import Control.Monad (void)+import Foreign.Ptr (Ptr)+import Foreign.Storable+import System.Posix.Types (COff, Fd)+import qualified System.SendFile.FreeBSD as SFI+#elif defined(OSX)+import Control.Monad (void, when)+import Foreign.Ptr (Ptr)+import Foreign.Storable (poke)+import System.Posix.Types (COff, Fd)+import qualified System.SendFile.Darwin as SFI+#endif+++------------------------------------------------------------------------------+tests :: [Test]+tests = [ testSendHeaders+ , testSendHeaderCrash+ , testSendFile+ , testSendFileCrash+ , testSendFileZero+ , testTrivials+ ]+++------------------------------------------------------------------------------+testSendHeaders :: Test+testSendHeaders = testCase "sendfile/sendHeaders" $ do+ callLog <- newMVar []+ sampleData <- newMVar sampleActions+ nWaits <- newMVar (0 :: Int)+ let bumpWaits = \x -> x `seq` modifyMVar_ nWaits (return . (+1))+ SF.sendHeadersImpl (sendHeadersMockSendFunc sampleData callLog) bumpWaits+ builder 100+ [c1, c2, c3] <- readMVar callLog+ assertEqual "sendHeaders1" c1 c2+ assertEqual "sendHeaders2" 8 (_sz c3)+ readMVar nWaits >>= assertEqual "sendHeaders3" 1++ where+ builder = byteString $ S.replicate 10 ' '+ sampleActions = [ c_set_errno eAGAIN >> return (-1)+ , return 2+ , return 8+ ]+++------------------------------------------------------------------------------+testSendHeaderCrash :: Test+testSendHeaderCrash = testCase "sendfile/sendHeaders/crash" $ do+ callLog <- newMVar []+ sampleData <- newMVar sampleActions+ nWaits <- newMVar (0 :: Int)+ let bumpWaits = \x -> x `seq` modifyMVar_ nWaits (return . (+1))+ expectException $+ SF.sendHeadersImpl (sendHeadersMockSendFunc sampleData callLog) bumpWaits+ builder 100+ where+ builder = byteString $ S.replicate 10 ' '+ sampleActions = [ c_set_errno eCONNRESET >> return (-1) ]+++------------------------------------------------------------------------------+testTrivials :: Test+testTrivials = testCase "sendfile/trivials" $+ void (evaluate $ length SF.sendFileMode)+++------------------------------------------------------------------------------+data SendHeadersCallLog = SendHeadersCallLog {+ _fd :: Fd+ , _str :: Ptr CChar+ , _sz :: CSize+ , _flags :: CInt+ }+ deriving (Eq, Show, Ord)+++------------------------------------------------------------------------------+sendHeadersMockSendFunc :: MVar [IO CSize] -- ^ sample outputs+ -> MVar [SendHeadersCallLog] -- ^ log of calls+ -> Fd -> Ptr CChar -> CSize -> CInt -> IO CSize+sendHeadersMockSendFunc sampleData callLog !fd !cstr !clen !flags = do+ modifyMVar_ callLog (return . (++ [SendHeadersCallLog fd cstr clen flags]))+ x <- modifyMVar sampleData $ \xs -> return $!+ if null xs then ([], return Nothing) else (tail xs, fmap Just $! head xs)+ x >>= maybe (c_set_errno eCONNRESET >> return (-1))+ (return)+++foreign import ccall unsafe "set_errno" c_set_errno :: Errno -> IO ()+++------------------------------------------------------------------------------+-- Testing for internal sendfile via dep injection+#if defined(LINUX)+data SendFileCallLog = SendFileCallLog {+ _sf_fd1 :: Fd+ , _sf_fd2 :: Fd+ , _sf_off :: COff+ , _sf_sz :: CSize+ }+ deriving (Eq, Show, Ord)+++------------------------------------------------------------------------------+sendFileMockSendFunc :: MVar [IO CSize] -- ^ sample outputs+ -> MVar [SendFileCallLog] -- ^ log of calls+ -> Fd -> Fd -> Ptr COff -> CSize -> IO CSsize+sendFileMockSendFunc sampleData callLog !fd1 !fd2 !cstr !clen = do+ cp <- if cstr == nullPtr then return (-1) else peek cstr++ modifyMVar_ callLog (return . (++ [SendFileCallLog fd1 fd2 cp clen]))+ x <- modifyMVar sampleData $ \xs -> return $!+ if null xs then ([], return Nothing) else (tail xs, fmap Just $! head xs)+ x >>= maybe (c_set_errno eCONNRESET >> return (-1))+ (return . fromIntegral)++#elif defined(FREEBSD)+data SendFileCallLog = SendFileCallLog {+ _sf_fd1 :: Fd+ , _sf_fd2 :: Fd+ , _sf_off :: COff+ , _sf_sz :: CSize+ }+ deriving (Eq, Show, Ord)+++------------------------------------------------------------------------------+sendFileMockSendFunc :: MVar [IO CInt] -- ^ sample outputs+ -> MVar [SendFileCallLog] -- ^ log of calls+ -> Fd -> Fd -> COff -> CSize -> Ptr () -> Ptr COff+ -> CInt -> IO CInt+sendFileMockSendFunc sampleData callLog !fd1 !fd2 !off !clen !_ !pbytes !_ = do+ modifyMVar_ callLog (return . (++ [SendFileCallLog fd1 fd2 off clen]))+ x <- modifyMVar sampleData $ \xs -> return $!+ if null xs then ([], return Nothing) else (tail xs, fmap Just $! head xs)+ x >>= maybe (c_set_errno eCONNRESET >> return (-1)) return+++#elif defined(OSX)+data SendFileCallLog = SendFileCallLog {+ _sf_fd1 :: Fd+ , _sf_fd2 :: Fd+ , _sf_off :: COff+ , _sf_sz :: COff+ }+ deriving (Eq, Show, Ord)+++------------------------------------------------------------------------------+sendFileMockSendFunc :: MVar [IO CInt] -- ^ sample outputs+ -> MVar [SendFileCallLog] -- ^ log of calls+ -> Fd -> Fd -> COff -> Ptr COff -> IO CInt+sendFileMockSendFunc sampleData callLog !fd1 !fd2 !off !pnbytes = do+ !clen <- peek pnbytes+ modifyMVar_ callLog (return . (++ [SendFileCallLog fd1 fd2 off clen]))+ x <- modifyMVar sampleData $ \xs -> return $!+ if null xs then ([], return Nothing) else (tail xs, fmap Just $! head xs)+ x >>= maybe (c_set_errno eCONNRESET >> return (-1))+ (\l -> do when (l > 0) (poke pnbytes (fromIntegral l))+ return l)++#endif+++------------------------------------------------------------------------------+testSendFile :: Test+testSendFile = testCase "sendfile/sendfile-impl" $ do+ callLog <- newMVar []+ sampleData <- newMVar sampleActions+ nWaits <- newMVar (0 :: Int)+ let bumpWaits = \x -> x `seq` modifyMVar_ nWaits (return . (+1))+ SFI.sendFileImpl (sendFileMockSendFunc sampleData callLog) bumpWaits+ 100 101 0 10+ [c1, c2] <- readMVar callLog+ assertEqual "sendFile1" c1 c2+ assertEqual "sendFile2" 10 (_sf_sz c2)+ readMVar nWaits >>= assertEqual "sendFile3" 1++ modifyMVar_ callLog $ const $ return []+ modifyMVar_ nWaits $ const $ return 0+ modifyMVar_ sampleData $ const $ return sampleActions2++ SFI.sendFileImpl (sendFileMockSendFunc sampleData callLog) bumpWaits+ 100 101 1 9++ [_, c4] <- readMVar callLog++ readMVar nWaits >>= assertEqual "nwaits-2" 1+ assertEqual "sendFile3" 9 (_sf_sz c4)+ assertEqual "sendFile3-off" 1 (_sf_off c4)+++ where+ sampleActions = [ c_set_errno eAGAIN >> return (-1)+ , c_set_errno eOK >> return 2+ ]++ sampleActions2 = [ c_set_errno eAGAIN >> return (-1)+ , c_set_errno eOK >> return 2+ ]+++------------------------------------------------------------------------------+testSendFileZero :: Test+testSendFileZero = testCase "sendfile/sendfile-zero" $ do+ callLog <- newMVar []+ sampleData <- newMVar sampleActions+ nWaits <- newMVar (0 :: Int)+ let bumpWaits = \x -> x `seq` modifyMVar_ nWaits (return . (+1))+ c <- SFI.sendFileImpl (sendFileMockSendFunc sampleData callLog) bumpWaits+ 100 101 0 0+ readMVar callLog >>= assertEqual "empty call log" []+ readMVar nWaits >>= assertEqual "no waits" 0+ assertEqual "no bytes read" 0 c++ where+ sampleActions = [ c_set_errno eAGAIN >> return (-1)+ , c_set_errno eOK >> return 2+ ]+++------------------------------------------------------------------------------+testSendFileCrash :: Test+testSendFileCrash = testCase "sendfile/sendFile/crash" $ do+ callLog <- newMVar []+ sampleData <- newMVar sampleActions+ nWaits <- newMVar (0 :: Int)+ let bumpWaits = \x -> x `seq` modifyMVar_ nWaits (return . (+1))+ expectException $+ SFI.sendFileImpl (sendFileMockSendFunc sampleData callLog) bumpWaits+ 100 101 0 10+ where+ sampleActions = [ c_set_errno eCONNRESET >> return (-1) ]
+ test/Test/Blackbox.hs view
@@ -0,0 +1,697 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Test.Blackbox+ ( tests+ , haTests+ , ssltests+ , startTestServers+ ) where++--------------------------------------------------------------------------------+import Control.Applicative ((<$>))+import Control.Arrow (first)+import Control.Concurrent (MVar, ThreadId, forkIO, forkIOWithUnmask, killThread, newEmptyMVar, putMVar, takeMVar, threadDelay, tryPutMVar)+import Control.Exception (bracket, bracketOnError, finally, mask_)+import Control.Monad (forM_, forever, void, when)+import qualified Data.ByteString.Base16 as B16+import Data.ByteString.Builder (byteString)+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import Data.CaseInsensitive (CI)+import qualified Data.CaseInsensitive as CI+import Data.List (sort)+import Data.Monoid (Monoid (mconcat, mempty))+import qualified Network.Http.Client as HTTP+import qualified Network.Http.Types as HTTP+import qualified Network.Socket as N+import qualified Network.Socket.ByteString as NB+import Prelude (Bool (..), Eq (..), IO, Int, Maybe (..), Show (..), String, concat, concatMap, const, dropWhile, elem, flip, fromIntegral, fst, head, id, map, mapM_, maybe, min, not, null, otherwise, putStrLn, replicate, return, reverse, uncurry, ($), ($!), (*), (++), (.), (^))+import qualified Prelude+------------------------------------------------------------------------------+#ifdef OPENSSL+import qualified OpenSSL.Session as SSL+#endif+import qualified System.IO.Streams as Streams+import System.Timeout (timeout)+import Test.Framework (Test, TestOptions' (topt_maximum_generated_tests), plusTestOptions)+import Test.Framework.Providers.HUnit (testCase)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.HUnit hiding (Test, path)+import Test.QuickCheck (Arbitrary (arbitrary))+import Test.QuickCheck.Monadic (forAllM, monadicIO)+import qualified Test.QuickCheck.Monadic as QC+import qualified Test.QuickCheck.Property as QC+------------------------------------------------------------------------------+import Snap.Internal.Debug (debug)+import Snap.Internal.Http.Server.Session (httpAcceptLoop, snapToServerHandler)+import qualified Snap.Internal.Http.Server.Socket as Sock+import qualified Snap.Internal.Http.Server.TLS as TLS+import qualified Snap.Internal.Http.Server.Types as Types+import Snap.Test.Common (ditchHeaders, eatException, expectExceptionBeforeTimeout, recvAll, timeoutIn, withSock)+import Test.Common.Rot13 (rot13)+import Test.Common.TestHandler (testHandler)+++------------------------------------------------------------------------------+tests :: Int -> [Test]+tests port = map (\f -> f False port "") testFunctions++ssltests :: Maybe Int -> [Test]+ssltests = maybe [] httpsTests+ where httpsTests port = map (\f -> f True port sslname) testFunctions+ sslname = "ssl/"++haTests :: Int -> [Test]+haTests port = [ testHaProxy port+ , testHaProxyLocal port+ , testHaProxyFileServe port+ ]++testFunctions :: [Bool -> Int -> String -> Test]+testFunctions = [ testPong+-- FIXME: waiting on http-enumerator patch for HEAD behaviour+-- , testHeadPong+ , testEcho+ , testRot13+ , testSlowLoris+ , testBlockingRead+ , testBigResponse+ , testPartial+ , testFileUpload+ , testTimeoutTickle+ , testHasDateHeader+ , testServerHeader+ , testFileServe+ , testTimelyRedirect+ , testChunkedHead+ ]++------------------------------------------------------------------------------+startServer :: Types.ServerConfig hookState+ -> IO a+ -> (a -> N.Socket)+ -> (a -> Types.AcceptFunc)+ -> IO (ThreadId, Int, MVar ())+startServer config bind projSock afunc =+ bracketOnError bind (N.close . projSock) forkServer+ where+ forkServer a = do+ mv <- newEmptyMVar+ port <- fromIntegral <$> N.socketPort (projSock a)+ tid <- forkIO $+ eatException $+ (httpAcceptLoop (snapToServerHandler testHandler)+ config+ (afunc a)+ `finally` putMVar mv ())+ return (tid, port, mv)+++------------------------------------------------------------------------------+-- | Returns the thread the server is running in as well as the port it is+-- listening on.+data TestServerType = NormalTest | ProxyTest | SSLTest+ deriving (Show)++startTestSocketServer :: TestServerType -> IO (ThreadId, Int, MVar ())+startTestSocketServer serverType = do+ putStrLn $ "Blackbox: starting " ++ show serverType ++ " server"+ case serverType of+ NormalTest -> startServer emptyServerConfig bindSock id Sock.httpAcceptFunc+ ProxyTest -> startServer emptyServerConfig bindSock id Sock.haProxyAcceptFunc+ SSLTest -> startServer emptyServerConfig bindSSL fst+ (uncurry TLS.httpsAcceptFunc)+ where+#if MIN_VERSION_network(2,7,0)+ anyport = N.defaultPort+#else+ anyport = N.aNY_PORT+#endif++ bindSSL = do+ sockCtx <- TLS.bindHttps "127.0.0.1"+ (fromIntegral anyport)+ "test/cert.pem"+ False+ "test/key.pem"+#ifdef OPENSSL+ -- Set client code not to verify+ HTTP.modifyContextSSL $ \ctx -> do+ SSL.contextSetVerificationMode ctx SSL.VerifyNone+ return ctx+#endif+ return sockCtx++ bindSock = Sock.bindSocket "127.0.0.1" (fromIntegral anyport)++ logAccess !_ !_ !_ = return ()+ logError !_ = return ()+ onStart !_ = return ()+ onParse !_ !_ = return ()+ onUserHandlerFinished !_ !_ !_ = return ()+ onDataFinished !_ !_ !_ = return ()+ onExceptionHook !_ !_ = return ()+ onEscape !_ = return ()++ emptyServerConfig = Types.ServerConfig logAccess+ logError+ onStart+ onParse+ onUserHandlerFinished+ onDataFinished+ onExceptionHook+ onEscape+ "localhost"+ 6+ False+ 1+++------------------------------------------------------------------------------+waitabit :: IO ()+waitabit = threadDelay $ 2*seconds+++------------------------------------------------------------------------------+seconds :: Int+seconds = (10::Int) ^ (6::Int)+++------------------------------------------------------------------------------+fetch :: ByteString -> IO ByteString+fetch url = HTTP.get url HTTP.concatHandler'+++------------------------------------------------------------------------------+fetchWithHeaders :: ByteString+ -> IO (ByteString, [(CI ByteString, ByteString)])+fetchWithHeaders url = HTTP.get url h+ where+ h resp is = do+ let hdrs = map (first CI.mk) $ HTTP.retrieveHeaders $ HTTP.getHeaders resp+ body <- HTTP.concatHandler' resp is+ return (body, hdrs)+++------------------------------------------------------------------------------+slowTestOptions :: Bool -> TestOptions' Maybe+slowTestOptions ssl =+ if ssl+ then mempty { topt_maximum_generated_tests = Just 75 }+ else mempty { topt_maximum_generated_tests = Just 300 }+++------------------------------------------------------------------------------+-- FIXME: waiting on http-enumerator patch for HEAD behaviour+-- headPong :: Bool -> Int -> IO ByteString+-- headPong ssl port = do+-- let uri = (if ssl then "https" else "http")+-- ++ "://127.0.0.1:" ++ show port ++ "/echo"++-- req0 <- HTTP.parseUrl uri++-- let req = req0 { HTTP.method = "HEAD" }+-- rsp <- HTTP.httpLbs req+-- return $ S.concat $ L.toChunks $ HTTP.responseBody rsp+++------------------------------------------------------------------------------+-- FIXME: waiting on http-enumerator patch for HEAD behaviour+-- testHeadPong :: Bool -> Int -> String -> Test+-- testHeadPong ssl port name = testCase (name ++ "blackbox/pong/HEAD") $ do+-- doc <- headPong ssl port+-- assertEqual "pong HEAD response" "" doc+++------------------------------------------------------------------------------+-- TODO: doesn't work w/ ssl+testBlockingRead :: Bool -> Int -> String -> Test+testBlockingRead ssl port name =+ testCase (name ++ "blackbox/testBlockingRead") $+ if ssl then return () else runIt++ where+ runIt = withSock port $ \sock -> do+ m <- timeout (60*seconds) $ go sock+ maybe (assertFailure "timeout")+ (const $ return ())+ m++ go sock = do+ NB.sendAll sock "GET /"+ waitabit+ NB.sendAll sock "pong HTTP/1.1\r\n"+ NB.sendAll sock "Host: 127.0.0.1\r\n"+ NB.sendAll sock "Content-Length: 0\r\n"+ NB.sendAll sock "Connection: close\r\n\r\n"++ resp <- recvAll sock++ let s = head $ ditchHeaders $ S.lines resp++ assertEqual "pong response" "PONG" s+++------------------------------------------------------------------------------+-- TODO: this one doesn't work w/ SSL+testSlowLoris :: Bool -> Int -> String -> Test+testSlowLoris ssl port name = testCase (name ++ "blackbox/slowloris") $+ if ssl then return () else withSock port go++ where+ go sock = do+ NB.sendAll sock "POST /echo HTTP/1.1\r\n"+ NB.sendAll sock "Host: 127.0.0.1\r\n"+ NB.sendAll sock "Content-Length: 2500000\r\n"+ NB.sendAll sock "Connection: close\r\n\r\n"++ b <- expectExceptionBeforeTimeout (loris sock) 30++ assertBool "didn't catch slow loris attack" b++ loris sock = forever $ do+ NB.sendAll sock "."+ waitabit+++------------------------------------------------------------------------------+testRot13 :: Bool -> Int -> String -> Test+testRot13 ssl port name =+ plusTestOptions (slowTestOptions ssl) $+ testProperty (name ++ "blackbox/rot13") $+ monadicIO $ forAllM arbitrary prop+ where+ prop txt = do+ let uri = (if ssl then "https" else "http")+ ++ "://127.0.0.1:" ++ show port ++ "/rot13"++ doc <- QC.run $ HTTP.post (S.pack uri) "text/plain"+ (Streams.write (Just $ byteString txt))+ HTTP.concatHandler'+ QC.assert $ txt == rot13 doc+++------------------------------------------------------------------------------+doPong :: Bool -> Int -> IO ByteString+doPong ssl port = do+ debug "getting URI"+ let !uri = (if ssl then "https" else "http")+ ++ "://127.0.0.1:" ++ show port ++ "/pong"+ debug $ "URI is: '" ++ uri ++ "', calling simpleHttp"++ rsp <- fetch $ S.pack uri++ debug $ "response was " ++ show rsp+ return rsp+++------------------------------------------------------------------------------+testPong :: Bool -> Int -> String -> Test+testPong ssl port name = testCase (name ++ "blackbox/pong") $ do+ doc <- doPong ssl port+ assertEqual "pong response" "PONG" doc+++------------------------------------------------------------------------------+testHasDateHeader :: Bool -> Int -> String -> Test+testHasDateHeader ssl port name = testCase (name ++ "blackbox/hasDateHdr") $ do+ let !url = (if ssl then "https" else "http") ++ "://127.0.0.1:" ++ show port+ ++ "/pong"+ (rsp, hdrs) <- fetchWithHeaders $ S.pack url++ let hasDate = "date" `elem` map fst hdrs+ when (not hasDate) $ do+ putStrLn "server not sending dates:"+ forM_ hdrs $ \(k,v) -> S.putStrLn $ S.concat [CI.original k, ": ", v]+ assertBool "has date" hasDate+ assertEqual "pong response" "PONG" rsp+++------------------------------------------------------------------------------+testChunkedHead :: Bool -> Int -> String -> Test+testChunkedHead ssl port name = testCase (name ++ "blackbox/chunkedHead") $+ if ssl then return () else withSock port go+ where+ go sock = do+ NB.sendAll sock $ S.concat [ "HEAD /chunked HTTP/1.1\r\n"+ , "Host: localhost\r\n"+ , "\r\n"+ ]+ s <- NB.recv sock 4096+ assertBool (concat [ "no body: received '"+ , S.unpack s+ , "'" ]) $ isOK s++ split x l | S.null x = reverse l+ | otherwise = let (a, b) = S.break (== '\r') x+ b' = S.drop 2 b+ in split b' (a : l)++ isOK s = let lns = split s []+ lns' = Prelude.drop 1 $ dropWhile (not . S.null) lns+ in null lns'+++------------------------------------------------------------------------------+-- TODO: no ssl here+-- test server's ability to trap/recover from IO errors+testPartial :: Bool -> Int -> String -> Test+testPartial ssl port name =+ testCase (name ++ "blackbox/testPartial") $+ if ssl then return () else runIt++ where+ runIt = do+ m <- timeout (60*seconds) go+ maybe (assertFailure "timeout")+ (const $ return ())+ m++ go = do+ withSock port $ \sock ->+ NB.sendAll sock "GET /pong HTTP/1.1\r\n"++ doc <- doPong ssl port+ assertEqual "pong response" "PONG" doc+++------------------------------------------------------------------------------+-- TODO: no ssl here+-- test server's ability to trap/recover from IO errors+testTimelyRedirect :: Bool -> Int -> String -> Test+testTimelyRedirect ssl port name =+ testCase (name ++ "blackbox/testTimelyRedirect") $+ if ssl then return () else runIt++ where+ runIt = do+ m <- timeout (5*seconds) go+ maybe (assertFailure "timeout")+ (const $ return ())+ m++ go = do+ withSock port $ \sock -> do+ NB.sendAll sock $ S.concat [ "GET /redirect HTTP/1.1\r\n"+ , "Host: localhost\r\n\r\n" ]+ resp <- NB.recv sock 100000+ assertBool "wasn't code 302" $ S.isInfixOf "302" resp+ assertBool "didn't have content length" $+ S.isInfixOf "content-length: 0" resp+++------------------------------------------------------------------------------+-- TODO: no ssl+testBigResponse :: Bool -> Int -> String -> Test+testBigResponse ssl port name =+ testCase (name ++ "blackbox/testBigResponse") $+ if ssl then return () else runIt+ where+ runIt = withSock port $ \sock -> do+ m <- timeout (120*seconds) $ go sock+ maybe (assertFailure "timeout")+ (const $ return ())+ m++ go sock = do+ NB.sendAll sock "GET /bigresponse HTTP/1.1\r\n"+ NB.sendAll sock "Host: 127.0.0.1\r\n"+ NB.sendAll sock "Content-Length: 0\r\n"+ NB.sendAll sock "Connection: close\r\n\r\n"++ let body = S.replicate 4000000 '.'+ resp <- recvAll sock++ let s = head $ ditchHeaders $ S.lines resp++ assertBool "big response" $ body == s+++------------------------------------------------------------------------------+testHaProxy :: Int -> Test+testHaProxy port = testCase "blackbox/haProxy" runIt++ where+ runIt = withSock port $ \sock -> do+ m <- timeout (120*seconds) $ go sock+ maybe (assertFailure "timeout")+ (const $ return ())+ m++ go sock = do+ NB.sendAll sock $ S.concat+ [ "PROXY TCP4 1.2.3.4 5.6.7.8 1234 5678\r\n"+ , "GET /remoteAddrPort HTTP/1.1\r\n"+ , "Host: 127.0.0.1\r\n"+ , "Content-Length: 0\r\n"+ , "Connection: close\r\n\r\n"+ ]++ resp <- recvAll sock++ let s = head $ ditchHeaders $ S.lines resp++ when (s /= "1.2.3.4:1234") $ S.putStrLn s+ assertEqual "haproxy response" "1.2.3.4:1234" s+++------------------------------------------------------------------------------+testHaProxyFileServe :: Int -> Test+testHaProxyFileServe port = testCase "blackbox/haProxyFileServe" runIt+ where+ runIt = withSock port $ \sock -> do+ m <- timeout (120*seconds) $ go sock+ maybe (assertFailure "timeout")+ (const $ return ())+ m++ go sock = do+ NB.sendAll sock $ S.concat+ [ "PROXY UNKNOWN\r\n"+ , "GET /fileserve/hello.txt HTTP/1.1\r\n"+ , "Host: 127.0.0.1\r\n"+ , "Content-Length: 0\r\n"+ , "Connection: close\r\n\r\n"+ ]++ resp <- recvAll sock++ let s = head $ ditchHeaders $ S.lines resp++ assertEqual "haproxy response" "hello world" s+++------------------------------------------------------------------------------+testHaProxyLocal :: Int -> Test+testHaProxyLocal port = testCase "blackbox/haProxyLocal" runIt++ where+#if MIN_VERSION_network(2,7,0)+ anyport = N.defaultPort+#else+ anyport = N.aNY_PORT+#endif++ remoteAddrServer :: N.Socket+ -> MVar (Maybe String)+ -> (forall a . IO a -> IO a)+ -> IO ()+ remoteAddrServer ssock mvar restore =+ timeoutIn 10 $+ flip finally (tryPutMVar mvar Nothing) $+ bracket (restore $ N.accept ssock)+ (eatException . N.close . fst)+ (\(_, peer) -> putMVar mvar $! Just $! show peer)++ slurp p input = timeoutIn 10 $ withSock p+ $ \sock -> do NB.sendAll sock input+ recvAll sock++ determineSourceInterfaceAddr =+ timeoutIn 10 $+ bracket+ (Sock.bindSocket "127.0.0.1" (fromIntegral anyport))+ (eatException . N.close)+ (\ssock -> do+ mv <- newEmptyMVar+ svrPort <- fromIntegral <$> N.socketPort ssock+ bracket (mask_ $ forkIOWithUnmask $ remoteAddrServer ssock mv)+ (eatException . killThread)+ (const $ do void $ slurp svrPort ""+ (Just s) <- takeMVar mv+ return $! fst $ S.breakEnd (==':') $ S.pack s))++ runIt = do+ saddr <- determineSourceInterfaceAddr+ resp <- slurp port $ S.concat+ [ "PROXY UNKNOWN\r\n"+ , "GET /remoteAddrPort HTTP/1.1\r\n"+ , "Host: 127.0.0.1\r\n"+ , "Content-Length: 0\r\n"+ , "Connection: close\r\n\r\n"+ ]++ let s = head $ ditchHeaders $ S.lines resp++ when (not $ S.isPrefixOf saddr s) $ S.putStrLn s+ assertBool "haproxy response" $ S.isPrefixOf saddr s+++------------------------------------------------------------------------------+-- This test checks two things:+--+-- 1. that the timeout tickling logic works+-- 2. that "flush" is passed along through a gzip operation.+testTimeoutTickle :: Bool -> Int -> String -> Test+testTimeoutTickle ssl port name =+ testCase (name ++ "blackbox/timeout/tickle") $ do+ let uri = (if ssl then "https" else "http")+ ++ "://127.0.0.1:" ++ show port ++ "/timeout/tickle"+ doc <- fetch $ S.pack uri+ let expected = S.concat $ replicate 10 ".\n"+ assertEqual "response equal" expected doc+++------------------------------------------------------------------------------+testFileServe :: Bool -> Int -> String -> Test+testFileServe ssl port name =+ testCase (name ++ "blackbox/fileserve") $ do+ let uri = (if ssl then "https" else "http")+ ++ "://127.0.0.1:" ++ show port ++ "/fileserve/hello.txt"+ doc <- fetch $ S.pack uri+ let expected = "hello world\n"+ assertEqual "response equal" expected doc+++------------------------------------------------------------------------------+testFileUpload :: Bool -> Int -> String -> Test+testFileUpload ssl port name =+ plusTestOptions (slowTestOptions ssl) $+ testProperty (name ++ "blackbox/upload") $+ QC.mapSize (if ssl then min 100 else min 300) $+ monadicIO $+ forAllM arbitrary prop+ where+ boundary = "boundary-jdsklfjdsalkfjadlskfjldskjfldskjfdsfjdsklfldksajfl"++ prefix = [ "--"+ , boundary+ , "\r\n"+ , "content-disposition: form-data; name=\"submit\"\r\n"+ , "\r\nSubmit\r\n" ]++ body kvps = L.concat $ prefix ++ concatMap part kvps ++ suffix+ where+ part (k,v) = [ "--"+ , boundary+ , "\r\ncontent-disposition: attachment; filename=\""+ , k+ , "\"\r\nContent-Type: text/plain\r\n\r\n"+ , v+ , "\r\n" ]++ suffix = [ "--", boundary, "--\r\n" ]++ hdrs = [ ("Content-type", S.concat $ [ "multipart/form-data; boundary=" ]+ ++ L.toChunks boundary) ]++ b16 (k,v) = (ne $ e k, e v)+ where+ ne s = if L.null s then "file" else s+ e s = L.fromChunks [ B16.encode $ S.concat $ L.toChunks s ]++ response kvps = L.concat $ [ "Param:\n"+ , "submit\n"+ , "Value:\n"+ , "Submit\n\n" ] ++ concatMap responseKVP kvps++ responseKVP (k,v) = [ "File:\n"+ , k+ , "\nValue:\n"+ , v+ , "\n\n" ]++ prop kvps' = do+ let kvps = sort $ map b16 kvps'++ let uri = S.pack $ concat [ if ssl then "https" else "http"+ , "://127.0.0.1:"+ , show port+ , "/upload/handle" ]++ let txt = response kvps+ doc0 <- QC.run+ $ HTTP.withConnection (HTTP.establishConnection uri)+ $ \conn -> do+ req <- HTTP.buildRequest $ do+ HTTP.http HTTP.POST uri+ mapM_ (uncurry HTTP.setHeader) hdrs++ HTTP.sendRequest conn req (Streams.write $ Just+ $ mconcat+ $ map byteString+ $ L.toChunks+ $ body kvps)+ HTTP.receiveResponse conn HTTP.concatHandler'++ let doc = L.fromChunks [doc0]+ when (txt /= doc) $ QC.run $ do+ L.putStrLn "expected:"+ L.putStrLn "----------------------------------------"+ L.putStrLn txt+ L.putStrLn "----------------------------------------"+ L.putStrLn "\ngot:"+ L.putStrLn "----------------------------------------"+ L.putStrLn doc+ L.putStrLn "----------------------------------------"++ QC.assert $ txt == doc+++------------------------------------------------------------------------------+testEcho :: Bool -> Int -> String -> Test+testEcho ssl port name =+ plusTestOptions (slowTestOptions ssl) $+ testProperty (name ++ "blackbox/echo") $+ QC.mapSize (if ssl then min 100 else min 300) $+ monadicIO $ forAllM arbitrary prop+ where+ prop txt = do+ let uri = (if ssl then "https" else "http")+ ++ "://127.0.0.1:" ++ show port ++ "/echo"++ doc <- QC.run $ HTTP.post (S.pack uri) "text/plain"+ (Streams.write (Just $ byteString txt))+ HTTP.concatHandler'+ QC.assert $ txt == doc+++------------------------------------------------------------------------------+testServerHeader :: Bool -> Int -> String -> Test+testServerHeader ssl port name =+ testCase (name ++ "blackbox/server-header") $ do+ let uri = (if ssl then "https" else "http")+ ++ "://127.0.0.1:" ++ show port ++ "/server-header"+ HTTP.get (S.pack uri) $ \resp _ -> do+ let serverHeader = HTTP.getHeader resp "server"+ assertEqual "server header" (Just "foo") serverHeader+++------------------------------------------------------------------------------+startTestServers :: IO ((ThreadId, Int, MVar ()),+ (ThreadId, Int, MVar ()),+ Maybe (ThreadId, Int, MVar ()))+startTestServers = do+ x <- startTestSocketServer NormalTest+ y <- startTestSocketServer ProxyTest+#ifdef OPENSSL+ z <- startTestSocketServer SSLTest+ return (x, y, Just z)+#else+ return (x, y, Nothing)+#endif
+ test/Test/Common/Rot13.hs view
@@ -0,0 +1,24 @@+module Test.Common.Rot13 (rot13) where++----------------------------------------------------------------------------+import Data.ByteString.Char8 (ByteString)+import qualified Data.ByteString.Char8 as S+import Data.Char( ord, isAsciiUpper, isAsciiLower, isAlpha, chr )+++------------------------------------------------------------------------------+rotone :: Char -> Char+rotone x | acc x = f+ | otherwise = x+ where+ aA = ord 'A'+ aa = ord 'a'+ xx = ord x+ f = g $ if isAsciiUpper x then aA else aa+ g st = chr $ st + (xx - st + 13) `mod` 26+ acc c = isAlpha c && (isAsciiUpper c || isAsciiLower c)+++----------------------------------------------------------------------------+rot13 :: ByteString -> ByteString+rot13 = S.map rotone
+ test/Test/Common/TestHandler.hs view
@@ -0,0 +1,193 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}++module Test.Common.TestHandler (testHandler) where++------------------------------------------------------------------------------+import Control.Concurrent (threadDelay)+import Control.Exception (throwIO)+import Control.Monad (liftM)+import Control.Monad.IO.Class (MonadIO (liftIO))+import Data.ByteString.Builder (Builder, byteString)+import Data.ByteString.Builder.Extra (flush)+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import Data.List (sort)+import qualified Data.Map as Map+import Data.Maybe (fromMaybe)+import Data.Monoid (Monoid (mappend, mconcat, mempty))+------------------------------------------------------------------------------+import Snap.Core (Request (rqParams, rqURI), Snap, getParam, getRequest, logError, modifyResponse, redirect, route, rqClientAddr, rqClientPort, setContentLength, setContentType, setHeader, setResponseBody, setResponseCode, setTimeout, transformRequestBody, writeBS, writeBuilder, writeLBS)+import Snap.Internal.Debug ()+import Snap.Util.FileServe (serveDirectory)+import Snap.Util.FileUploads (PartInfo (partContentType, partFileName), allowWithMaximumSize, defaultUploadPolicy, disallow, handleFileUploads)+import Snap.Util.GZip (noCompression, withCompression)+import System.Directory (createDirectoryIfMissing)+import System.IO.Streams (OutputStream)+import qualified System.IO.Streams as Streams+import Test.Common.Rot13 (rot13)+++------------------------------------------------------------------------------+-- timeout handling+------------------------------------------------------------------------------+timeoutTickleHandler :: Snap ()+timeoutTickleHandler = do+ noCompression -- FIXME: remove this when zlib-bindings and+ -- zlib-enumerator support gzip stream flushing+ modifyResponse $ setResponseBody (trickleOutput 10)+ . setContentType "text/plain"+ setTimeout 2+++badTimeoutTickleHandler :: Snap ()+badTimeoutTickleHandler = do+ noCompression -- FIXME: remove this when zlib-bindings and+ -- zlib-enumerator support gzip stream flushing+ modifyResponse $ setResponseBody (trickleOutput 10)+ . setContentType "text/plain"+ setTimeout 2+++trickleOutput :: Int -> OutputStream Builder -> IO (OutputStream Builder)+trickleOutput n os = do+ Streams.fromList dots >>= Streams.mapM f >>= Streams.supplyTo os+ return os+ where+ dots = replicate n ".\n"+ f x = threadDelay 1000000 >> return (byteString x `mappend` flush)+++------------------------------------------------------------------------------+pongHandler :: Snap ()+pongHandler = modifyResponse $+ setResponseBody body .+ setContentType "text/plain" .+ setContentLength 4+ where+ body os = do Streams.write (Just $ byteString "PONG") os+ return os++echoUriHandler :: Snap ()+echoUriHandler = do+ req <- getRequest+ writeBS $ rqURI req++echoHandler :: Snap ()+echoHandler = transformRequestBody return++rot13Handler :: Snap ()+rot13Handler = transformRequestBody (Streams.map rot13)++bigResponseHandler :: Snap ()+bigResponseHandler = do+ let sz = 4000000+ let s = L.take sz $ L.cycle $ L.fromChunks [S.replicate 400000 '.']+ modifyResponse $ setContentLength $ fromIntegral sz+ writeLBS s+++responseHandler :: Snap ()+responseHandler = do+ !code <- liftM (read . S.unpack . fromMaybe "503") $ getParam "code"+ modifyResponse $ setResponseCode code+ writeBS $ S.pack $ show code+++uploadForm :: Snap ()+uploadForm = do+ modifyResponse $ setContentType "text/html"+ writeBS form++ where+ form = S.concat [ "<html><head><title>Upload a file</title></head><body>\n"+ , "<p>Upload some <code>text/plain</code> files:</p>\n"+ , "<form method='post' "+ , "enctype='multipart/form-data' "+ , "action='/upload/handle'>\n"+ , "<input type='file' "+ , "accept='text/plain' "+ , "multiple='true' "+ , "name='file'></input>\n"+ , "<input type='submit' name='Submit'></input>\n"+ , "</form></body></html>" ]+++uploadHandler :: Snap ()+uploadHandler = do+ logError "uploadHandler"+ liftIO $ createDirectoryIfMissing True tmpdir+ files <- handleFileUploads tmpdir defaultUploadPolicy partPolicy hndl+ let m = sort files++ params <- liftM (Prelude.map (\(a,b) -> (a,S.concat b)) .+ Map.toAscList .+ rqParams) getRequest++ modifyResponse $ setContentType "text/plain"+ writeBuilder $ buildRqParams params `mappend` buildFiles m++ where+ f p = fromMaybe "-" $ partFileName p++ hndl _ (Left e) = throwIO e+ hndl partInfo (Right fp) = do+ !c <- liftIO $ S.readFile fp+ return $! (f partInfo, c)++ builder _ [] = mempty+ builder ty ((k,v):xs) =+ mconcat [ byteString ty+ , byteString ":\n"+ , byteString k+ , byteString "\nValue:\n"+ , byteString v+ , byteString "\n\n"+ , builder ty xs ]+++ buildRqParams = builder "Param"+ buildFiles = builder "File"++ tmpdir = "dist/filetmp"+ partPolicy partInfo = if partContentType partInfo == "text/plain"+ then allowWithMaximumSize 200000+ else disallow++serverHeaderHandler :: Snap ()+serverHeaderHandler = modifyResponse $ setHeader "Server" "foo"+++chunkedResponse :: Snap ()+chunkedResponse = writeBS "chunked"+++remoteAddrPort :: Snap ()+remoteAddrPort = do+ rq <- getRequest+ let addr = rqClientAddr rq+ let port = rqClientPort rq+ let out = S.concat [ addr, ":", S.pack (show port) ]+ modifyResponse $ setContentLength $ fromIntegral $ S.length out+ writeBS out+++testHandler :: Snap ()+testHandler = withCompression $+ route [ ("pong" , pongHandler )+ , ("redirect" , redirect "/pong" )+ , ("echo" , echoHandler )+ , ("rot13" , rot13Handler )+ , ("echoUri" , echoUriHandler )+ , ("remoteAddrPort" , remoteAddrPort )+ , ("fileserve" , noCompression >>+ serveDirectory "testserver/static")+ , ("bigresponse" , bigResponseHandler )+ , ("respcode/:code" , responseHandler )+ , ("upload/form" , uploadForm )+ , ("upload/handle" , uploadHandler )+ , ("timeout/tickle" , timeoutTickleHandler )+ , ("timeout/badtickle" , badTimeoutTickleHandler )+ , ("server-header" , serverHeaderHandler )+ , ("chunked" , chunkedResponse )+ ]
+ test/TestSuite.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main where++import Control.Concurrent (killThread, takeMVar)+import qualified Control.Exception as E+import Control.Monad (liftM)+import Data.Maybe (maybeToList)+#if !MIN_VERSION_network(2,7,0)+import Network (withSocketsDo)+#endif+import System.Environment+import Test.Framework (defaultMain, testGroup)+------------------------------------------------------------------------------+import qualified Snap.Internal.Http.Server.TLS as TLS+------------------------------------------------------------------------------+import qualified Snap.Internal.Http.Server.Address.Tests as Address+import qualified Snap.Internal.Http.Server.Parser.Tests as Parser+import qualified Snap.Internal.Http.Server.Session.Tests as Session+import qualified Snap.Internal.Http.Server.Socket.Tests as Socket+import qualified Snap.Internal.Http.Server.TimeoutManager.Tests as TimeoutManager+import Snap.Test.Common (eatException)+#ifdef HAS_SENDFILE+import qualified System.SendFile.Tests as SendFile+#endif+import qualified Test.Blackbox++#if MIN_VERSION_network(2,7,0)+withSocketsDo :: IO a -> IO a+withSocketsDo = id+#endif++------------------------------------------------------------------------------+main :: IO ()+main = withSocketsDo $ TLS.withTLS $ eatException $+ E.bracket (Test.Blackbox.startTestServers)+ cleanup+ (\tinfos -> do+ let blackboxTests = bbox tinfos+ defaultMain $ tests ++ blackboxTests+ )+ where+ cleanup (x, y, m) = do+ let backends = [x, y] ++ maybeToList m+ mapM_ (killThread . (\(a, _, _) -> a)) backends+ mapM_ (takeMVar . (\(_, _, a) -> a)) backends++ bbox ((_, port, _), (_, port2, _), m) =+ [ testGroup "Blackbox" $+ concat [ Test.Blackbox.tests port+ , Test.Blackbox.haTests port2+ , Test.Blackbox.ssltests $ fmap (\(_,x,_) -> x) m+ ]+ ]++ tests = [ testGroup "Address" Address.tests+ , testGroup "Parser" Parser.tests+#ifdef HAS_SENDFILE+ , testGroup "SendFile" SendFile.tests+#endif+ , testGroup "Server" Session.tests+ , testGroup "Socket" Socket.tests+ , testGroup "TimeoutManager" TimeoutManager.tests+ ]+++------------------------------------------------------------------------------+sslPort :: Int -> Maybe Int++#ifdef OPENSSL+sslPort sp = Just (sp + 100)+#else+sslPort _ = Nothing+#endif++ports :: Int -> (Int, Maybe Int)+ports sp = (sp, sslPort sp)+++getStartPort :: IO Int+getStartPort = (liftM read (getEnv "STARTPORT") >>= E.evaluate)+ `E.catch` \(_::E.SomeException) -> return 8111
+ test/bad_key.pem view
@@ -0,0 +1,15 @@+-----BEGIN RSA PRIVATE KEY-----+MIICXgIBAAKBgQDHFq5lSdMZ9yXCn/m/GPgBPq0WnKHZf0fje1CV08n5Acge28ze+lUdofKEWCbuw4RE7P8OKPwH/bzcLCQSVaL3G1ehQAG5eOUzA6tkGVbT8MEW4vEed+kG0SEVgcYHt2h3jFM9YVd9ojMxj1XuIykmjtinG1ThaYcHPFZgOfRr0oXwIDAQAB+AoGBAIr+p9UpfIvFRASkYd3sFdQXpwqBYnIR7ePBBVsFWR5TAx+gP2ErAYbOdDyJ+oRN1nu0psGBFaySlxd0bd6rETLFXMWbA0uDJcqASrlsOhsbhgPH7aExYfAi7eX8h+fAwD//j2E1sS6WvNWu0YANKR2yrM9R0vcbt0GF7hlmyV7lhRAkEA+6DCI6NfbdvR+jkvaxzOdC9jY/eBI9a4BbyjPLUSlTuQsGrp6s0Sj1LOQscItzqkPSutugM3f1dlG+lqq31/fnqQJBAMqMOknRBlOZY8DBfCorvNXAjIenoqlqE1D4yTL+tE5C3zEyvTcF+zPAaX220vf1OkL1bX4jKUxx8uXIqiYND9McCQQCWoWWWc9qMqUqJJF+TYBJjRSyg+zeLfL4ssQAHF15Id5/l/BqLtLenlKpkz0EobrJi7ALTl5lhYa/kVuJzVbFIBAkEA+shE17U9mUHi5yexQTILHMORmp5wo1Of8s2ME/2ANBACmV4pT7ttiXHPTEY+kt90q+Qk7iXlABYToFjuj2nABSYQJAO6W9P18mM2p6vkiBuNReW6VN/ftYqq5TLK3hXh2Q+0d5v0eW9ce7CiQueH5kxq44EVVTIDiVLe2pk+BQIntMC8w==+-----END RSA PRIVATE KEY-----
− test/benchmark/Benchmark.hs
@@ -1,7 +0,0 @@-module Main where--import Criterion.Main-import qualified Snap.Internal.Http.Parser.Benchmark as PB--main :: IO ()-main = defaultMain [ PB.benchmarks ]
− test/benchmark/Snap/Internal/Http/Parser/Benchmark.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE PackageImports #-}--module Snap.Internal.Http.Parser.Benchmark- ( benchmarks )- where--import qualified Control.Exception as E-import "monads-fd" Control.Monad.Identity-import Criterion.Main hiding (run)-import Data.Attoparsec hiding (Result(..))-import Data.ByteString (ByteString)-import qualified Data.ByteString as S-import qualified Data.ByteString.Lazy.Char8 as L-import Snap.Internal.Http.Parser-import Snap.Internal.Http.Parser.Data-import qualified Snap.Iteratee as SI-import Snap.Iteratee hiding (take)--parseGet :: IO ()-parseGet = do- step <- runIteratee parseRequest- run_ $ enumBS parseGetData step- return ()---parseChunked :: IO ()-parseChunked = do- sstep <- runIteratee stream2stream- c <- toChunked parseChunkedData- cstep <- runIteratee $ readChunkedTransferEncoding sstep- let i = enumBS c cstep- f <- run_ i- return ()---- utils-toChunked :: L.ByteString -> IO ByteString-toChunked lbs = do- sstep <- runIteratee stream2stream- cstep <- runIteratee $ joinI $ writeChunkedTransferEncoding sstep- run_ $ enumLBS lbs cstep--benchmarks = bgroup "parser"- [ bench "firefoxget" $ whnfIO parseGet- , bench "readChunkedTransferEncoding" $ whnfIO parseChunked ]---stream2stream :: (Monad m) => Iteratee ByteString m ByteString -stream2stream = liftM S.concat consume
− test/benchmark/Snap/Internal/Http/Parser/Data.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Snap.Internal.Http.Parser.Data - ( parseGetData- , parseChunkedData- )- where--import Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as S-import qualified Data.ByteString.Lazy.Char8 as L-parseGetData = S.concat - [ "GET /favicon.ico HTTP/1.1\r\n"- , "Host: 0.0.0.0=5000\r\n"- , "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"- , "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"- , "Accept-Language: en-us,en;q=0.5\r\n"- , "Accept-Encoding: gzip,deflate\r\n"- , "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"- , "Keep-Alive: 300\r\n"- , "Connection: keep-alive\r\n"- , "\r\n" ]--parseChunkedData = L.fromChunks ["In the beginning, everything was void, and J.H.W.H. Conway began to create numbers.", "Conway said, \"Let there be two rules which bring forth all numbers larege and small.", "This shall be the first rule: Every number corresponds to two sets of previously created numbers, such that no member of the left set is greater than or equal to any member of the right set.", "And the second rule shall be this: One number is less than or equal to another number if and only if no member of the first number \'s left set is greater than or equal to the second number, and no member of the second number\'s right set is less than or equal to the first number.\" And Conway examined these two rules he had made, and behold! They were very good.", "And the first number was created from the void left set and the void right set. Conway called this number \"zero,\" and said that it shall be a sign to separate positive numbers from negative numbers.", "Conway proved that zero was less than or equal to zero, end he saw that it was good.", "And the evening and the morning were the day of zero.", "On the next day, two more numbers were created, one with zero as its left set and one with zero as its right set. And Conway called the former number \"one,\" and the latter he called \"minus one.\" And he proved that minus one is less than but not equal to zero and zero is less than but not equal to one.", "And the evening day.", "And Conway said, \"Let the numbers be added to each other in this wise: The left set of the sum of two numbers shall be the sums of all left parts of each number with the other; and in like manner the right set shall be from the right parts, each according to its kind.\" Conway proved that every number plus zero is unchanged, and he saw that addition was good.", "And the evening and the morning were the third day."]
+ test/cbits/errno_util.c view
@@ -0,0 +1,5 @@+#include <errno.h>++void set_errno(int e) {+ errno = e;+}
+ test/cert.pem view
@@ -0,0 +1,14 @@+-----BEGIN CERTIFICATE-----+MIICOzCCAaQCCQChUcwtek3F7DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJD+SDEPMA0GA1UECAwGWnVyaWNoMQ8wDQYDVQQHDAZadXJpY2gxFzAVBgNVBAoMDlNu+YXAgRnJhbWV3b3JrMRgwFgYDVQQDDA9HcmVnb3J5IENvbGxpbnMwHhcNMTAxMjEx+MTk1MjA0WhcNMzgwNDI3MTk1MjA0WjBiMQswCQYDVQQGEwJDSDEPMA0GA1UECAwG+WnVyaWNoMQ8wDQYDVQQHDAZadXJpY2gxFzAVBgNVBAoMDlNuYXAgRnJhbWV3b3Jr+MRgwFgYDVQQDDA9HcmVnb3J5IENvbGxpbnMwgZ8wDQYJKoZIhvcNAQEBBQADgY0A+MIGJAoGBAMcWrmVJ0xn3JcKf+b8Y+Bs+rRacodl/R+N7UJXTyfkByB7bzN6VR2h8+oRYJu7DhETs/w4o/Af9vNwsJBJVovcbV6FAAbl45TMDq2QZVtPwwTDi8R52QbRIR+WBxge3aHeMUz1hV32iMzGPVe4jKSaO2KcbVOFphwc8VmA59GvShfAgMBAAEwDQYJ+KoZIhvcNAQEFBQADgYEAXsRchaVlL4RP5V+r1npL7n4W3Ge2O7F+fQ2dX6tNyqeo+tMAdc6wYahg3m+PejWASVCh0vVEjBx2WYOMRPsmk/DYLUi4UwZYPrvZtbfSbMrD++mYmZhqCDM4316qAg5OwcTON3+VZXMwbXCVM+vUCvZIw4xh6ywNjvuQjCzy7oKMg=+-----END CERTIFICATE-----
− test/common/Paths_snap_server.hs
@@ -1,9 +0,0 @@-module Paths_snap_server (- version- ) where--import Data.Version (Version(..))--version :: Version-version = Version {versionBranch = [0,0,0], versionTags = ["unknown"]}-
− test/common/Snap/Test/Common.hs
@@ -1,88 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}--{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}---module Snap.Test.Common where--import Control.Exception (SomeException)-import Control.Monad-import Control.Monad.CatchIO-import Data.ByteString (ByteString)-import qualified Data.ByteString as S-import qualified Data.ByteString.Lazy as L-import Data.ByteString.Internal (c2w)-import qualified Data.DList as D-import Network.Socket-import qualified Network.Socket.ByteString as N-import Prelude hiding (catch)-import Test.QuickCheck-import System.Timeout--import Snap.Internal.Iteratee.Debug ()---instance Arbitrary S.ByteString where- arbitrary = liftM (S.pack . map c2w) arbitrary--instance Arbitrary L.ByteString where- arbitrary = do- n <- choose(0,5)- chunks <- replicateM n arbitrary- return $ L.fromChunks chunks----expectExceptionBeforeTimeout :: IO a -- ^ action to run- -> Int -- ^ number of seconds to expect- -- exception by- -> IO Bool-expectExceptionBeforeTimeout act nsecs = do- x <- timeout (nsecs * (10::Int)^(6::Int)) f- case x of- Nothing -> return False- (Just y) -> return y-- where- f = (act >> return False) `catch` \(e::SomeException) -> do- if show e == "<<timeout>>"- then return False- else return True- --withSock :: Int -> (Socket -> IO a) -> IO a-withSock port go = do- addr <- liftM (addrAddress . Prelude.head) $- getAddrInfo (Just myHints)- (Just "127.0.0.1")- (Just $ show port)-- sock <- socket AF_INET Stream defaultProtocol- connect sock addr-- go sock `finally` sClose sock-- where- myHints = defaultHints { addrFlags = [ AI_NUMERICHOST ] }---recvAll :: Socket -> IO ByteString-recvAll sock = do- d <- f D.empty sock- return $ S.concat $ D.toList d-- where- f d sk = do- s <- N.recv sk 100000- if S.null s- then return d- else f (D.snoc d s) sk---ditchHeaders :: [ByteString] -> [ByteString]-ditchHeaders ("":xs) = xs-ditchHeaders ("\r":xs) = xs-ditchHeaders (_:xs) = ditchHeaders xs-ditchHeaders [] = []-
− test/common/Test/Common/Rot13.hs
@@ -1,19 +0,0 @@-module Test.Common.Rot13 (rot13) where--import Data.ByteString.Char8 (ByteString)-import qualified Data.ByteString.Char8 as S-import Data.Char--rotone :: Char -> Char-rotone x | acc x = f- | otherwise = x- where- aA = ord 'A'- aa = ord 'a'- xx = ord x- f = g $ if isAsciiUpper x then aA else aa- g st = chr $ st + (xx - st + 13) `mod` 26- acc c = isAlpha c && (isAsciiUpper c || isAsciiLower c)--rot13 :: ByteString -> ByteString-rot13 = S.map rotone
− test/common/Test/Common/TestHandler.hs
@@ -1,75 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE OverloadedStrings #-}--module Test.Common.TestHandler (testHandler) where---import Control.Monad-import Control.Monad.Trans--import qualified Data.ByteString.Char8 as S-import qualified Data.ByteString.Lazy.Char8 as L-import Data.Maybe--import Snap.Iteratee hiding (Enumerator)-import qualified Snap.Iteratee as I-import Snap.Types-import Snap.Util.FileServe-import Snap.Util.GZip-import Test.Common.Rot13 (rot13)---pongHandler :: Snap ()-pongHandler = modifyResponse $ setResponseBody (enumBS "PONG") .- setContentType "text/plain" .- setContentLength 4--echoUriHandler :: Snap ()-echoUriHandler = do- req <- getRequest- writeBS $ rqURI req---echoHandler :: Snap ()-echoHandler = transformRequestBody returnI---rot13Handler :: Snap ()-rot13Handler = transformRequestBody f- where- f origStep = do- mbX <- I.head- maybe (enumEOF origStep)- (feedStep origStep)- mbX-- feedStep origStep x = do- step <- lift $ runIteratee $ enumBS (rot13 x) origStep- f step---bigResponseHandler :: Snap ()-bigResponseHandler = do- let sz = 4000000- let s = L.take sz $ L.cycle $ L.fromChunks [S.replicate 400000 '.']- modifyResponse $ setContentLength sz- writeLBS s---responseHandler :: Snap ()-responseHandler = do- !code <- liftM (read . S.unpack . fromMaybe "503") $ getParam "code"- modifyResponse $ setResponseCode code- writeBS $ S.pack $ show code---testHandler :: Snap ()-testHandler = withCompression $- route [ ("pong" , pongHandler )- , ("echo" , echoHandler )- , ("rot13" , rot13Handler )- , ("echoUri" , echoUriHandler )- , ("fileserve" , fileServe "testserver/static")- , ("bigresponse" , bigResponseHandler )- , ("respcode/:code" , responseHandler )- ]
− test/data/fileServe/foo.bin
@@ -1,1 +0,0 @@-FOO
− test/data/fileServe/foo.bin.bin.bin
@@ -1,1 +0,0 @@-FOO
− test/data/fileServe/foo.html
@@ -1,1 +0,0 @@-FOO
− test/data/fileServe/foo.txt
@@ -1,1 +0,0 @@-FOO
+ test/dummy.txt view
@@ -0,0 +1,1 @@+TESTING 1-2-3
+ test/key.pem view
@@ -0,0 +1,15 @@+-----BEGIN RSA PRIVATE KEY-----+MIICXgIBAAKBgQDHFq5lSdMZ9yXCn/m/GPgbPq0WnKHZf0fje1CV08n5Acge28ze+lUdofKEWCbuw4RE7P8OKPwH/bzcLCQSVaL3G1ehQAG5eOUzA6tkGVbT8MEw4vEed+kG0SEVgcYHt2h3jFM9YVd9ojMxj1XuIykmjtinG1ThaYcHPFZgOfRr0oXwIDAQAB+AoGBAIr+p9UpfIvFRASkYd3sFdQXpwqBYnIR7ePBBVsFWR5TAx+gP2ErAYbOdDyJ+oRN1nu0psGBFaySlxd0bd6rETLFXMWbA0uDJcqASrlsOhsbhgPH7aExYfAi7eX8h+FAwD//j2E1sS6WvNWu0YANKR2yrM9R0vcbt0GF7hlmyV7lhRAkEA+6DCI6nfbdvR+jkvaxzOdC9jY/eBI9a4BbyjPLUSlTuQsGrp6s0Sj1LOQscItzqkPSutugM3f1dlG+lqq31/fnqQJBAMqMOknRBlOZY8DBfCorvNXAjIenoqlqE1D4yTL+tE5C3zEyvTcF+jPAaX220vf1OkL1bX4jKUxx8uXIqiYND9McCQQCWoWWWc9qMqUqJJF+TYBJjRSyg+zeLfL4ssQAHF15Id5/l/BqLtLenlKpkz0EobrJi7ALTl5lhYa/kVuJzVbFIBAkEA+shE17U9mUHi5yexQTILHMORmp5wo1Of8s2ME/2ANBACmV4pT7ttiXHPTEY+kt90q+Qk7iXlABYToFjuj2nABSYQJAO6W9P18mM2p6vkiBuNReW6VN/ftYqq5TLK3hXh2Q+0d5v0eW9ce7CiQueH5kxq44EVVTIDiVLe2pk+BQIntMC8w==+-----END RSA PRIVATE KEY-----
− test/pongserver/Main.hs
@@ -1,32 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module Main where--import Control.Concurrent-import Control.Exception (finally)--import Snap.Iteratee-import Snap.Types-import Snap.Http.Server---- FIXME: need better primitives for output-pongServer :: Snap ()-pongServer = modifyResponse $ setResponseBody (enumBS "PONG") .- setContentType "text/plain" .- setContentLength 4---main :: IO ()-main = do- m <- newEmptyMVar-- forkIO $ go m- takeMVar m-- return ()-- where- go m = httpServe config pongServer `finally` putMVar m ()- config = addListen (ListenHttp "*" 8000) $- setErrorLog Nothing $- setAccessLog Nothing $- setCompression False $ emptyConfig
− test/runTestsAndCoverage.sh
@@ -1,58 +0,0 @@-#!/bin/sh--set -e--if [ -z "$DEBUG" ]; then- export DEBUG=testsuite-fi--SUITE=./dist/build/testsuite/testsuite--rm -f *.tix--if [ ! -f $SUITE ]; then- cat <<EOF-Testsuite executable not found, please run:- cabal configure -ftest-then- cabal build-EOF- exit;-fi--./dist/build/testsuite/testsuite -j4 -a1000 $*--DIR=dist/hpc--rm -Rf $DIR-mkdir -p $DIR--EXCLUDES='Main-Data.CIByteString-Data.Concurrent.HashMap.Internal-Data.Concurrent.HashMap.Tests-Paths_snap_server-Snap.Internal.Http.Parser.Tests-Snap.Internal.Http.Server.Tests-Snap.Internal.Http.Types.Tests-Snap.Internal.Iteratee.Tests-Text.Snap.Templates.Tests-Snap.Test.Common-Test.Blackbox-Test.Common.Rot13-Test.Common.TestHandler'--EXCL=""--for m in $EXCLUDES; do- EXCL="$EXCL --exclude=$m"-done--hpc markup $EXCL --destdir=$DIR testsuite >/dev/null 2>&1--rm -f testsuite.tix--cat <<EOF--Test coverage report written to $DIR.-EOF
− test/snap-server-testsuite.cabal
@@ -1,223 +0,0 @@-name: snap-server-testsuite-version: 0.1.1-build-type: Simple-cabal-version: >= 1.6--Flag libev- Description: Use libev?- Default: False--Flag portable- Description: Compile in cross-platform mode. No platform-specific code or- optimizations such as C routines will be used.- Default: False--Flag gnutls- Description: Enable https support using the libgnutls library.- Default: False--Executable testsuite- hs-source-dirs: suite common ../src- main-is: TestSuite.hs-- build-depends:- QuickCheck >= 2,- array >= 0.3 && <0.4,- attoparsec >= 0.8.1 && < 0.9,- attoparsec-enumerator >= 0.2.0.1 && < 0.3,- base >= 4 && < 5,- binary >= 0.5 && < 0.6,- bytestring,- bytestring-nums >= 0.3.1 && < 0.4,- bytestring-show >= 0.3.2 && < 0.4,- containers,- directory,- directory-tree,- dlist >= 0.5 && < 0.6,- enumerator == 0.4.*,- filepath,- haskell98,- http-enumerator >= 0.2.1.5 && <0.3,- HUnit >= 1.2 && < 2,- monads-fd >= 0.1.0.4 && <0.2,- murmur-hash >= 0.1 && < 0.2,- network == 2.3.*,- old-locale,- parallel > 2,- process,- snap-core >= 0.3 && <0.4,- template-haskell,- test-framework >= 0.3.1 && <0.4,- test-framework-hunit >= 0.2.5 && < 0.3,- test-framework-quickcheck2 >= 0.2.6 && < 0.3,- time,- transformers,- utf8-string >= 0.3.6 && <0.4,- vector >= 0.7 && <0.8,- vector-algorithms >= 0.4 && <0.5,- PSQueue >= 1.1 && <1.2-- if !os(windows)- build-depends: unix-- if flag(libev)- build-depends: hlibev >= 0.2.5 && < 0.3- cpp-options: -DLIBEV-- if flag(gnutls)- extra-libraries: gnutls- cpp-options: -DGNUTLS- c-sources: ../src/Snap/Internal/Http/Server/gnutls_helpers.c-- if flag(portable) || os(windows)- cpp-options: -DPORTABLE-- ghc-options: -O2 -Wall -fhpc -fwarn-tabs- -funbox-strict-fields -threaded- -fno-warn-unused-do-bind---Executable pongserver- hs-source-dirs: pongserver common ../src- main-is: Main.hs-- build-depends:- QuickCheck >= 2,- array >= 0.3 && <0.4,- attoparsec >= 0.8.1 && < 0.9,- attoparsec-enumerator >= 0.2.0.1 && < 0.3,- base >= 4 && < 5,- bytestring,- bytestring-nums >= 0.3.1 && < 0.4,- bytestring-show >= 0.3.2 && < 0.4,- cereal >= 0.3 && < 0.4,- containers,- directory-tree,- dlist >= 0.5 && < 0.6,- enumerator == 0.4.*,- filepath,- haskell98,- HUnit >= 1.2 && < 2,- monads-fd >= 0.1.0.4 && <0.2,- old-locale,- parallel > 2,- MonadCatchIO-transformers >= 0.2.1 && < 0.3,- murmur-hash >= 0.1 && < 0.2,- network == 2.3.*,- snap-core >= 0.3 && <0.4,- template-haskell,- time,- transformers,- unix-compat == 0.2.*,- utf8-string >= 0.3.6 && <0.4,- vector >= 0.7 && <0.8,- vector-algorithms >= 0.4 && <0.5,- PSQueue >= 1.1 && <1.2-- if flag(portable) || os(windows)- cpp-options: -DPORTABLE- else- build-depends: unix-- if flag(libev)- build-depends: hlibev >= 0.2.5 && < 0.3- cpp-options: -DLIBEV-- if flag(gnutls)- extra-libraries: gnutls- cpp-options: -DGNUTLS- c-sources: ../src/Snap/Internal/Http/Server/gnutls_helpers.c-- if os(linux) && !flag(portable)- cpp-options: -DLINUX -DHAS_SENDFILE- other-modules:- System.SendFile,- System.SendFile.Linux-- if os(darwin) && !flag(portable)- cpp-options: -DOSX -DHAS_SENDFILE- other-modules:- System.SendFile,- System.SendFile.Darwin-- if os(freebsd) && !flag(portable)- cpp-options: -DFREEBSD -DHAS_SENDFILE- other-modules:- System.SendFile,- System.SendFile.FreeBSD-- if flag(portable) || os(windows)- cpp-options: -DPORTABLE-- ghc-options: -Wall -O2 -fwarn-tabs -funbox-strict-fields -threaded- -fno-warn-unused-do-bind- ghc-prof-options: -prof -auto-all---Executable testserver- hs-source-dirs: testserver common ../src- main-is: Main.hs-- build-depends:- QuickCheck >= 2,- array >= 0.3 && <0.4,- attoparsec >= 0.8.1 && < 0.9,- attoparsec-enumerator >= 0.2.0.1 && < 0.3,- base >= 4 && < 5,- binary >= 0.5 && < 0.6,- bytestring,- bytestring-nums >= 0.3.1 && < 0.4,- bytestring-show >= 0.3.2 && < 0.4,- containers,- directory-tree,- dlist >= 0.5 && < 0.6,- enumerator == 0.4.*,- filepath,- haskell98,- HUnit >= 1.2 && < 2,- MonadCatchIO-transformers >= 0.2.1 && < 0.3,- monads-fd >= 0.1.0.4 && <0.2,- murmur-hash >= 0.1 && < 0.2,- network == 2.3.*,- old-locale,- parallel > 2,- snap-core >= 0.3 && <0.4,- template-haskell,- test-framework >= 0.3.1 && <0.4,- test-framework-hunit >= 0.2.5 && < 0.3,- test-framework-quickcheck2 >= 0.2.6 && < 0.3,- time,- transformers,- utf8-string >= 0.3.6 && <0.4,- vector >= 0.7 && <0.8,- vector-algorithms >= 0.4 && <0.5,- PSQueue >= 1.1 && <1.2-- if !os(windows)- build-depends: unix-- if flag(libev)- build-depends: hlibev >= 0.2.5 && < 0.3- cpp-options: -DLIBEV-- if flag(gnutls)- extra-libraries: gnutls- cpp-options: -DGNUTLS- c-sources: ../src/Snap/Internal/Http/Server/gnutls_helpers.c-- if flag(portable) || os(windows)- cpp-options: -DPORTABLE-- ghc-options: -O2 -Wall -fwarn-tabs- -funbox-strict-fields -threaded- -fno-warn-unused-do-bind---Executable benchmark- hs-source-dirs: benchmark common ../src- main-is: Benchmark.hs- build-depends:- base >= 4 && < 5,- network == 2.3.*,- http-enumerator >= 0.2.1.3 && <0.3,- criterion >= 0.5 && <0.6
− test/suite/Data/Concurrent/HashMap/Tests.hs
@@ -1,121 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE PackageImports #-}--module Data.Concurrent.HashMap.Tests- ( tests ) where--import Data.ByteString.Char8 (ByteString)-import Data.List-import Data.Word-import Test.Framework-import Test.Framework.Providers.QuickCheck2-import Test.QuickCheck-import Test.QuickCheck.Monadic--import qualified Data.Concurrent.HashMap as H-import Snap.Test.Common ()--tests :: [Test]-tests = [ testFromTo- , testLookup- , testDeletes- , testUpdate- ]----- make sure we generate two strings which hash to the same bucket.-bogoHash :: ByteString -> Word-bogoHash "qqq" = 12345-bogoHash "zzz" = 12345-bogoHash x = H.hashBS x---testFromTo :: Test-testFromTo = testProperty "HashMap/fromList/toList" $- monadicIO $ forAllM arbitrary prop- where- prop :: [(Int,Int)] -> PropertyM IO ()- prop l = do- ht <- run $ H.fromList H.hashInt l- l' <- run $ H.toList ht-- let s1 = sort l- let s2 = sort l'-- assert $ s1 == s2---testDeletes :: Test-testDeletes = testProperty "HashMap/deletes" $- monadicIO $ forAllM arbitrary prop- where- prop :: [(ByteString,ByteString)] -> PropertyM IO ()- prop l' = do- pre (not $ null l')- let l = [("qqq","QQQ"),("zzz","ZZZ")] ++ l'- let h = head l'-- ht <- run $ H.fromList bogoHash l- v1 <- run $ H.lookup "qqq" ht- v2 <- run $ H.lookup "zzz" ht-- run $ H.delete "qqq" ht- v3 <- run $ H.lookup "qqq" ht- v4 <- run $ H.lookup "zzz" ht-- run $ H.delete (fst h) ht- run $ H.delete (fst h) ht-- v5 <- run $ H.lookup (fst h) ht-- assert $ v1 == Just "QQQ"- assert $ v2 == Just "ZZZ"- assert $ v3 == Nothing- assert $ v4 == Just "ZZZ"- assert $ v5 == Nothing---testLookup :: Test-testLookup = testProperty "HashMap/lookup" $- monadicIO $ forAllM arbitrary prop- where- prop :: [(ByteString,ByteString)] -> PropertyM IO ()- prop l' = do- pre (not $ null l')- let h = head l'- let l = filter ((/= (fst h)) . fst) $ tail l'-- ht <- run $ H.fromList H.hashBS (h:l)-- v1 <- run $ H.lookup (fst h) ht- run $ H.delete (fst h) ht- v2 <- run $ H.lookup (fst h) ht-- assert $ v1 == (Just $ snd h)- assert $ v2 == Nothing---testUpdate :: Test-testUpdate = testProperty "HashMap/update" $- monadicIO $ forAllM arbitrary prop- where- prop :: [(ByteString,ByteString)] -> PropertyM IO ()- prop l' = do- pre (not $ null l')- let h = head l'- let l = filter ((/= (fst h)) . fst) $ tail l'-- ht <- run $ H.fromList H.hashBS (h:l)- e1 <- run $ H.update (fst h) "qqq" ht- v1 <- run $ H.lookup (fst h) ht- run $ H.delete (fst h) ht- v2 <- run $ H.lookup (fst h) ht- e2 <- run $ H.update (fst h) "zzz" ht- v3 <- run $ H.lookup (fst h) ht-- assert e1- assert $ v1 == Just "qqq"- assert $ v2 == Nothing- assert $ not e2- assert $ v3 == Just "zzz"
− test/suite/Snap/Internal/Http/Parser/Tests.hs
@@ -1,280 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Snap.Internal.Http.Parser.Tests- ( tests ) where--import qualified Control.Exception as E-import Control.Exception hiding (try, assert)-import Control.Monad-import Control.Parallel.Strategies-import Data.Attoparsec hiding (Result(..))-import Data.ByteString (ByteString)-import qualified Data.ByteString as S-import qualified Data.ByteString.Lazy as L-import Data.ByteString.Internal (c2w)-import Data.List-import qualified Data.Map as Map-import Data.Maybe (isNothing)-import Data.Monoid-import Test.Framework-import Test.Framework.Providers.HUnit-import Test.Framework.Providers.QuickCheck2-import Test.QuickCheck-import qualified Test.QuickCheck.Monadic as QC-import Test.QuickCheck.Monadic hiding (run, assert)-import Test.HUnit hiding (Test, path)-import Text.Printf--import Snap.Internal.Http.Parser-import Snap.Internal.Http.Types-import Snap.Internal.Debug-import Snap.Iteratee hiding (map, sequence)-import qualified Snap.Iteratee as I-import Snap.Test.Common()---tests :: [Test]-tests = [ testShow- , testCookie- , testChunked- , testBothChunked- , testBothChunkedPipelined- , testBothChunkedEmpty- , testP2I- , testNull- , testPartial- , testParseError- , testFormEncoded ]---emptyParser :: Parser ByteString-emptyParser = option "foo" $ string "bar"--testShow :: Test-testShow = testCase "parser/show" $ do- let i = IRequest GET "/" (1,1) []- let !b = show i `using` rdeepseq- return $ b `seq` ()---testP2I :: Test-testP2I = testCase "parser/iterParser" $ do- i <- liftM (enumBS "z") $ runIteratee (iterParser emptyParser)- l <- run_ i-- assertEqual "should be foo" "foo" l---forceErr :: SomeException -> IO ()-forceErr e = f `seq` (return ())- where- !f = show e---testNull :: Test-testNull = testCase "parser/shortParse" $ do- f <- run_ (parseRequest)- assertBool "should be Nothing" $ isNothing f---testPartial :: Test-testPartial = testCase "parser/partial" $ do- i <- liftM (enumBS "GET / ") $ runIteratee parseRequest- f <- E.try $ run_ i-- case f of (Left e) -> forceErr e- (Right x) -> assertFailure $ "expected exception, got " ++ show x---testParseError :: Test-testParseError = testCase "parser/error" $ do- step <- runIteratee parseRequest- let i = enumBS "ZZZZZZZZZZ" step- f <- E.try $ run_ i-- case f of (Left e) -> forceErr e- (Right x) -> assertFailure $ "expected exception, got " ++ show x----- | convert a bytestring to chunked transfer encoding-transferEncodingChunked :: L.ByteString -> L.ByteString-transferEncodingChunked = f . L.toChunks- where- toChunk s = L.concat [ len, "\r\n", L.fromChunks [s], "\r\n" ]- where- len = L.pack $ map c2w $ printf "%x" $ S.length s-- f l = L.concat $ (map toChunk l ++ ["0\r\n\r\n"])----- | ensure that running the 'readChunkedTransferEncoding' iteratee against--- 'transferEncodingChunked' returns the original string-testChunked :: Test-testChunked = testProperty "parser/chunkedTransferEncoding" $- monadicIO $ forAllM arbitrary prop_chunked- where- prop_chunked s = do- QC.run $ debug "=============================="- QC.run $ debug $ "input is " ++ show s- QC.run $ debug $ "chunked is " ++ show chunked- QC.run $ debug "------------------------------"- sstep <- QC.run $ runIteratee $ stream2stream- step <- QC.run $ runIteratee $- joinI $ readChunkedTransferEncoding sstep-- out <- QC.run $ run_ $ enum step-- QC.assert $ s == out- QC.run $ debug "==============================\n"-- where- chunked = (transferEncodingChunked s)- enum = enumLBS chunked---testBothChunked :: Test-testBothChunked = testProperty "parser/invertChunked" $- monadicIO $ forAllM arbitrary prop- where- prop s = do- sstep <- QC.run $ runIteratee stream2stream- let it = joinI $ writeChunkedTransferEncoding sstep-- bs <- QC.run $ runIteratee it >>= run_ . enumLBS s-- let enum = enumLBS bs-- x <- QC.run $- runIteratee (joinI $ readChunkedTransferEncoding sstep) >>=- run_ . enum-- QC.assert $ s == x----testBothChunkedPipelined :: Test-testBothChunkedPipelined = testProperty "parser/testBothChunkedPipelined" $- monadicIO prop- where- prop = do- sz <- QC.pick (choose (1000,4000))- s' <- QC.pick $ resize sz arbitrary- ntimes <- QC.pick (choose (4,7))- --let s' = L.take 2000 $ L.fromChunks $ repeat s-- let e = enumLBS s'- let n = fromEnum $ L.length s'-- let enum = foldl' (>==>) (enumBS "") (replicate ntimes e)-- bufi <- QC.run $- unsafeBufferIteratee copyingStream2Stream >>= runIteratee-- iter' <- QC.run $ runIteratee $ joinI $- writeChunkedTransferEncoding bufi- let iter = I.joinI $ I.take n iter'-- let iters = replicate ntimes iter- let mothra = foldM (\s it -> it >>= \t -> return $ s `mappend` t)- mempty- iters-- bs <- QC.run $ runIteratee mothra >>= run_ . enum-- let e2 = enumBS bs-- let pcrlf = \s -> iterParser $ string "\r\n" >> return s-- sstep <- QC.run $ runIteratee stream2stream-- let iters' = replicate ntimes $ joinI $- readChunkedTransferEncoding sstep- let godzilla = sequence $ map (>>= pcrlf) iters'-- x <- QC.run $ runIteratee godzilla >>= run_ . e2-- QC.assert $- x == (replicate ntimes s')----testBothChunkedEmpty :: Test-testBothChunkedEmpty = testCase "parser/testBothChunkedEmpty" prop- where- prop = do- let s' = ""- let e = enumLBS s'- let n = fromEnum $ L.length s'-- let ntimes = 5- let enum = foldl' (>==>) (enumBS "") (replicate ntimes e)-- sstep <- runIteratee stream2stream-- step <- runIteratee $- joinI $- writeChunkedTransferEncoding sstep- iter <- liftM returnI $ runIteratee $ joinI $ I.take n step-- let iters = replicate ntimes (iter :: Iteratee ByteString IO L.ByteString)- let mothra = foldM (\s it -> it >>= \t -> return $ s `mappend` t)- mempty- iters-- mothraStep <- runIteratee mothra- bs <- run_ $ enum mothraStep-- let e2 = enumLBS bs-- let pcrlf = \s -> iterParser $ string "\r\n" >> return s-- let iters' = replicate ntimes $ joinI $- readChunkedTransferEncoding sstep- godzilla <- runIteratee $ sequence $ map (>>= pcrlf) iters'-- x <- run_ $ e2 godzilla-- assertBool "empty chunked transfer" $- x == (replicate ntimes s')---testCookie :: Test-testCookie =- testCase "parser/parseCookie" $ do- assertEqual "cookie parsing" (Just [cv]) cv2-- where- cv = Cookie nm v Nothing Nothing Nothing- cv2 = parseCookie ct-- nm = "foo"- v = "bar"-- ct = S.concat [ nm- , "="- , v ]---testFormEncoded :: Test-testFormEncoded = testCase "parser/formEncoded" $ do- let bs = "foo1=bar1&foo2=bar2+baz2&foo3=foo%20bar"- let mp = parseUrlEncoded bs-- assertEqual "foo1" (Just ["bar1"] ) $ Map.lookup "foo1" mp- assertEqual "foo2" (Just ["bar2 baz2"]) $ Map.lookup "foo2" mp- assertEqual "foo3" (Just ["foo bar"] ) $ Map.lookup "foo3" mp---copyingStream2Stream :: (Monad m) => Iteratee ByteString m ByteString-copyingStream2Stream = go []- where- go l = do- mbx <- I.head- maybe (return $ S.concat $ reverse l)- (\x -> let !z = S.copy x in go (z:l))- mbx--stream2stream :: (Monad m) => Iteratee ByteString m L.ByteString-stream2stream = liftM L.fromChunks consume
− test/suite/Snap/Internal/Http/Server/Tests.hs
@@ -1,897 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE DeriveDataTypeable #-}--module Snap.Internal.Http.Server.Tests- ( tests ) where--import Control.Concurrent-import Control.Exception ( catch- , try- , throwIO- , bracket- , finally- , SomeException- , Exception )-import Control.Monad-import "monads-fd" Control.Monad.Trans-import qualified Data.ByteString.Char8 as S-import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString.Lazy.Char8 as LC-import Data.ByteString (ByteString)-import Data.ByteString.Internal (c2w)-import Data.Char-import Data.Int-import Data.IORef-import qualified Data.Map as Map-import Data.Maybe (fromJust)-import Data.Time.Calendar-import Data.Time.Clock-import Data.Typeable-import qualified Network.HTTP.Enumerator as HTTP-import qualified Network.Socket.ByteString as N-import Prelude hiding (catch, take)-import qualified Prelude-import System.Timeout-import Test.Framework-import Test.Framework.Providers.HUnit-import Test.HUnit hiding (Test, path)--import qualified Snap.Http.Server as Svr--import Snap.Internal.Debug-import Snap.Internal.Http.Types-import Snap.Internal.Http.Server-import qualified Snap.Iteratee as I-import Snap.Iteratee hiding (map)-import Snap.Internal.Http.Server.Backend-import Snap.Test.Common-import Snap.Types--data TestException = TestException- deriving (Show, Typeable)-instance Exception TestException---tests :: [Test]-tests = [ testHttpRequest1- , testMultiRequest- , testHttpRequest2- , testHttpRequest3- , testHttpRequest3'- , testHttpResponse1- , testHttpResponse2- , testHttpResponse3- , testHttpResponse4- , testHttpResponseCookies- , testHttp1- , testHttp2- , testHttp100- , testExpectGarbage- , testPartialParse- , testMethodParsing- , testServerStartupShutdown- , testServerShutdownWithOpenConns- , testChunkOn1_0- , testSendFile- , testTrivials]---testTrivials :: Test-testTrivials = testCase "server/trivials" $ do- let !v = Svr.snapServerVersion- return $! v `seq` ()----------------------------------------------------------------------------------- HTTP request tests---- note leading crlf -- test tolerance of this, some old browsers send an extra--- crlf after a post body-sampleRequest :: ByteString-sampleRequest =- S.concat [ "\r\nGET /foo/bar.html?param1=abc¶m2=def%20+¶m1=abc HTTP/1.1\r\n"- , "Host: www.zabble.com:7777\r\n"- , "Content-Length: 10\r\n"- , "X-Random-Other-Header: foo\r\n bar\r\n"- , "Cookie: foo=\"bar\\\"\"\r\n"- , "\r\n"- , "0123456789" ]--sampleRequestExpectContinue :: ByteString-sampleRequestExpectContinue =- S.concat [ "\r\nGET /foo/bar.html?param1=abc¶m2=def%20+¶m1=abc HTTP/1.1\r\n"- , "Host: www.zabble.com:7777\r\n"- , "Content-Length: 10\r\n"- , "Expect: 100-continue\r\n"- , "X-Random-Other-Header: foo\r\n bar\r\n"- , "Cookie: foo=\"bar\\\"\"\r\n"- , "\r\n"- , "0123456789" ]--sampleRequestExpectGarbage :: ByteString-sampleRequestExpectGarbage =- S.concat [ "\r\nGET /foo/bar.html?param1=abc¶m2=def%20+¶m1=abc HTTP/1.1\r\n"- , "Host: www.zabble.com:7777\r\n"- , "Content-Length: 10\r\n"- , "Expect: wuzzawuzzawuzza\r\n"- , "X-Random-Other-Header: foo\r\n bar\r\n"- , "Cookie: foo=\"bar\\\"\"\r\n"- , "\r\n"- , "0123456789" ]--sampleRequest1_0 :: ByteString-sampleRequest1_0 =- S.concat [ "\r\nGET /foo/bar.html?param1=abc¶m2=def%20+¶m1=abc HTTP/1.0\r\n"- , "Host: www.zabble.com:7777\r\n"- , "Content-Length: 10\r\n"- , "X-Random-Other-Header: foo\r\n bar\r\n"- , "Cookie: foo=\"bar\\\"\"\r\n"- , "\r\n"- , "0123456789" ]--testMethodParsing :: Test-testMethodParsing =- testCase "server/method parsing" $ Prelude.mapM_ testOneMethod ms- where- ms = [ GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT ]----mkRequest :: ByteString -> IO Request-mkRequest s = do- step <- runIteratee $ liftM fromJust $ rsm receiveRequest- let iter = enumBS s step- run_ iter---testReceiveRequest :: Iteratee ByteString IO (Request,L.ByteString)-testReceiveRequest = do- r <- liftM fromJust $ rsm receiveRequest- se <- liftIO $ readIORef (rqBody r)- let (SomeEnumerator e) = se- it <- liftM e $ lift $ runIteratee copyingStream2Stream- b <- it- return (r,b)---testReceiveRequestIter :: ByteString- -> IO (Iteratee ByteString IO (Request,L.ByteString))-testReceiveRequestIter req =- liftM (enumBS req) $ runIteratee testReceiveRequest---testHttpRequest1 :: Test-testHttpRequest1 =- testCase "server/HttpRequest1" $ do- iter <- testReceiveRequestIter sampleRequest-- (req,body) <- run_ iter-- assertEqual "not secure" False $ rqIsSecure req-- assertEqual "content length" (Just 10) $ rqContentLength req-- assertEqual "parse body" "0123456789" body-- assertEqual "cookie" [Cookie "foo" "bar\"" Nothing Nothing Nothing] $- rqCookies req-- assertEqual "continued headers" (Just ["foo bar"]) $- Map.lookup "x-random-other-header" $ rqHeaders req-- assertEqual "parse URI"- "/foo/bar.html?param1=abc¶m2=def%20+¶m1=abc"- $ rqURI req-- assertEqual "server port" 7777 $ rqServerPort req- assertEqual "context path" "/" $ rqContextPath req- assertEqual "pathinfo" "foo/bar.html" $ rqPathInfo req- assertEqual "query string" "param1=abc¶m2=def%20+¶m1=abc" $- rqQueryString req- assertEqual "server name" "www.zabble.com" $ rqServerName req- assertEqual "version" (1,1) $ rqVersion req- assertEqual "param1" (Just ["abc","abc"]) $- rqParam "param1" req- assertEqual "param2" (Just ["def "]) $- rqParam "param2" req----testMultiRequest :: Test-testMultiRequest =- testCase "server/MultiRequest" $ do- let clientIter = do- (r1,b1) <- testReceiveRequest- (r2,b2) <- testReceiveRequest-- return (r1,b1,r2,b2)-- iter <- liftM (enumBS sampleRequest >==> enumBS sampleRequest) $- runIteratee clientIter-- (req1,body1,req2,body2) <- run_ iter-- assertEqual "parse body 1" "0123456789" body1- assertEqual "parse body 2" "0123456789" body2-- assertEqual "parse URI 1"- "/foo/bar.html?param1=abc¶m2=def%20+¶m1=abc"- $ rqURI req1-- assertEqual "parse URI 2"- "/foo/bar.html?param1=abc¶m2=def%20+¶m1=abc"- $ rqURI req2----testOneMethod :: Method -> IO ()-testOneMethod m = do- step <- runIteratee $ liftM fromJust $ rsm receiveRequest- let iter = enumLBS txt step- req <- run_ iter-- assertEqual "method" m $ rqMethod req-- where- txt = methodTestText m---sampleShortRequest :: ByteString-sampleShortRequest = "GET /fo"--expectException :: IO a -> IO ()-expectException m = do- e <- try m- case e of- Left (_::SomeException) -> return ()- Right _ -> assertFailure "expected exception, didn't get it"---testPartialParse :: Test-testPartialParse = testCase "server/short" $ do- step <- runIteratee $ liftM fromJust $ rsm receiveRequest- let iter = enumBS sampleShortRequest step-- expectException $ run_ iter---methodTestText :: Method -> L.ByteString-methodTestText m = L.concat [ (L.pack $ map c2w $ show m)- , " / HTTP/1.1\r\n\r\n" ]---sampleRequest2 :: ByteString-sampleRequest2 =- S.concat [ "GET /foo/bar.html?param1=abc¶m2=def¶m1=abc HTTP/1.1\r\n"- , "Host: www.foo.com:8080\r\n"- , "Transfer-Encoding: chunked\r\n"- , "\r\n"- , "a\r\n"- , "0123456789\r\n"- , "4\r\n"- , "0123\r\n"- , "0\r\n\r\n" ]--testHttpRequest2 :: Test-testHttpRequest2 =- testCase "server/HttpRequest2" $ do- iter <- testReceiveRequestIter sampleRequest2- (_,body) <- run_ iter-- assertEqual "parse body" "01234567890123" body---testHttpRequest3 :: Test-testHttpRequest3 =- testCase "server/HttpRequest3" $ do- iter <- testReceiveRequestIter sampleRequest3- (req,body) <- run_ iter-- assertEqual "no cookies" [] $ rqCookies req-- assertEqual "multiheader" (Just ["1","2"]) $- Map.lookup "Multiheader" (rqHeaders req)-- assertEqual "host" ("localhost", 80) $- (rqServerName req, rqServerPort req)-- assertEqual "post param 1"- (rqParam "postparam1" req)- (Just ["1"])-- assertEqual "post param 2"- (rqParam "postparam2" req)- (Just ["2"])-- -- make sure the post body is still emitted- assertEqual "parse body" (LC.fromChunks [samplePostBody3]) body---testHttpRequest3' :: Test-testHttpRequest3' =- testCase "server/HttpRequest3'" $ do- iter <- testReceiveRequestIter sampleRequest3'- (req,body) <- run_ iter-- assertEqual "post param 1"- (rqParam "postparam1" req)- (Just ["1"])-- assertEqual "post param 2"- (rqParam "postparam2" req)- (Just ["2"])-- -- make sure the post body is still emitted- assertEqual "parse body" (LC.fromChunks [samplePostBody3]) body---samplePostBody3 :: ByteString-samplePostBody3 = "postparam1=1&postparam2=2"---sampleRequest3 :: ByteString-sampleRequest3 =- S.concat [ "\r\nGET /foo/bar.html?param1=abc¶m2=def%20+¶m1=abc HTTP/1.1\r\n"- , "Content-Type: application/x-www-form-urlencoded\r\n"- , "Content-Length: 25\r\n"- , "Multiheader: 1\r\n"- , "Multiheader: 2\r\n"- , "X-Random-Other-Header: foo\r\n bar\r\n"- , "\r\n"- , samplePostBody3 ]---sampleRequest3' :: ByteString-sampleRequest3' =- S.concat [ "\r\nGET /foo/bar.html?param1=abc¶m2=def%20+¶m1=abc HTTP/1.1\r\n"- , "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n"- , "Content-Length: 25\r\n"- , "Multiheader: 1\r\n"- , "Multiheader: 2\r\n"- , "X-Random-Other-Header: foo\r\n bar\r\n"- , "\r\n"- , samplePostBody3 ]-----rsm :: ServerMonad a -> Iteratee ByteString IO a-rsm = runServerMonad "localhost" (SessionInfo "127.0.0.1" 80 "127.0.0.1" 58382 False) alog elog- where- alog = const . const . return $ ()- elog = const $ return ()---testHttpResponse1 :: Test-testHttpResponse1 = testCase "server/HttpResponse1" $ do- sstep <- runIteratee copyingStream2Stream- req <- mkRequest sampleRequest-- b <- run_ $ rsm $- sendResponse req rsp1 sstep testOnSendFile >>=- return . snd-- assertEqual "http response" (L.concat [- "HTTP/1.0 600 Test\r\n"- , "Content-Length: 10\r\n"- , "Foo: Bar\r\n\r\n"- , "0123456789"- ]) b-- where- rsp1 = updateHeaders (Map.insert "Foo" ["Bar"]) $- setContentLength 10 $- setResponseStatus 600 "Test" $- modifyResponseBody (>==> (enumBS "0123456789")) $- setResponseBody returnI $- emptyResponse { rspHttpVersion = (1,0) }----testOnSendFile :: FilePath -> Int64 -> Int64 -> IO L.ByteString-testOnSendFile f st sz = do- sstep <- runIteratee copyingStream2Stream- run_ $ enumFilePartial f (st,st+sz) sstep--testHttpResponse2 :: Test-testHttpResponse2 = testCase "server/HttpResponse2" $ do- sstep <- runIteratee copyingStream2Stream- req <- mkRequest sampleRequest- b2 <- run_ $ rsm $- sendResponse req rsp2 sstep testOnSendFile >>=- return . snd-- assertEqual "http response" (L.concat [- "HTTP/1.0 600 Test\r\n"- , "Connection: close\r\n"- , "Foo: Bar\r\n\r\n"- , "0123456789"- ]) b2- where- rsp1 = updateHeaders (Map.insert "Foo" ["Bar"]) $- setContentLength 10 $- setResponseStatus 600 "Test" $- modifyResponseBody (>==> (enumBS "0123456789")) $- setResponseBody returnI $- emptyResponse { rspHttpVersion = (1,0) }- rsp2 = rsp1 { rspContentLength = Nothing }---testHttpResponse3 :: Test-testHttpResponse3 = testCase "server/HttpResponse3" $ do- sstep <- runIteratee copyingStream2Stream- req <- mkRequest sampleRequest-- b3 <- run_ $ rsm $- sendResponse req rsp3 sstep testOnSendFile >>=- return . snd-- assertEqual "http response" b3 $ L.concat [- "HTTP/1.1 600 Test\r\n"- , "Content-Type: text/plain\r\n"- , "Foo: Bar\r\n"- , "Transfer-Encoding: chunked\r\n\r\n"- , "a\r\n"- , "0123456789\r\n"- , "0\r\n\r\n"- ]--- where- rsp1 = updateHeaders (Map.insert "Foo" ["Bar"]) $- setContentLength 10 $- setResponseStatus 600 "Test" $- modifyResponseBody (>==> (enumBS "0123456789")) $- setResponseBody returnI $- emptyResponse { rspHttpVersion = (1,0) }- rsp2 = rsp1 { rspContentLength = Nothing }- rsp3 = setContentType "text/plain" $ (rsp2 { rspHttpVersion = (1,1) })---testHttpResponse4 :: Test-testHttpResponse4 = testCase "server/HttpResponse4" $ do- sstep <- runIteratee copyingStream2Stream-- req <- mkRequest sampleRequest-- b <- run_ $ rsm $- sendResponse req rsp1 sstep testOnSendFile >>=- return . snd-- assertEqual "http response" (L.concat [- "HTTP/1.0 304 Test\r\n"- , "Content-Length: 0\r\n\r\n"- ]) b-- where- rsp1 = setResponseStatus 304 "Test" $- emptyResponse { rspHttpVersion = (1,0) }---testHttpResponseCookies :: Test-testHttpResponseCookies = testCase "server/HttpResponseCookies" $ do- sstep <- runIteratee copyingStream2Stream- req <- mkRequest sampleRequest- b <- run_ $ rsm $- sendResponse req rsp2 sstep testOnSendFile >>=- return . snd- b2 <- run_ $ rsm $- sendResponse req rsp3 sstep testOnSendFile >>=- return . snd-- assertEqual "http response cookie" (L.concat [- "HTTP/1.0 304 Test\r\n"- , "Content-Length: 0\r\n"- , "Set-Cookie: foo=bar; path=/; expires=Sat, 30-Jan-2010 00:00:00 GMT; domain=.foo.com\r\n\r\n"- ]) b--- assertEqual "http response multi-cookies" (L.concat [- "HTTP/1.0 304 Test\r\n"- , "Content-Length: 0\r\n"- , "Set-Cookie: foo=bar; path=/; expires=Sat, 30-Jan-2010 00:00:00 GMT; domain=.foo.com\r\n"- , "Set-Cookie: zoo=baz; path=/; expires=Sat, 30-Jan-2010 00:00:00 GMT; domain=.foo.com\r\n\r\n"- ]) b2-- where- rsp1 = setResponseStatus 304 "Test" $- emptyResponse { rspHttpVersion = (1,0) }- rsp2 = addResponseCookie cook rsp1- rsp3 = addResponseCookie cook2 rsp2-- utc = UTCTime (ModifiedJulianDay 55226) 0- cook = Cookie "foo" "bar" (Just utc) (Just ".foo.com") (Just "/")- cook2 = Cookie "zoo" "baz" (Just utc) (Just ".foo.com") (Just "/")- cook3 = Cookie "boo" "baz" Nothing Nothing Nothing----echoServer :: (ByteString -> IO ())- -> Request- -> Iteratee ByteString IO (Request,Response)-echoServer _ req = do- se <- liftIO $ readIORef (rqBody req)- let (SomeEnumerator enum) = se- i <- liftM enum $ lift $ runIteratee copyingStream2Stream- b <- i- let cl = L.length b- liftIO $ writeIORef (rqBody req) (SomeEnumerator $ joinI . I.take 0)- return (req, rsp b cl)- where- rsp s cl = emptyResponse { rspBody = Enum $ enumLBS s- , rspContentLength = Just $ fromIntegral cl }---echoServer2 :: ServerHandler-echoServer2 _ req = do- (rq,rsp) <- echoServer (const $ return ()) req- return (rq, addResponseCookie cook rsp)- where- cook = Cookie "foo" "bar" (Just utc) (Just ".foo.com") (Just "/")- utc = UTCTime (ModifiedJulianDay 55226) 0---testHttp1 :: Test-testHttp1 = testCase "server/httpSession" $ do- let enumBody = enumBS sampleRequest >==> enumBS sampleRequest2-- ref <- newIORef ""-- let (iter,onSendFile) = mkIter ref-- runHTTP Nothing Nothing echoServer "localhost" (SessionInfo "127.0.0.1" 80 "127.0.0.1" 58384 False)- enumBody iter onSendFile (return ())-- s <- readIORef ref-- let lns = LC.lines s-- let ok = case lns of- ([ "HTTP/1.1 200 OK\r"- , "Content-Length: 10\r"- , d1- , s1- , "\r"- , "0123456789HTTP/1.1 200 OK\r"- , "Content-Length: 14\r"- , d2- , s2- , "\r"- , "01234567890123" ]) -> (("Date" `L.isPrefixOf` d1) &&- ("Date" `L.isPrefixOf` d2) &&- ("Server" `L.isPrefixOf` s1) &&- ("Server" `L.isPrefixOf` s2))-- _ -> False-- when (not ok) $ do- putStrLn "server/httpSession fail!!!! got:"- LC.putStrLn s-- assertBool "pipelined responses" ok---mkIter :: IORef L.ByteString- -> (Iteratee ByteString IO (), FilePath -> Int64 -> Int64 -> IO ())-mkIter ref = (iter, \f st sz -> onF f st sz iter)- where- iter = do- x <- copyingStream2Stream- liftIO $ modifyIORef ref $ \s -> L.append s x-- onF f st sz i = do- step <- runIteratee i- let it = enumFilePartial f (st,st+sz) step- run_ it---testChunkOn1_0 :: Test-testChunkOn1_0 = testCase "server/transfer-encoding chunked" $ do- let enumBody = enumBS sampleRequest1_0-- ref <- newIORef ""- let (iter,onSendFile) = mkIter ref-- done <- newEmptyMVar- forkIO (runHTTP Nothing Nothing f "localhost" (SessionInfo "127.0.0.1" 80 "127.0.0.1" 58384 False)- enumBody iter onSendFile (return ())- `finally` putMVar done ())-- takeMVar done-- -- this is a pretty lame way of checking whether the output was chunked,- -- but "whatever"- output <- liftM lower $ readIORef ref-- assertBool "chunked output" $ not $ S.isInfixOf "chunked" output- assertBool "connection close" $ S.isInfixOf "connection: close" output-- where- lower = S.map toLower . S.concat . L.toChunks-- f :: ServerHandler- f _ req = do- let s = L.fromChunks $ Prelude.take 500 $ repeat "fldkjlfksdjlfd"- let out = enumLBS s- return (req, emptyResponse { rspBody = Enum out })---sampleRequest4 :: ByteString-sampleRequest4 =- S.concat [ "\r\nGET /foo/bar.html?param1=abc¶m2=def%20+¶m1=abc HTTP/1.1\r\n"- , "Host: www.zabble.com:7777\r\n"- , "Content-Length: 10\r\n"- , "Connection: close\r\n"- , "X-Random-Other-Header: foo\r\n bar\r\n"- , "Cookie: foo=\"bar\\\"\"\r\n"- , "\r\n"- , "0123456789" ]---testHttp2 :: Test-testHttp2 = testCase "server/connection: close" $ do- let enumBody = enumBS sampleRequest4 >==> enumBS sampleRequest2-- ref <- newIORef ""-- let (iter,onSendFile) = mkIter ref-- done <- newEmptyMVar-- forkIO (runHTTP Nothing- Nothing- echoServer2- "localhost"- (SessionInfo "127.0.0.1" 80 "127.0.0.1" 58384 False)- enumBody- iter- onSendFile- (return ()) `finally` putMVar done ())-- takeMVar done-- s <- readIORef ref-- let lns = LC.lines s-- let ok = case lns of- ([ "HTTP/1.1 200 OK\r"- , "Connection: close\r"- , "Content-Length: 10\r"- , d1- , s1- , "Set-Cookie: foo=bar; path=/; expires=Sat, 30-Jan-2010 00:00:00 GMT; domain=.foo.com\r"- , "\r"- , "0123456789" ]) -> (("Date" `L.isPrefixOf` d1) &&- ("Server" `L.isPrefixOf` s1))-- _ -> False-- assertBool "connection: close" ok----testHttp100 :: Test-testHttp100 = testCase "server/expect100" $ do- let enumBody = enumBS sampleRequestExpectContinue-- ref <- newIORef ""-- let (iter,onSendFile) = mkIter ref-- runHTTP Nothing- Nothing- echoServer2- "localhost"- (SessionInfo "127.0.0.1" 80 "127.0.0.1" 58384 False)- enumBody- iter- onSendFile- (return ())-- s <- readIORef ref-- let lns = LC.lines s-- let ok = case lns of- ([ "HTTP/1.1 100 Continue\r"- , "\r"- , "HTTP/1.1 200 OK\r"- , "Content-Length: 10\r"- , d1- , s1- , "Set-Cookie: foo=bar; path=/; expires=Sat, 30-Jan-2010 00:00:00 GMT; domain=.foo.com\r"- , "\r"- , "0123456789" ]) -> (("Date" `L.isPrefixOf` d1) &&- ("Server" `L.isPrefixOf` s1))-- _ -> False-- when (not ok) $ do- putStrLn "expect100 fail! got:"- LC.putStrLn s-- assertBool "100 Continue" ok---testExpectGarbage :: Test-testExpectGarbage = testCase "server/Expect: garbage" $ do- let enumBody = enumBS sampleRequestExpectGarbage-- ref <- newIORef ""-- let (iter,onSendFile) = mkIter ref-- runHTTP Nothing- Nothing- echoServer2- "localhost"- (SessionInfo "127.0.0.1" 80 "127.0.0.1" 58384 False)- enumBody- iter- onSendFile- (return ())-- s <- readIORef ref-- let lns = LC.lines s-- let ok = case lns of- ([ "HTTP/1.1 200 OK\r"- , "Content-Length: 10\r"- , d1- , s1- , "Set-Cookie: foo=bar; path=/; expires=Sat, 30-Jan-2010 00:00:00 GMT; domain=.foo.com\r"- , "\r"- , "0123456789" ]) -> (("Date" `L.isPrefixOf` d1) &&- ("Server" `L.isPrefixOf` s1))-- _ -> False-- assertBool "random expect: header" ok-----pongServer :: Snap ()-pongServer = modifyResponse $ setResponseBody (enumBS "PONG") .- setContentType "text/plain" .- setContentLength 4--sendFileFoo :: Snap ()-sendFileFoo = sendFile "data/fileServe/foo.html"---testSendFile :: Test-testSendFile = testCase "server/sendFile" $ do- bracket (forkIO serve)- (killThread)- (\tid -> do- m <- timeout (120 * seconds) $ go tid- maybe (assertFailure "timeout")- (const $ return ())- m)-- where- serve = (httpServe [HttpPort "*" port] Nothing "localhost"- Nothing Nothing- $ runSnap sendFileFoo)- `catch` \(_::SomeException) -> return ()-- go tid = do- waitabit-- doc <- HTTP.simpleHttp "http://localhost:8123/"-- killThread tid- waitabit-- assertEqual "sendFile" "FOO\n" doc--- waitabit = threadDelay $ ((10::Int)^(6::Int))-- port = 8123---testServerStartupShutdown :: Test-testServerStartupShutdown = testCase "server/startup/shutdown" $ do- bracket (forkIO $- httpServe [HttpPort "*" port]- Nothing- "localhost"- (Just "test-access.log")- (Just "test-error.log")- (runSnap pongServer))- (killThread)- (\tid -> do- m <- timeout (120 * seconds) $ go tid- maybe (assertFailure "timeout")- (const $ return ())- m)--- where- go tid = do- debug $ "testServerStartupShutdown: waiting a bit"- waitabit- debug $ "testServerStartupShutdown: sending http request"- doc <- HTTP.simpleHttp "http://localhost:8145/"- assertEqual "server" "PONG" doc-- debug $ "testServerStartupShutdown: killing thread"- killThread tid- debug $ "testServerStartupShutdown: kill signal sent to thread"- waitabit-- expectException $ HTTP.simpleHttp "http://localhost:8145/"- return ()-- waitabit = threadDelay $ 2*((10::Int)^(6::Int))-- port = 8145---testServerShutdownWithOpenConns :: Test-testServerShutdownWithOpenConns = testCase "server/shutdown-open-conns" $ do- tid <- forkIO $- httpServe [HttpPort "127.0.0.1" port]- Nothing- "localhost"- Nothing- Nothing- (runSnap pongServer)-- waitabit-- result <- newEmptyMVar-- forkIO $ do- e <- try $ withSock port $ \sock -> do- N.sendAll sock "GET /"- waitabit- killThread tid- waitabit- N.sendAll sock "pong HTTP/1.1\r\n"- N.sendAll sock "Host: 127.0.0.1\r\n"- N.sendAll sock "Content-Length: 0\r\n"- N.sendAll sock "Connection: close\r\n\r\n"-- resp <- recvAll sock- when (S.null resp) $ throwIO TestException-- let s = S.unpack $ Prelude.head $ ditchHeaders $ S.lines resp- debug $ "got HTTP response " ++ s ++ ", we shouldn't be here...."-- putMVar result e-- e <- timeout (75*seconds) $ takeMVar result-- case e of- Nothing -> killThread tid >> assertFailure "timeout"- (Just r) ->- case r of- (Left (_::SomeException)) -> return ()- (Right _) -> assertFailure "socket didn't get killed"--- where- waitabit = threadDelay $ 2*((10::Int)^(6::Int))- port = 8146----seconds :: Int-seconds = (10::Int) ^ (6::Int)---copyingStream2Stream :: (Monad m) => Iteratee ByteString m L.ByteString-copyingStream2Stream = go []- where- go l = do- mbx <- I.head- maybe (return $ L.fromChunks $ reverse l)- (\x -> let !z = S.copy x in go (z:l))- mbx
− test/suite/Test/Blackbox.hs
@@ -1,280 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE PackageImports #-}--module Test.Blackbox- ( tests- , ssltests- , startTestServer ) where---------------------------------------------------------------------------------import Control.Concurrent-import Control.Exception (SomeException, catch)-import Control.Monad-import qualified Data.ByteString.Char8 as S-import Data.ByteString.Char8 (ByteString)-import qualified Data.ByteString.Lazy.Char8 as L-import Data.Int-import qualified Network.HTTP.Enumerator as HTTP-import qualified Network.Socket.ByteString as N-import Prelude hiding (catch, take)-import System.Timeout-import Test.Framework-import Test.Framework.Providers.HUnit-import Test.Framework.Providers.QuickCheck2-import Test.HUnit hiding (Test, path)-import Test.QuickCheck-import qualified Test.QuickCheck.Monadic as QC-import Test.QuickCheck.Monadic hiding (run, assert)--------------------------------------------------------------------------------import Snap.Http.Server-import Snap.Test.Common-import Test.Common.Rot13-import Test.Common.TestHandler---------------------------------------------------------------------------------testFunctions :: [Bool -> Int -> String -> Test]-testFunctions = [ testPong--- FIXME: waiting on http-enumerator patch for HEAD behaviour--- , testHeadPong- , testEcho- , testRot13- , testSlowLoris- , testBlockingRead- , testBigResponse- , testPartial- ]----------------------------------------------------------------------------------tests :: Int -> String -> [Test]-tests port name = map (\f -> f False port name) testFunctions----------------------------------------------------------------------------------ssltests :: String -> Maybe Int -> [Test]-ssltests name = maybe [] httpsTests- where httpsTests port = map (\f -> f True port sslname) testFunctions- sslname = "ssl/" ++ name---------------------------------------------------------------------------------startTestServer :: Int- -> Maybe Int- -> ConfigBackend- -> IO (ThreadId, MVar ())-startTestServer port sslport backend = do- let cfg = setAccessLog (Just $ "ts-access." ++ show backend ++ ".log") .- setErrorLog (Just $ "ts-error." ++ show backend ++ ".log") .- addListen (ListenHttp "*" port) .- setBackend backend .- setVerbose False $- defaultConfig-- let cfg' = case sslport of- Nothing -> cfg- Just p -> addListen- (ListenHttps "*" p "cert.pem" "key.pem")- cfg-- mvar <- newEmptyMVar- tid <- forkIO $ do- (httpServe cfg' testHandler)- `catch` \(_::SomeException) -> return ()- putMVar mvar ()- waitabit-- return (tid,mvar)----------------------------------------------------------------------------------doPong :: Bool -> Int -> IO ByteString-doPong ssl port = do- let uri = (if ssl then "https" else "http")- ++ "://localhost:" ++ show port ++ "/pong"-- rsp <- HTTP.simpleHttp uri- return $ S.concat $ L.toChunks rsp------------------------------------------------------------------------------------ FIXME: waiting on http-enumerator patch for HEAD behaviour--- headPong :: Bool -> Int -> IO ByteString--- headPong ssl port = do--- let uri = (if ssl then "https" else "http")--- ++ "://localhost:" ++ show port ++ "/echo"---- req0 <- HTTP.parseUrl uri---- let req = req0 { HTTP.method = "HEAD" }--- rsp <- HTTP.httpLbs req--- return $ S.concat $ L.toChunks $ HTTP.responseBody rsp---------------------------------------------------------------------------------testPong :: Bool -> Int -> String -> Test-testPong ssl port name = testCase (name ++ "/blackbox/pong") $ do- doc <- doPong ssl port- assertEqual "pong response" "PONG" doc------------------------------------------------------------------------------------ FIXME: waiting on http-enumerator patch for HEAD behaviour--- testHeadPong :: Bool -> Int -> String -> Test--- testHeadPong ssl port name = testCase (name ++ "/blackbox/pong/HEAD") $ do--- doc <- headPong ssl port--- assertEqual "pong HEAD response" "" doc----------------------------------------------------------------------------------testEcho :: Bool -> Int -> String -> Test-testEcho ssl port name = testProperty (name ++ "/blackbox/echo") $- monadicIO $ forAllM arbitrary prop- where- prop txt = do- let uri = (if ssl then "https" else "http")- ++ "://localhost:" ++ show port ++ "/echo"-- req0 <- QC.run $ HTTP.parseUrl uri- let req = req0 { HTTP.requestBody = txt- , HTTP.method = "POST" }-- rsp <- QC.run $ HTTP.httpLbs req- let doc = HTTP.responseBody rsp-- QC.assert $ txt == doc----------------------------------------------------------------------------------testRot13 :: Bool -> Int -> String -> Test-testRot13 ssl port name = testProperty (name ++ "/blackbox/rot13") $- monadicIO $ forAllM arbitrary prop- where- prop txt = do- let uri = (if ssl then "https" else "http")- ++ "://localhost:" ++ show port ++ "/rot13"-- req0 <- QC.run $ HTTP.parseUrl uri- let req = req0 { HTTP.requestBody = L.fromChunks [txt]- , HTTP.method = "POST" }-- rsp <- QC.run $ HTTP.httpLbs req- let doc = S.concat $ L.toChunks $ HTTP.responseBody rsp-- QC.assert $ txt == rot13 doc------------------------------------------------------------------------------------ TODO: this one doesn't work w/ SSL-testSlowLoris :: Bool -> Int -> String -> Test-testSlowLoris ssl port name = testCase (name ++ "/blackbox/slowloris") $- if ssl then return () else withSock port go-- where- go sock = do- m <- timeout (120*seconds) $ go' sock- maybe (assertFailure "slowloris: timeout")- (const $ return ())- m-- go' sock = do- N.sendAll sock "POST /echo HTTP/1.1\r\n"- N.sendAll sock "Host: 127.0.0.1\r\n"- N.sendAll sock "Content-Length: 2500000\r\n"- N.sendAll sock "Connection: close\r\n\r\n"-- b <- expectExceptionBeforeTimeout (loris sock) 60-- assertBool "didn't catch slow loris attack" b-- loris sock = do- N.sendAll sock "."- waitabit- loris sock------------------------------------------------------------------------------------ TODO: doesn't work w/ ssl-testBlockingRead :: Bool -> Int -> String -> Test-testBlockingRead ssl port name =- testCase (name ++ "/blackbox/testBlockingRead") $- if ssl then return () else runIt-- where- runIt = withSock port $ \sock -> do- m <- timeout (60*seconds) $ go sock- maybe (assertFailure "timeout")- (const $ return ())- m-- go sock = do- N.sendAll sock "GET /"- waitabit- N.sendAll sock "pong HTTP/1.1\r\n"- N.sendAll sock "Host: 127.0.0.1\r\n"- N.sendAll sock "Content-Length: 0\r\n"- N.sendAll sock "Connection: close\r\n\r\n"-- resp <- recvAll sock-- let s = head $ ditchHeaders $ S.lines resp-- assertEqual "pong response" "PONG" s------------------------------------------------------------------------------------ TODO: no ssl here--- test server's ability to trap/recover from IO errors-testPartial :: Bool -> Int -> String -> Test-testPartial ssl port name =- testCase (name ++ "/blackbox/testPartial") $- if ssl then return () else runIt-- where- runIt = do- m <- timeout (60*seconds) go- maybe (assertFailure "timeout")- (const $ return ())- m-- go = do- withSock port $ \sock ->- N.sendAll sock "GET /pong HTTP/1.1\r\n"-- doc <- doPong ssl port- assertEqual "pong response" "PONG" doc------------------------------------------------------------------------------------ TODO: no ssl-testBigResponse :: Bool -> Int -> String -> Test-testBigResponse ssl port name =- testCase (name ++ "/blackbox/testBigResponse") $- if ssl then return () else runIt- where- runIt = withSock port $ \sock -> do- m <- timeout (120*seconds) $ go sock- maybe (assertFailure "timeout")- (const $ return ())- m-- go sock = do- N.sendAll sock "GET /bigresponse HTTP/1.1\r\n"- N.sendAll sock "Host: 127.0.0.1\r\n"- N.sendAll sock "Content-Length: 0\r\n"- N.sendAll sock "Connection: close\r\n\r\n"-- let body = S.replicate 4000000 '.'- resp <- recvAll sock-- let s = head $ ditchHeaders $ S.lines resp-- assertBool "big response" $ body == s----------------------------------------------------------------------------------waitabit :: IO ()-waitabit = threadDelay $ 2*seconds----------------------------------------------------------------------------------seconds :: Int-seconds = (10::Int) ^ (6::Int)
− test/suite/TestSuite.hs
@@ -1,62 +0,0 @@-{-# LANGUAGE CPP #-}--module Main where--import Control.Exception-import Control.Concurrent (killThread)-import Control.Concurrent.MVar-import Control.Monad-import qualified Network.HTTP.Enumerator as HTTP-import Test.Framework (defaultMain, testGroup)-import Snap.Http.Server.Config---import qualified Data.Concurrent.HashMap.Tests-import qualified Snap.Internal.Http.Parser.Tests-import qualified Snap.Internal.Http.Server.Tests-import qualified Test.Blackbox--ports :: [Int]-ports = [8195..]--#ifdef GNUTLS-sslports :: [Maybe Int]-sslports = map Just [8295..]-#else-sslports :: [Maybe Int]-sslports = repeat Nothing-#endif--#ifdef LIBEV-backends :: [(Int,Maybe Int,ConfigBackend)]-backends = zip3 ports sslports [ConfigSimpleBackend, ConfigLibEvBackend]-#else-backends :: [(Int,Maybe Int,ConfigBackend)]-backends = zip3 ports sslports [ConfigSimpleBackend]-#endif--main :: IO ()-main = HTTP.withHttpEnumerator $ do- tinfos <- forM backends $ \(port,sslport,b) ->- Test.Blackbox.startTestServer port sslport b-- defaultMain (tests ++ concatMap blackbox backends) `finally` do- mapM_ killThread $ map fst tinfos- mapM_ takeMVar $ map snd tinfos-- where tests =- [ testGroup "Data.Concurrent.HashMap.Tests"- Data.Concurrent.HashMap.Tests.tests- , testGroup "Snap.Internal.Http.Parser.Tests"- Snap.Internal.Http.Parser.Tests.tests- , testGroup "Snap.Internal.Http.Server.Tests"- Snap.Internal.Http.Server.Tests.tests- ]- blackbox (port, sslport, b) =- [ testGroup ("Test.Blackbox " ++ backendName)- $ Test.Blackbox.tests port backendName- , testGroup ("Test.Blackbox SSL " ++ backendName)- $ Test.Blackbox.ssltests backendName sslport- ]- where- backendName = show b
− test/testserver/Main.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}--module Main where--import Control.Concurrent-import Control.Exception (finally)--import Snap.Http.Server-import Test.Common.TestHandler---{---/pong-/fileserve-/echo-pipelined POST requests-slowloris attack / timeout test---}---main :: IO ()-main = do- m <- newEmptyMVar-- forkIO $ go m- takeMVar m-- return ()-- where- go m = quickHttpServe testHandler `finally` putMVar m ()-
− test/testserver/static/hello.txt
@@ -1,1 +0,0 @@-hello world
+ testserver/Main.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Rank2Types #-}++module Main where++import Control.Concurrent+import Control.Exception (finally)++import Snap.Http.Server+import Test.Common.TestHandler+++{-++/pong+/fileserve+/echo+pipelined POST requests+slowloris attack / timeout test++-}+++main :: IO ()+main = do+ m <- newEmptyMVar++ forkIO $ go m+ takeMVar m++ return ()++ where+ go m = quickHttpServe testHandler `finally` putMVar m ()+
+ testserver/static/hello.txt view
@@ -0,0 +1,1 @@+hello world