From a8e1315ee7e1ebc67578ece62b5c226516570640 Mon Sep 17 00:00:00 2001 From: Joseph Kachmar Date: Tue, 5 Jul 2016 11:34:30 -0400 Subject: [PATCH 01/34] Fix servant-js examples The Servant.JS Counter example was broken: - `axios` was not completely applied. It now uses `defAxiosOptions` similarly to the `angular` example - `OverloadedStrings` was required, but not included --- servant-js/examples/counter.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/servant-js/examples/counter.hs b/servant-js/examples/counter.hs index 5d2b80d0..4040b053 100644 --- a/servant-js/examples/counter.hs +++ b/servant-js/examples/counter.hs @@ -1,6 +1,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeOperators #-} import Control.Concurrent.STM @@ -92,7 +93,7 @@ main = do writeJSForAPI testApi (angular defAngularOptions) (www "angular" "api.js") - writeJSForAPI testApi axios (www "axios" "api.js") + writeJSForAPI testApi (axios defAxiosOptions) (www "axios" "api.js") writeServiceJS (www "angular" "api.service.js") From 197ed0548a0e6a5b6fcf7f9926b7a041ffd4b97f Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Sun, 10 Jul 2016 23:28:51 +0300 Subject: [PATCH 02/34] Use parseRequest --- servant-client/src/Servant/Common/Req.hs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/servant-client/src/Servant/Common/Req.hs b/servant-client/src/Servant/Common/Req.hs index 6d922634..eb921316 100644 --- a/servant-client/src/Servant/Common/Req.hs +++ b/servant-client/src/Servant/Common/Req.hs @@ -103,7 +103,7 @@ setRQBody b t req = req { reqBody = Just (b, t) } reqToRequest :: (Functor m, MonadThrow m) => Req -> BaseUrl -> m Request reqToRequest req (BaseUrl reqScheme reqHost reqPort path) = - setheaders . setAccept . setrqb . setQS <$> parseUrlThrow url + setheaders . setAccept . setrqb . setQS <$> parseRequest url where url = show $ nullURI { uriScheme = case reqScheme of Http -> "http:" @@ -129,8 +129,18 @@ reqToRequest req (BaseUrl reqScheme reqHost reqPort path) = | not . null . reqAccept $ req] } toProperHeader (name, val) = (fromString name, encodeUtf8 val) + #if !MIN_VERSION_http_client(0,4,30) - parseUrlThrow = parseUrl +-- 'parseRequest' is introduced in http-client-0.4.30 +-- it differs from 'parseUrl', by not throwing exceptions on non-2xx http statuses +-- +-- See for implementations: +-- http://hackage.haskell.org/package/http-client-0.4.30/docs/src/Network-HTTP-Client-Request.html#parseRequest +-- http://hackage.haskell.org/package/http-client-0.5.0/docs/src/Network-HTTP-Client-Request.html#parseRequest +parseRequest :: MonadThrow m => String -> m Request +parseRequest url = disableStatusCheck <$> parseUrl url + where + disableStatusCheck req = req { checkStatus = \ _status _headers _cookies -> Nothing } #endif @@ -147,8 +157,7 @@ performRequest :: Method -> Req -> Manager -> BaseUrl performRequest reqMethod req manager reqHost = do partialRequest <- liftIO $ reqToRequest req reqHost - let request = disableStatusCheck $ - partialRequest { Client.method = reqMethod } + let request = partialRequest { Client.method = reqMethod } eResponse <- liftIO $ catchConnectionError $ Client.httpLbs request manager case eResponse of @@ -169,13 +178,6 @@ performRequest reqMethod req manager reqHost = do throwE $ FailureResponse status ct body return (status_code, body, ct, hdrs, response) -disableStatusCheck :: Request -> Request -#if MIN_VERSION_http_client(0,5,0) -disableStatusCheck req = req { checkResponse = \ _req _res -> return () } -#else -disableStatusCheck req = req { checkStatus = \ _status _headers _cookies -> Nothing } -#endif - performRequestCT :: MimeUnrender ct result => Proxy ct -> Method -> Req -> Manager -> BaseUrl -> ClientM ([HTTP.Header], result) From 6999b002977fa1a726ea627f716e47c677047713 Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Sun, 7 Aug 2016 20:12:09 +0300 Subject: [PATCH 03/34] Support aeson-1 --- servant-client/servant-client.cabal | 2 +- servant-js/servant-js.cabal | 2 +- servant-server/servant-server.cabal | 2 +- servant/servant.cabal | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/servant-client/servant-client.cabal b/servant-client/servant-client.cabal index 2dfc4403..089e1209 100644 --- a/servant-client/servant-client.cabal +++ b/servant-client/servant-client.cabal @@ -36,7 +36,7 @@ library Servant.Common.Req build-depends: base >= 4.7 && < 4.10 - , aeson >= 0.7 && < 0.12 + , aeson >= 0.7 && < 1.1 , attoparsec >= 0.12 && < 0.14 , base64-bytestring >= 1.0.0.1 && < 1.1 , bytestring >= 0.10 && < 0.11 diff --git a/servant-js/servant-js.cabal b/servant-js/servant-js.cabal index d29dc96c..726e0b4e 100644 --- a/servant-js/servant-js.cabal +++ b/servant-js/servant-js.cabal @@ -65,7 +65,7 @@ executable counter buildable: False build-depends: base >= 4.7 && < 5 - , aeson >= 0.7 && < 0.12 + , aeson >= 0.7 && < 1.1 , filepath >= 1 , lens >= 4 , servant == 0.8.* diff --git a/servant-server/servant-server.cabal b/servant-server/servant-server.cabal index 66a18577..ff84d947 100644 --- a/servant-server/servant-server.cabal +++ b/servant-server/servant-server.cabal @@ -47,7 +47,7 @@ library build-depends: base >= 4.7 && < 4.10 , base-compat >= 0.9 && < 0.10 - , aeson >= 0.7 && < 0.12 + , aeson >= 0.7 && < 1.1 , attoparsec >= 0.12 && < 0.14 , base64-bytestring >= 1.0 && < 1.1 , bytestring >= 0.10 && < 0.11 diff --git a/servant/servant.cabal b/servant/servant.cabal index 48784cac..3c89171f 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -51,7 +51,7 @@ library build-depends: base >= 4.7 && < 4.10 , base-compat >= 0.9 && < 0.10 - , aeson >= 0.7 && < 0.12 + , aeson >= 0.7 && < 1.1 , attoparsec >= 0.12 && < 0.14 , bytestring >= 0.10 && < 0.11 , bytestring-conversion >= 0.3 && < 0.4 From 490502cad1fab8ea7c1ff96f68fec5c355fee0ba Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Wed, 10 Aug 2016 17:49:56 +0300 Subject: [PATCH 04/34] Support QuickCheck-2.9 --- servant-mock/servant-mock.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servant-mock/servant-mock.cabal b/servant-mock/servant-mock.cabal index f71dbd75..89ff1f6f 100644 --- a/servant-mock/servant-mock.cabal +++ b/servant-mock/servant-mock.cabal @@ -34,7 +34,7 @@ library servant == 0.8.*, servant-server == 0.8.*, transformers >= 0.3 && <0.6, - QuickCheck >= 2.7 && <2.9, + QuickCheck >= 2.7 && <2.10, wai >= 3.0 && <3.3 hs-source-dirs: src default-language: Haskell2010 From b1f143010e939ef6b180d636bfd14050eb39f945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Sun, 14 Aug 2016 20:13:46 +0200 Subject: [PATCH 05/34] servant-client: fix compilation when building with http-client < 0.4.30 --- servant-client/src/Servant/Common/Req.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servant-client/src/Servant/Common/Req.hs b/servant-client/src/Servant/Common/Req.hs index eb921316..ea610cce 100644 --- a/servant-client/src/Servant/Common/Req.hs +++ b/servant-client/src/Servant/Common/Req.hs @@ -138,7 +138,7 @@ reqToRequest req (BaseUrl reqScheme reqHost reqPort path) = -- http://hackage.haskell.org/package/http-client-0.4.30/docs/src/Network-HTTP-Client-Request.html#parseRequest -- http://hackage.haskell.org/package/http-client-0.5.0/docs/src/Network-HTTP-Client-Request.html#parseRequest parseRequest :: MonadThrow m => String -> m Request -parseRequest url = disableStatusCheck <$> parseUrl url +parseRequest url = liftM disableStatusCheck (parseUrl url) where disableStatusCheck req = req { checkStatus = \ _status _headers _cookies -> Nothing } #endif From d0a28e46b032ee8f6de707d99379ad04e117c607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Sun, 14 Aug 2016 19:58:05 +0200 Subject: [PATCH 06/34] add missing test file to servant-server.cabal --- servant-server/servant-server.cabal | 1 + 1 file changed, 1 insertion(+) diff --git a/servant-server/servant-server.cabal b/servant-server/servant-server.cabal index ff84d947..d055df2f 100644 --- a/servant-server/servant-server.cabal +++ b/servant-server/servant-server.cabal @@ -99,6 +99,7 @@ test-suite spec hs-source-dirs: test main-is: Spec.hs other-modules: + Servant.ArbitraryMonadServerSpec Servant.Server.ErrorSpec Servant.Server.Internal.ContextSpec Servant.Server.RouterSpec From 4ccfce2331c4b89f051ec6592b5bead975353bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Sun, 14 Aug 2016 22:45:32 +0200 Subject: [PATCH 07/34] docs: bump Sphinx version --- doc/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/requirements.txt b/doc/requirements.txt index 0c9c95a8..93ddeccc 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -17,7 +17,7 @@ recommonmark==0.4.0 singledispatch==3.4.0.3 six==1.10.0 snowballstemmer==1.2.1 -Sphinx==1.3.4 +Sphinx==1.3.6 sphinx-autobuild==0.5.2 sphinx-rtd-theme==0.1.9 tornado==4.3 From 1b83d30cf3ea89a8ad7b52c0640fa91b095cc214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Thu, 11 Aug 2016 16:53:46 +0200 Subject: [PATCH 08/34] switch ci to stack and add ci cron job to test hackage breakage --- .travis.yml | 28 +++++++++++----------------- travis.sh => scripts/ci-cron.sh | 9 ++++++++- 2 files changed, 19 insertions(+), 18 deletions(-) rename travis.sh => scripts/ci-cron.sh (56%) diff --git a/.travis.yml b/.travis.yml index d6854b8a..1a006a6b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,33 +3,27 @@ sudo: false language: c env: - - GHCVER=7.8.4 CABALVER=1.22 - - GHCVER=7.10.3 CABALVER=1.22 - - GHCVER=8.0.1 CABALVER=1.24 + - STACK_YAML=stack-ghc-7.8.4.yaml + - STACK_YAML=stack.yaml + - STACK_YAML=stack-ghc-8.0.1.yaml addons: apt: - sources: - - hvr-ghc packages: - - ghc-7.8.4 - - ghc-7.10.3 - - ghc-8.0.1 - - cabal-install-1.22 - - cabal-install-1.24 - libgmp-dev install: - - (mkdir -p $HOME/.local/bin && cd $HOME/.local/bin && wget https://zalora-public.s3.amazonaws.com/tinc && chmod +x tinc) - - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH - - ghc --version - - cabal --version - - travis_retry cabal update - - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config + - mkdir -p ~/.local/bin + - export PATH=$HOME/.local/bin:$PATH + - travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' + - stack --version + - stack setup --no-terminal + - (cd $HOME/.local/bin && wget https://zalora-public.s3.amazonaws.com/tinc && chmod +x tinc) script: - - ./travis.sh + - if [ "$TRAVIS_EVENT_TYPE" = "cron" ] ; then ./scripts/ci-cron.sh ; else stack test --ghc-options=-Werror --no-terminal ; fi cache: directories: - $HOME/.tinc/cache + - $HOME/.stack diff --git a/travis.sh b/scripts/ci-cron.sh similarity index 56% rename from travis.sh rename to scripts/ci-cron.sh index cd815efb..27be3e35 100755 --- a/travis.sh +++ b/scripts/ci-cron.sh @@ -1,8 +1,15 @@ #!/usr/bin/env bash +set -o nounset set -o errexit +set -o verbose -for package in $(cat sources.txt) doc/tutorial ; do +export PATH=$(stack path --bin-path):$PATH + +stack install cabal-install +cabal update + +for package in $(cat sources.txt) ; do echo testing $package pushd $package tinc From f5efaf9416bf619e4c082cee07546335127616fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Wed, 17 Aug 2016 13:37:53 +0200 Subject: [PATCH 09/34] add changelog entry for `CaptureAll` --- servant/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index dd3c33ca..f35679d1 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -1,3 +1,8 @@ +next +---- + +* Add `CaptureAll` combinator. Captures all of the remaining segments in a URL. + 0.8 --- From 95d077f5867fe70f253a54640ef03ab8a6c131dd Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Tue, 10 May 2016 17:44:01 +0200 Subject: [PATCH 10/34] Add more JS documentation. Contributed by freezeboy in PR #11 - https://github.com/haskell-servant/haskell-servant.github.io/pull/11/files --- doc/tutorial/Javascript.lhs | 355 +++++++++++++++++++++++++++++++----- 1 file changed, 313 insertions(+), 42 deletions(-) diff --git a/doc/tutorial/Javascript.lhs b/doc/tutorial/Javascript.lhs index 4054e4b3..921fe40f 100644 --- a/doc/tutorial/Javascript.lhs +++ b/doc/tutorial/Javascript.lhs @@ -151,57 +151,36 @@ so we need a `Proxy` for our API type `API'` without its `Raw` endpoint. Very similarly to how one can derive haskell functions, we can derive the javascript with just a simple function call to `jsForAPI` from -`Servant.JQuery`. +`Servant.JS`. ``` haskell apiJS :: Text -apiJS = jsForAPI api vanillaJS +apiJS = jsForAPI api jquery ``` This `Text` contains 2 Javascript functions, 'getPoint' and 'getBooks': ``` javascript -var getPoint = function(onSuccess, onError) -{ - var xhr = new XMLHttpRequest(); - xhr.open('GET', '/point', true); - xhr.setRequestHeader("Accept","application/json"); - xhr.onreadystatechange = function (e) { - if (xhr.readyState == 4) { - if (xhr.status == 204 || xhr.status == 205) { - onSuccess(); - } else if (xhr.status >= 200 && xhr.status < 300) { - var value = JSON.parse(xhr.responseText); - onSuccess(value); - } else { - var value = JSON.parse(xhr.responseText); - onError(value); - } - } - } - xhr.send(null); -} +var getPoint = function (onSuccess, onError) + { + $.ajax( + { url: '/point' + , success: onSuccess + , error: onError + , method: 'GET' + }); +}; -var getBooks = function(q, onSuccess, onError) -{ - var xhr = new XMLHttpRequest(); - xhr.open('GET', '/books' + '?q=' + encodeURIComponent(q), true); - xhr.setRequestHeader("Accept","application/json"); - xhr.onreadystatechange = function (e) { - if (xhr.readyState == 4) { - if (xhr.status == 204 || xhr.status == 205) { - onSuccess(); - } else if (xhr.status >= 200 && xhr.status < 300) { - var value = JSON.parse(xhr.responseText); - onSuccess(value); - } else { - var value = JSON.parse(xhr.responseText); - onError(value); - } - } - } - xhr.send(null); -} + +var getBooks = function (q, onSuccess, onError) + { + $.ajax( + { url: '/books' + '?q=' + encodeURIComponent(q) + , success: onSuccess + , error: onError + , method: 'GET' + }); +}; ``` We created a directory `static` that contains two static files: `index.html`, @@ -226,3 +205,295 @@ And we're good to go. You can start the `main` function of this file and go to `http://localhost:8000/`. Start typing in the name of one of the authors in our database or part of a book title, and check out how long it takes to approximate pi using the method mentioned above. + +## Customizations + +Instead of calling `jquery`, you can call its variant `jqueryWith`. +Here are the type definitions + +```haskell ignore +jquery :: JavaScriptGenerator +jqueryWith :: CommonGeneratorOptions -> JavaScriptGenerator +``` + +The `CommonGeneratorOptions` will let you define different behaviors to +change how functions are generated. Here is the definition of currently +available options: + +```haskell +data CommonGeneratorOptions = CommonGeneratorOptions + { + -- | function generating function names + functionNameBuilder :: FunctionName -> String + -- | name used when a user want to send the request body (to let you redefine it) + , requestBody :: String + -- | name of the callback parameter when the request was successful + , successCallback :: String + -- | name of the callback parameter when the request reported an error + , errorCallback :: String + -- | namespace on which we define the js function (empty mean local var) + , moduleName :: String + -- | a prefix that should be prepended to the URL in the generated JS + , urlPrefix :: String + } +``` + +This pattern is available with all supported backends, and default values are provided. + +## Vanilla support + +If you don't use JQuery for your application, you can reduce your +dependencies to simply use the `XMLHttpRequest` object from the standard API. + +Use the same code as before but simply replace the previous `apiJS` with +the following one: + +``` haskell +apiJS :: String +apiJS = jsForAPI api vanillaJS +``` + +The rest is *completely* unchanged. + +The output file is a bit different, but it has the same parameters, + +``` javascript + +var getPoint = function (onSuccess, onError) +{ + var xhr = new XMLHttpRequest(); + xhr.open('GET', '/point', true); + + xhr.onreadystatechange = function (e) { + if (xhr.readyState == 4) { + var value = JSON.parse(xhr.responseText); + if (xhr.status == 200 || xhr.status == 201) { + onSuccess(value); + } else { + onError(value); + } + } + } + xhr.send(null); +}; + +var getBooks = function (q, onSuccess, onError) +{ + var xhr = new XMLHttpRequest(); + xhr.open('GET', '/books' + '?q=' + encodeURIComponent(q), true); + + xhr.onreadystatechange = function (e) { + if (xhr.readyState == 4) { + var value = JSON.parse(xhr.responseText); + if (xhr.status == 200 || xhr.status == 201) { + onSuccess(value); + } else { + onError(value); + } + } + } + xhr.send(null); +}; +``` + +And that's all, your web service can of course be accessible from those +two clients at the same time! + +## Axios support + +### Simple usage + +If you use Axios library for your application, we support that too! + +Use the same code as before but simply replace the previous `apiJS` with +the following one: + +``` haskell +apiJS :: String +apiJS = jsForAPI api $ axios defAxiosOptions +``` + +The rest is *completely* unchanged. + +The output file is a bit different, + +``` javascript + +var getPoint = function () +{ + return axios({ url: '/point' + , method: 'get' + }); +}; + +var getBooks = function (q) +{ + return axios({ url: '/books' + '?q=' + encodeURIComponent(q) + , method: 'get' + }); +}; +``` + +**Caution:** In order to support the promise style of the API, there are no onSuccess +nor onError callback functions. + +### Defining Axios configuration + +Axios lets you define a 'configuration' to determine the behavior of the +program when the AJAX request is sent. + +We mapped this into a configuration + +``` haskell +data AxiosOptions = AxiosOptions + { -- | indicates whether or not cross-site Access-Control requests + -- should be made using credentials + withCredentials :: !Bool + -- | the name of the cookie to use as a value for xsrf token + , xsrfCookieName :: !(Maybe String) + -- | the name of the header to use as a value for xsrf token + , xsrfHeaderName :: !(Maybe String) + } +``` + +## Angular support + +### Simple usage + +You can apply the same procedure as with `vanillaJS` and `jquery`, and +generate top level functions. + +The difference is that `angular` Generator always takes an argument. + +``` haskell +apiJS :: String +apiJS = jsForAPI api $ angular defAngularOptions +``` + +The generated code will be a bit different than previous generators. An extra +argument `$http` will be added to let Angular magical Dependency Injector +operate. + +**Caution:** In order to support the promise style of the API, there are no onSuccess +nor onError callback functions. + +``` javascript + +var getPoint = function($http) +{ + return $http( + { url: '/counter' + , method: 'GET' + }); +} + +var getBooks = function($http, q) +{ + return $http( + { url: '/books' + '?q=' + encodeURIComponent(q), true); + , method: 'GET' + }); +} +``` + +You can then build your controllers easily + +``` javascript + +app.controller("MyController", function($http) { + this.getPoint = getPoint($http) + .success(/* Do something */) + .error(/* Report error */); + + this.getPoint = getBooks($http, q) + .success(/* Do something */) + .error(/* Report error */); +}); +``` + +### Service generator + +You can also generate automatically a service to wrap the whole API as +a single Angular service: + +``` javascript +app.service('MyService', function($http) { + return ({ + postCounter: function() + { + return $http( + { url: '/counter' + , method: 'POST' + }); + }, + getCounter: function() + { + return $http( + { url: '/books' + '?q=' + encodeURIComponent(q), true); + , method: 'GET' + }); + } + }); +}); +``` + +To do so, you just have to use an alternate generator. + +``` haskell +apiJS :: String +apiJS = jsForAPI api $ angularService defAngularOptions +``` + +Again, it is possible to customize some portions with the options. + +``` haskell +data AngularOptions = AngularOptions + { -- | When generating code with wrapInService, name of the service to generate, default is 'app' + serviceName :: String + , -- | beginning of the service definition + prologue :: String -> String -> String + , -- | end of the service definition + epilogue :: String + } +``` + +# Custom function name builder + +Servant comes with three name builders included: + +- camelCase (the default) +- concatCase +- snakeCase + +Keeping the JQuery as an example, let's see the impact: + +``` haskell +apiJS :: String +apiJS = jsForAPI api $ jqueryWith defCommonGeneratorOptions { functionNameBuilder: snakeCase } +``` + +This `String` contains 2 Javascript functions: + +``` javascript + +var getPoint = function (onSuccess, onError) +{ + $.ajax( + { url: '/point' + , success: onSuccess + , error: onError + , method: 'GET' + }); +}; + +var getBooks = function (q, onSuccess, onError) +{ + $.ajax( + { url: '/books' + '?q=' + encodeURIComponent(q) + , success: onSuccess + , error: onError + , method: 'GET' + }); +}; +``` + From 9e71fde7562a6c1b7edf689cb6cc8a7773e28b1e Mon Sep 17 00:00:00 2001 From: freezeboy Date: Tue, 10 May 2016 23:04:19 +0200 Subject: [PATCH 11/34] Fixing typo in Javascript.lhs --- doc/tutorial/Javascript.lhs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial/Javascript.lhs b/doc/tutorial/Javascript.lhs index 921fe40f..09c21df3 100644 --- a/doc/tutorial/Javascript.lhs +++ b/doc/tutorial/Javascript.lhs @@ -469,7 +469,7 @@ Keeping the JQuery as an example, let's see the impact: ``` haskell apiJS :: String -apiJS = jsForAPI api $ jqueryWith defCommonGeneratorOptions { functionNameBuilder: snakeCase } +apiJS = jsForAPI api $ jqueryWith defCommonGeneratorOptions { functionNameBuilder= snakeCase } ``` This `String` contains 2 Javascript functions: From 7aa550aa051d5868a09a2561ae33727409b3146b Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Thu, 12 May 2016 13:20:02 +0200 Subject: [PATCH 12/34] Make Javascript tutorial compile. --- doc/tutorial/Javascript.lhs | 179 +++++++++++++++------------- doc/tutorial/test/JavascriptSpec.hs | 7 +- servant-js/src/Servant/JS.hs | 1 + 3 files changed, 105 insertions(+), 82 deletions(-) diff --git a/doc/tutorial/Javascript.lhs b/doc/tutorial/Javascript.lhs index 09c21df3..4bc1466e 100644 --- a/doc/tutorial/Javascript.lhs +++ b/doc/tutorial/Javascript.lhs @@ -154,33 +154,33 @@ javascript with just a simple function call to `jsForAPI` from `Servant.JS`. ``` haskell -apiJS :: Text -apiJS = jsForAPI api jquery +apiJS1 :: Text +apiJS1 = jsForAPI api jquery ``` This `Text` contains 2 Javascript functions, 'getPoint' and 'getBooks': ``` javascript -var getPoint = function (onSuccess, onError) - { - $.ajax( - { url: '/point' - , success: onSuccess - , error: onError - , method: 'GET' - }); -}; +var getPoint = function(onSuccess, onError) +{ + $.ajax( + { url: '/point' + , success: onSuccess + , error: onError + , type: 'GET' + }); +} -var getBooks = function (q, onSuccess, onError) - { - $.ajax( - { url: '/books' + '?q=' + encodeURIComponent(q) - , success: onSuccess - , error: onError - , method: 'GET' - }); -}; +var getBooks = function(q, onSuccess, onError) +{ + $.ajax( + { url: '/books' + '?q=' + encodeURIComponent(q) + , success: onSuccess + , error: onError + , type: 'GET' + }); +} ``` We created a directory `static` that contains two static files: `index.html`, @@ -192,7 +192,7 @@ write the generated javascript into a file: ``` haskell writeJSFiles :: IO () writeJSFiles = do - T.writeFile "static/api.js" apiJS + T.writeFile "static/api.js" apiJS1 jq <- T.readFile =<< Language.Javascript.JQuery.file T.writeFile "static/jq.js" jq ``` @@ -220,7 +220,7 @@ The `CommonGeneratorOptions` will let you define different behaviors to change how functions are generated. Here is the definition of currently available options: -```haskell +```haskell ignore data CommonGeneratorOptions = CommonGeneratorOptions { -- | function generating function names @@ -249,8 +249,8 @@ Use the same code as before but simply replace the previous `apiJS` with the following one: ``` haskell -apiJS :: String -apiJS = jsForAPI api vanillaJS +apiJS2 :: Text +apiJS2 = jsForAPI api vanillaJS ``` The rest is *completely* unchanged. @@ -259,41 +259,50 @@ The output file is a bit different, but it has the same parameters, ``` javascript -var getPoint = function (onSuccess, onError) + +var getPoint = function(onSuccess, onError) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', '/point', true); - - xhr.onreadystatechange = function (e) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', '/point', true); + xhr.setRequestHeader(\"Accept\",\"application/json\"); + xhr.onreadystatechange = function (e) { if (xhr.readyState == 4) { + if (xhr.status == 204 || xhr.status == 205) { + onSuccess(); + } else if (xhr.status >= 200 && xhr.status < 300) { var value = JSON.parse(xhr.responseText); - if (xhr.status == 200 || xhr.status == 201) { - onSuccess(value); - } else { - onError(value); - } - } + onSuccess(value); + } else { + var value = JSON.parse(xhr.responseText); + onError(value); + } } - xhr.send(null); -}; + } + xhr.send(null); +} -var getBooks = function (q, onSuccess, onError) +var getBooks = function(q, onSuccess, onError) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', '/books' + '?q=' + encodeURIComponent(q), true); - - xhr.onreadystatechange = function (e) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', '/books' + '?q=' + encodeURIComponent(q), true); + xhr.setRequestHeader(\"Accept\",\"application/json\"); + xhr.onreadystatechange = function (e) { if (xhr.readyState == 4) { + if (xhr.status == 204 || xhr.status == 205) { + onSuccess(); + } else if (xhr.status >= 200 && xhr.status < 300) { var value = JSON.parse(xhr.responseText); - if (xhr.status == 200 || xhr.status == 201) { - onSuccess(value); - } else { - onError(value); - } - } + onSuccess(value); + } else { + var value = JSON.parse(xhr.responseText); + onError(value); + } } - xhr.send(null); -}; + } + xhr.send(null); +} + + ``` And that's all, your web service can of course be accessible from those @@ -309,8 +318,8 @@ Use the same code as before but simply replace the previous `apiJS` with the following one: ``` haskell -apiJS :: String -apiJS = jsForAPI api $ axios defAxiosOptions +apiJS3 :: Text +apiJS3 = jsForAPI api $ axios defAxiosOptions ``` The rest is *completely* unchanged. @@ -319,19 +328,23 @@ The output file is a bit different, ``` javascript -var getPoint = function () -{ - return axios({ url: '/point' - , method: 'get' - }); -}; -var getBooks = function (q) +var getPoint = function() { - return axios({ url: '/books' + '?q=' + encodeURIComponent(q) - , method: 'get' - }); -}; + return axios({ url: '/point' + , method: 'get' + }); +} + + + +var getBooks = function(q) +{ + return axios({ url: '/books' + '?q=' + encodeURIComponent(q) + , method: 'get' + }); +} + ``` **Caution:** In order to support the promise style of the API, there are no onSuccess @@ -366,8 +379,8 @@ generate top level functions. The difference is that `angular` Generator always takes an argument. ``` haskell -apiJS :: String -apiJS = jsForAPI api $ angular defAngularOptions +apiJS4 :: Text +apiJS4 = jsForAPI api $ angular defAngularOptions ``` The generated code will be a bit different than previous generators. An extra @@ -379,21 +392,25 @@ nor onError callback functions. ``` javascript + var getPoint = function($http) { return $http( - { url: '/counter' - , method: 'GET' - }); + { url: '/point' + , method: 'GET' + }); } + + var getBooks = function($http, q) { return $http( - { url: '/books' + '?q=' + encodeURIComponent(q), true); + { url: '/books' + '?q=' + encodeURIComponent(q) , method: 'GET' }); } + ``` You can then build your controllers easily @@ -440,8 +457,8 @@ app.service('MyService', function($http) { To do so, you just have to use an alternate generator. ``` haskell -apiJS :: String -apiJS = jsForAPI api $ angularService defAngularOptions +apiJS5 :: Text +apiJS5 = jsForAPI api $ angularService defAngularOptions ``` Again, it is possible to customize some portions with the options. @@ -468,32 +485,34 @@ Servant comes with three name builders included: Keeping the JQuery as an example, let's see the impact: ``` haskell -apiJS :: String -apiJS = jsForAPI api $ jqueryWith defCommonGeneratorOptions { functionNameBuilder= snakeCase } +apiJS6 :: Text +apiJS6 = jsForAPI api $ jqueryWith defCommonGeneratorOptions { functionNameBuilder= snakeCase } ``` -This `String` contains 2 Javascript functions: +This `Text` contains 2 Javascript functions: ``` javascript -var getPoint = function (onSuccess, onError) + +var get_point = function(onSuccess, onError) { $.ajax( { url: '/point' , success: onSuccess , error: onError - , method: 'GET' + , type: 'GET' }); -}; +} -var getBooks = function (q, onSuccess, onError) +var get_books = function(q, onSuccess, onError) { $.ajax( { url: '/books' + '?q=' + encodeURIComponent(q) , success: onSuccess , error: onError - , method: 'GET' + , type: 'GET' }); -}; +} + ``` diff --git a/doc/tutorial/test/JavascriptSpec.hs b/doc/tutorial/test/JavascriptSpec.hs index 2d6007a5..7dfd4cec 100644 --- a/doc/tutorial/test/JavascriptSpec.hs +++ b/doc/tutorial/test/JavascriptSpec.hs @@ -15,7 +15,10 @@ spec = do describe "apiJS" $ do it "is contained verbatim in Javascript.lhs" $ do code <- readFile "Javascript.lhs" - cs apiJS `shouldSatisfy` (`isInfixOf` code) + cs apiJS1 `shouldSatisfy` (`isInfixOf` code) + cs apiJS3 `shouldSatisfy` (`isInfixOf` code) + cs apiJS4 `shouldSatisfy` (`isInfixOf` code) + cs apiJS6 `shouldSatisfy` (`isInfixOf` code) describe "writeJSFiles" $ do it "[not a test] write apiJS to static/api.js" $ do @@ -24,7 +27,7 @@ spec = do describe "app" $ with (return app) $ do context "/api.js" $ do it "delivers apiJS" $ do - get "/api.js" `shouldRespondWith` (fromString (cs apiJS)) + get "/api.js" `shouldRespondWith` (fromString (cs apiJS1)) context "/" $ do it "delivers something" $ do diff --git a/servant-js/src/Servant/JS.hs b/servant-js/src/Servant/JS.hs index 498d45da..d11c6eb0 100644 --- a/servant-js/src/Servant/JS.hs +++ b/servant-js/src/Servant/JS.hs @@ -112,6 +112,7 @@ module Servant.JS , javascript , NoTypes , GenerateList(..) + , FunctionName(..) ) where import Prelude hiding (writeFile) From b22e4e72f968bcbad8dff9cee1b58cbc4275e884 Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Mon, 15 Aug 2016 15:39:07 -0300 Subject: [PATCH 13/34] Review fixes --- doc/tutorial/Javascript.lhs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/tutorial/Javascript.lhs b/doc/tutorial/Javascript.lhs index 4bc1466e..2d9ab6bd 100644 --- a/doc/tutorial/Javascript.lhs +++ b/doc/tutorial/Javascript.lhs @@ -224,17 +224,17 @@ available options: data CommonGeneratorOptions = CommonGeneratorOptions { -- | function generating function names - functionNameBuilder :: FunctionName -> String + functionNameBuilder :: FunctionName -> Text -- | name used when a user want to send the request body (to let you redefine it) - , requestBody :: String + , requestBody :: Text -- | name of the callback parameter when the request was successful - , successCallback :: String + , successCallback :: Text -- | name of the callback parameter when the request reported an error - , errorCallback :: String + , errorCallback :: Text -- | namespace on which we define the js function (empty mean local var) - , moduleName :: String + , moduleName :: Text -- | a prefix that should be prepended to the URL in the generated JS - , urlPrefix :: String + , urlPrefix :: Text } ``` @@ -363,9 +363,9 @@ data AxiosOptions = AxiosOptions -- should be made using credentials withCredentials :: !Bool -- | the name of the cookie to use as a value for xsrf token - , xsrfCookieName :: !(Maybe String) + , xsrfCookieName :: !(Maybe Text) -- | the name of the header to use as a value for xsrf token - , xsrfHeaderName :: !(Maybe String) + , xsrfHeaderName :: !(Maybe Text) } ``` @@ -466,11 +466,11 @@ Again, it is possible to customize some portions with the options. ``` haskell data AngularOptions = AngularOptions { -- | When generating code with wrapInService, name of the service to generate, default is 'app' - serviceName :: String + serviceName :: Text , -- | beginning of the service definition - prologue :: String -> String -> String + prologue :: Text -> Text -> Text , -- | end of the service definition - epilogue :: String + epilogue :: Text } ``` From 23493d982d0ec591f115bc4a0414fbc0dd7b61e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Wed, 17 Aug 2016 15:51:10 +0200 Subject: [PATCH 14/34] add Raw to ComprehensiveAPI (and add ComprehensiveAPIWithoutRaw) --- servant-js/test/Servant/JSSpec.hs | 2 +- .../Servant/API/Internal/Test/ComprehensiveAPI.hs | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/servant-js/test/Servant/JSSpec.hs b/servant-js/test/Servant/JSSpec.hs index 5a53b00a..7cf56be0 100644 --- a/servant-js/test/Servant/JSSpec.hs +++ b/servant-js/test/Servant/JSSpec.hs @@ -33,7 +33,7 @@ import Servant.JSSpec.CustomHeaders -- * comprehensive api -- This declaration simply checks that all instances are in place. -_ = jsForAPI comprehensiveAPI vanillaJS :: Text +_ = jsForAPI comprehensiveAPIWithoutRaw vanillaJS :: Text -- * specs diff --git a/servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs b/servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs index f568e56f..e7c15633 100644 --- a/servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs +++ b/servant/src/Servant/API/Internal/Test/ComprehensiveAPI.hs @@ -13,6 +13,13 @@ import Servant.API type GET = Get '[JSON] NoContent type ComprehensiveAPI = + ComprehensiveAPIWithoutRaw :<|> + Raw + +comprehensiveAPI :: Proxy ComprehensiveAPI +comprehensiveAPI = Proxy + +type ComprehensiveAPIWithoutRaw = GET :<|> Get '[JSON] Int :<|> Capture "foo" Int :> GET :<|> @@ -22,7 +29,6 @@ type ComprehensiveAPI = QueryParam "foo" Int :> GET :<|> QueryParams "foo" Int :> GET :<|> QueryFlag "foo" :> GET :<|> --- Raw :<|> RemoteHost :> GET :<|> ReqBody '[JSON] Int :> GET :<|> Get '[JSON] (Headers '[Header "foo" Int] NoContent) :<|> @@ -33,5 +39,5 @@ type ComprehensiveAPI = WithNamedContext "foo" '[] GET :<|> CaptureAll "foo" Int :> GET -comprehensiveAPI :: Proxy ComprehensiveAPI -comprehensiveAPI = Proxy +comprehensiveAPIWithoutRaw :: Proxy ComprehensiveAPIWithoutRaw +comprehensiveAPIWithoutRaw = Proxy From a1b23018f97add4ccc56fbb50906f8fe0aa89ab5 Mon Sep 17 00:00:00 2001 From: Alex Mason Date: Fri, 2 Sep 2016 19:46:49 +1000 Subject: [PATCH 15/34] Replace use of ToByteString with HttpApiData for GetHeaders, fixes servant/#581 * Version bump because this changes the API for GetHeaders --- servant-mock/test/Servant/MockSpec.hs | 9 +++++---- servant/CHANGELOG.md | 1 + servant/servant.cabal | 2 +- servant/src/Servant/API/ResponseHeaders.hs | 15 ++++++++------- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/servant-mock/test/Servant/MockSpec.hs b/servant-mock/test/Servant/MockSpec.hs index 7d7b32ac..dfbcc0b9 100644 --- a/servant-mock/test/Servant/MockSpec.hs +++ b/servant-mock/test/Servant/MockSpec.hs @@ -8,9 +8,7 @@ module Servant.MockSpec where import Data.Aeson as Aeson -import Data.ByteString.Conversion.To import Data.Proxy -import Data.String import GHC.Generics import Network.Wai import Servant.API @@ -40,8 +38,11 @@ data TestHeader | ArbitraryHeader deriving (Show) -instance ToByteString TestHeader where - builder = fromString . show +instance ToHttpApiData TestHeader where + toHeader = toHeader . show + toUrlPiece _ = error "ToHttpApiData.toUrlPiece not implemented for TestHeader" + toQueryParam _ = error "ToHttpApiData.toQueryParam not implemented for TestHeader" + instance Arbitrary TestHeader where arbitrary = return ArbitraryHeader diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index f35679d1..bff2ed3e 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -2,6 +2,7 @@ next ---- * Add `CaptureAll` combinator. Captures all of the remaining segments in a URL. +* replace use of `ToByteString` with `HttpApiData` for `GetHeaders` 0.8 --- diff --git a/servant/servant.cabal b/servant/servant.cabal index 3c89171f..0f308995 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -1,5 +1,5 @@ name: servant -version: 0.8 +version: 0.8.1 synopsis: A family of combinators for defining webservices APIs description: A family of combinators for defining webservices APIs and serving them diff --git a/servant/src/Servant/API/ResponseHeaders.hs b/servant/src/Servant/API/ResponseHeaders.hs index cdb7341e..d70f78b5 100644 --- a/servant/src/Servant/API/ResponseHeaders.hs +++ b/servant/src/Servant/API/ResponseHeaders.hs @@ -31,8 +31,9 @@ module Servant.API.ResponseHeaders ) where import Data.ByteString.Char8 as BS (pack, unlines, init) -import Data.ByteString.Conversion (ToByteString, toByteString', +import Data.ByteString.Conversion (--ToByteString, toByteString', FromByteString, fromByteString) +import Web.HttpApiData (ToHttpApiData,toHeader) import qualified Data.CaseInsensitive as CI import Data.Proxy import GHC.TypeLits (KnownSymbol, symbolVal) @@ -88,18 +89,18 @@ class GetHeaders ls where instance OVERLAPPING_ GetHeaders (HList '[]) where getHeaders _ = [] -instance OVERLAPPABLE_ ( KnownSymbol h, ToByteString x, GetHeaders (HList xs) ) +instance OVERLAPPABLE_ ( KnownSymbol h, ToHttpApiData x, GetHeaders (HList xs) ) => GetHeaders (HList (Header h x ': xs)) where getHeaders hdrs = case hdrs of - Header val `HCons` rest -> (headerName , toByteString' val):getHeaders rest - UndecodableHeader h `HCons` rest -> (headerName, h) : getHeaders rest + Header val `HCons` rest -> (headerName , toHeader val):getHeaders rest + UndecodableHeader h `HCons` rest -> (headerName, h) :getHeaders rest MissingHeader `HCons` rest -> getHeaders rest where headerName = CI.mk . pack $ symbolVal (Proxy :: Proxy h) instance OVERLAPPING_ GetHeaders (Headers '[] a) where getHeaders _ = [] -instance OVERLAPPABLE_ ( KnownSymbol h, GetHeaders (HList rest), ToByteString v ) +instance OVERLAPPABLE_ ( KnownSymbol h, GetHeaders (HList rest), ToHttpApiData v ) => GetHeaders (Headers (Header h v ': rest) a) where getHeaders hs = getHeaders $ getHeadersHList hs @@ -111,11 +112,11 @@ class AddHeader h v orig new addHeader :: v -> orig -> new -- ^ N.B.: The same header can't be added multiple times -instance OVERLAPPING_ ( KnownSymbol h, ToByteString v ) +instance OVERLAPPING_ ( KnownSymbol h, ToHttpApiData v ) => AddHeader h v (Headers (fst ': rest) a) (Headers (Header h v ': fst ': rest) a) where addHeader a (Headers resp heads) = Headers resp (HCons (Header a) heads) -instance OVERLAPPABLE_ ( KnownSymbol h, ToByteString v +instance OVERLAPPABLE_ ( KnownSymbol h, ToHttpApiData v , new ~ (Headers '[Header h v] a) ) => AddHeader h v a new where addHeader a resp = Headers resp (HCons (Header a) HNil) From 85a6d9714cd9d8cf9cc1dab08b46f1add25727d5 Mon Sep 17 00:00:00 2001 From: Christine Koppelt Date: Fri, 2 Sep 2016 12:43:22 +0200 Subject: [PATCH 16/34] add 'stack setup' command --- CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c4eb4705..58aaca53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,9 +8,10 @@ repository. You can use `cabal`: ./scripts/test-all.sh # Run all the tests ``` -`stack`: +Or `stack`: ```shell +stack setup # Downloads and installs a proper GHC version if necessary stack build # Install and build packages stack test # Run all the tests ``` From 9b5a564f3c151c699a6ee16c7e0dfc9564fcc1f8 Mon Sep 17 00:00:00 2001 From: Alex Mason Date: Fri, 2 Sep 2016 23:14:45 +1000 Subject: [PATCH 17/34] Remove dependency on bytestring-conversion --- servant/servant.cabal | 1 - servant/src/Servant/API/ResponseHeaders.hs | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/servant/servant.cabal b/servant/servant.cabal index 0f308995..56a2cc6e 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -54,7 +54,6 @@ library , aeson >= 0.7 && < 1.1 , attoparsec >= 0.12 && < 0.14 , bytestring >= 0.10 && < 0.11 - , bytestring-conversion >= 0.3 && < 0.4 , case-insensitive >= 1.2 && < 1.3 , http-api-data >= 0.1 && < 0.3 , http-media >= 0.4 && < 0.7 diff --git a/servant/src/Servant/API/ResponseHeaders.hs b/servant/src/Servant/API/ResponseHeaders.hs index d70f78b5..1ddba9d0 100644 --- a/servant/src/Servant/API/ResponseHeaders.hs +++ b/servant/src/Servant/API/ResponseHeaders.hs @@ -31,9 +31,8 @@ module Servant.API.ResponseHeaders ) where import Data.ByteString.Char8 as BS (pack, unlines, init) -import Data.ByteString.Conversion (--ToByteString, toByteString', - FromByteString, fromByteString) -import Web.HttpApiData (ToHttpApiData,toHeader) +import Web.HttpApiData (ToHttpApiData,toHeader + ,FromHttpApiData,parseHeader) import qualified Data.CaseInsensitive as CI import Data.Proxy import GHC.TypeLits (KnownSymbol, symbolVal) @@ -69,17 +68,17 @@ class BuildHeadersTo hs where instance OVERLAPPING_ BuildHeadersTo '[] where buildHeadersTo _ = HNil -instance OVERLAPPABLE_ ( FromByteString v, BuildHeadersTo xs, KnownSymbol h ) +instance OVERLAPPABLE_ ( FromHttpApiData v, BuildHeadersTo xs, KnownSymbol h ) => BuildHeadersTo ((Header h v) ': xs) where buildHeadersTo headers = let wantedHeader = CI.mk . pack $ symbolVal (Proxy :: Proxy h) matching = snd <$> filter (\(h, _) -> h == wantedHeader) headers in case matching of [] -> MissingHeader `HCons` buildHeadersTo headers - xs -> case fromByteString (BS.init $ BS.unlines xs) of - Nothing -> UndecodableHeader (BS.init $ BS.unlines xs) + xs -> case parseHeader (BS.init $ BS.unlines xs) of + Left _err -> UndecodableHeader (BS.init $ BS.unlines xs) `HCons` buildHeadersTo headers - Just h -> Header h `HCons` buildHeadersTo headers + Right h -> Header h `HCons` buildHeadersTo headers -- * Getting From 5bef76ed03772d271be55801f6bc480cbe8f7baf Mon Sep 17 00:00:00 2001 From: Alex Mason Date: Fri, 2 Sep 2016 23:27:37 +1000 Subject: [PATCH 18/34] Remove all use of bytestring-conversion --- servant-docs/servant-docs.cabal | 2 -- servant-docs/src/Servant/Docs/Internal.hs | 5 ++--- servant-mock/servant-mock.cabal | 1 - servant-server/servant-server.cabal | 1 - servant-server/test/Servant/ServerSpec.hs | 1 - 5 files changed, 2 insertions(+), 8 deletions(-) diff --git a/servant-docs/servant-docs.cabal b/servant-docs/servant-docs.cabal index d325e3d9..d34ac9b4 100644 --- a/servant-docs/servant-docs.cabal +++ b/servant-docs/servant-docs.cabal @@ -36,7 +36,6 @@ library , aeson , aeson-pretty , bytestring - , bytestring-conversion , case-insensitive , hashable , http-media >= 0.6 @@ -61,7 +60,6 @@ executable greet-docs build-depends: base , aeson - , bytestring-conversion , lens , servant , servant-docs diff --git a/servant-docs/src/Servant/Docs/Internal.hs b/servant-docs/src/Servant/Docs/Internal.hs index 7b181822..70530455 100644 --- a/servant-docs/src/Servant/Docs/Internal.hs +++ b/servant-docs/src/Servant/Docs/Internal.hs @@ -25,7 +25,6 @@ import Control.Arrow (second) import Control.Lens (makeLenses, mapped, over, traversed, view, (%~), (&), (.~), (<>~), (^.), (|>)) import qualified Control.Monad.Omega as Omega -import Data.ByteString.Conversion (ToByteString, toByteString) import Data.ByteString.Lazy.Char8 (ByteString) import qualified Data.ByteString.Char8 as BSC import qualified Data.CaseInsensitive as CI @@ -461,12 +460,12 @@ class AllHeaderSamples ls where instance AllHeaderSamples '[] where allHeaderToSample _ = [] -instance (ToByteString l, AllHeaderSamples ls, ToSample l, KnownSymbol h) +instance (ToHttpApiData l, AllHeaderSamples ls, ToSample l, KnownSymbol h) => AllHeaderSamples (Header h l ': ls) where allHeaderToSample _ = mkHeader (toSample (Proxy :: Proxy l)) : allHeaderToSample (Proxy :: Proxy ls) where headerName = CI.mk . cs $ symbolVal (Proxy :: Proxy h) - mkHeader (Just x) = (headerName, cs $ toByteString x) + mkHeader (Just x) = (headerName, cs $ toHeader x) mkHeader Nothing = (headerName, "") -- | Synthesise a sample value of a type, encoded in the specified media types. diff --git a/servant-mock/servant-mock.cabal b/servant-mock/servant-mock.cabal index 89ff1f6f..64e012b0 100644 --- a/servant-mock/servant-mock.cabal +++ b/servant-mock/servant-mock.cabal @@ -69,5 +69,4 @@ test-suite spec servant-server, servant-mock, aeson, - bytestring-conversion, wai diff --git a/servant-server/servant-server.cabal b/servant-server/servant-server.cabal index d055df2f..44a787fa 100644 --- a/servant-server/servant-server.cabal +++ b/servant-server/servant-server.cabal @@ -114,7 +114,6 @@ test-suite spec , aeson , base64-bytestring , bytestring - , bytestring-conversion , directory , exceptions , hspec == 2.* diff --git a/servant-server/test/Servant/ServerSpec.hs b/servant-server/test/Servant/ServerSpec.hs index 2337c258..ade5a7b3 100644 --- a/servant-server/test/Servant/ServerSpec.hs +++ b/servant-server/test/Servant/ServerSpec.hs @@ -17,7 +17,6 @@ import Control.Monad (forM_, when, unless) import Control.Monad.Trans.Except (throwE) import Data.Aeson (FromJSON, ToJSON, decode', encode) import qualified Data.ByteString.Base64 as Base64 -import Data.ByteString.Conversion () import Data.Char (toUpper) import Data.Monoid import Data.Proxy (Proxy (Proxy)) From a991cbe77c0a951a39b942fa684b9e9898ac13c2 Mon Sep 17 00:00:00 2001 From: Alex Mason Date: Fri, 2 Sep 2016 23:53:18 +1000 Subject: [PATCH 19/34] Revert version bump, update changelog --- servant/CHANGELOG.md | 2 +- servant/servant.cabal | 2 +- servant/src/Servant/API/ResponseHeaders.hs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index bff2ed3e..f5973555 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -2,7 +2,7 @@ next ---- * Add `CaptureAll` combinator. Captures all of the remaining segments in a URL. -* replace use of `ToByteString` with `HttpApiData` for `GetHeaders` +* BACKWARDS INCOMPATIBLE replace use of `ToFromByteString` with `To/FromHttpApiData` for `GetHeaders/BuildHeadersTo` 0.8 --- diff --git a/servant/servant.cabal b/servant/servant.cabal index 56a2cc6e..d3607935 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -1,5 +1,5 @@ name: servant -version: 0.8.1 +version: 0.8 synopsis: A family of combinators for defining webservices APIs description: A family of combinators for defining webservices APIs and serving them diff --git a/servant/src/Servant/API/ResponseHeaders.hs b/servant/src/Servant/API/ResponseHeaders.hs index 1ddba9d0..99bd72b6 100644 --- a/servant/src/Servant/API/ResponseHeaders.hs +++ b/servant/src/Servant/API/ResponseHeaders.hs @@ -31,8 +31,8 @@ module Servant.API.ResponseHeaders ) where import Data.ByteString.Char8 as BS (pack, unlines, init) -import Web.HttpApiData (ToHttpApiData,toHeader - ,FromHttpApiData,parseHeader) +import Web.HttpApiData (ToHttpApiData, toHeader + ,FromHttpApiData, parseHeader) import qualified Data.CaseInsensitive as CI import Data.Proxy import GHC.TypeLits (KnownSymbol, symbolVal) From dbab31508ee21f1ece729a1560d417a726e9c287 Mon Sep 17 00:00:00 2001 From: Alex Mason Date: Fri, 2 Sep 2016 23:59:36 +1000 Subject: [PATCH 20/34] Comma style is hard --- servant/src/Servant/API/ResponseHeaders.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servant/src/Servant/API/ResponseHeaders.hs b/servant/src/Servant/API/ResponseHeaders.hs index 99bd72b6..deacb90b 100644 --- a/servant/src/Servant/API/ResponseHeaders.hs +++ b/servant/src/Servant/API/ResponseHeaders.hs @@ -31,8 +31,8 @@ module Servant.API.ResponseHeaders ) where import Data.ByteString.Char8 as BS (pack, unlines, init) -import Web.HttpApiData (ToHttpApiData, toHeader - ,FromHttpApiData, parseHeader) +import Web.HttpApiData (ToHttpApiData, toHeader, + FromHttpApiData, parseHeader) import qualified Data.CaseInsensitive as CI import Data.Proxy import GHC.TypeLits (KnownSymbol, symbolVal) From 3e704362c34a730aee05f187bbdcf87ffd658214 Mon Sep 17 00:00:00 2001 From: Alex Mason Date: Sat, 3 Sep 2016 00:23:21 +1000 Subject: [PATCH 21/34] Remove error calls and replace with working implementations of ToHttpApiData --- servant-mock/test/Servant/MockSpec.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servant-mock/test/Servant/MockSpec.hs b/servant-mock/test/Servant/MockSpec.hs index dfbcc0b9..83401c73 100644 --- a/servant-mock/test/Servant/MockSpec.hs +++ b/servant-mock/test/Servant/MockSpec.hs @@ -40,8 +40,8 @@ data TestHeader instance ToHttpApiData TestHeader where toHeader = toHeader . show - toUrlPiece _ = error "ToHttpApiData.toUrlPiece not implemented for TestHeader" - toQueryParam _ = error "ToHttpApiData.toQueryParam not implemented for TestHeader" + toUrlPiece = toUrlPiece . show + toQueryParam = toQueryParam . show instance Arbitrary TestHeader where From 47eed38ee6a595ac24fd7b550c5efe9043890af5 Mon Sep 17 00:00:00 2001 From: Cornelius Diekmann Date: Fri, 2 Sep 2016 16:38:03 +0200 Subject: [PATCH 22/34] Fixed typo: s/real/realm/ Actually, I'm just trying to learn servant and I'm reading the doc for the first time. But this just looks like a typo to me. --- doc/tutorial/ApiType.lhs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tutorial/ApiType.lhs b/doc/tutorial/ApiType.lhs index 096903e8..3aa4c844 100644 --- a/doc/tutorial/ApiType.lhs +++ b/doc/tutorial/ApiType.lhs @@ -319,8 +319,8 @@ Which is used like so: ``` haskell type ProtectedAPI12 - = UserAPI -- this is public - :<|> BasicAuth "my-real" User :> UserAPI2 -- this is protected by auth + = UserAPI -- this is public + :<|> BasicAuth "my-realm" User :> UserAPI2 -- this is protected by auth ``` ### Interoperability with `wai`: `Raw` From bf824a3889f4c1483ffc6ad816f9f6ae87ddbbcc Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Fri, 2 Sep 2016 13:09:47 -0300 Subject: [PATCH 23/34] Bump version to 0.8.1 --- doc/tutorial/tutorial.cabal | 2 +- servant-client/servant-client.cabal | 2 +- servant-docs/servant-docs.cabal | 2 +- servant-foreign/servant-foreign.cabal | 2 +- servant-js/servant-js.cabal | 2 +- servant-mock/servant-mock.cabal | 2 +- servant-server/servant-server.cabal | 2 +- servant/CHANGELOG.md | 2 +- servant/servant.cabal | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/tutorial/tutorial.cabal b/doc/tutorial/tutorial.cabal index 3b90c0dc..797ff5e2 100644 --- a/doc/tutorial/tutorial.cabal +++ b/doc/tutorial/tutorial.cabal @@ -1,5 +1,5 @@ name: tutorial -version: 0.8 +version: 0.8.1 synopsis: The servant tutorial homepage: http://haskell-servant.readthedocs.org/ license: BSD3 diff --git a/servant-client/servant-client.cabal b/servant-client/servant-client.cabal index 089e1209..edbca092 100644 --- a/servant-client/servant-client.cabal +++ b/servant-client/servant-client.cabal @@ -1,5 +1,5 @@ name: servant-client -version: 0.8 +version: 0.8.1 synopsis: automatical derivation of querying functions for servant webservices description: This library lets you derive automatically Haskell functions that diff --git a/servant-docs/servant-docs.cabal b/servant-docs/servant-docs.cabal index d325e3d9..a194b763 100644 --- a/servant-docs/servant-docs.cabal +++ b/servant-docs/servant-docs.cabal @@ -1,5 +1,5 @@ name: servant-docs -version: 0.8 +version: 0.8.1 synopsis: generate API docs for your servant webservice description: Library for generating API docs from a servant API definition. diff --git a/servant-foreign/servant-foreign.cabal b/servant-foreign/servant-foreign.cabal index ea5b599a..26be4dbd 100644 --- a/servant-foreign/servant-foreign.cabal +++ b/servant-foreign/servant-foreign.cabal @@ -1,5 +1,5 @@ name: servant-foreign -version: 0.8 +version: 0.8.1 synopsis: Helpers for generating clients for servant APIs in any programming language description: Helper types and functions for generating client functions for servant APIs in any programming language diff --git a/servant-js/servant-js.cabal b/servant-js/servant-js.cabal index 726e0b4e..04ea1ff9 100644 --- a/servant-js/servant-js.cabal +++ b/servant-js/servant-js.cabal @@ -1,5 +1,5 @@ name: servant-js -version: 0.8 +version: 0.8.1 synopsis: Automatically derive javascript functions to query servant webservices. description: Automatically derive javascript functions to query servant webservices. diff --git a/servant-mock/servant-mock.cabal b/servant-mock/servant-mock.cabal index 89ff1f6f..e4610e96 100644 --- a/servant-mock/servant-mock.cabal +++ b/servant-mock/servant-mock.cabal @@ -1,5 +1,5 @@ name: servant-mock -version: 0.8 +version: 0.8.1 synopsis: Derive a mock server for free from your servant API types description: Derive a mock server for free from your servant API types diff --git a/servant-server/servant-server.cabal b/servant-server/servant-server.cabal index d055df2f..04ad5fa3 100644 --- a/servant-server/servant-server.cabal +++ b/servant-server/servant-server.cabal @@ -1,5 +1,5 @@ name: servant-server -version: 0.8 +version: 0.8.1 synopsis: A family of combinators for defining webservices APIs and serving them description: A family of combinators for defining webservices APIs and serving them diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index f35679d1..c409c960 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -1,4 +1,4 @@ -next +0.8.1 ---- * Add `CaptureAll` combinator. Captures all of the remaining segments in a URL. diff --git a/servant/servant.cabal b/servant/servant.cabal index 3c89171f..0f308995 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -1,5 +1,5 @@ name: servant -version: 0.8 +version: 0.8.1 synopsis: A family of combinators for defining webservices APIs description: A family of combinators for defining webservices APIs and serving them From 76e74f9d5a91364df6d3b191d6d1a42810ff2c9f Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Wed, 7 Sep 2016 12:31:54 -0300 Subject: [PATCH 24/34] Add instances for IsSecure --- servant/CHANGELOG.md | 4 ++++ servant/src/Servant/API/IsSecure.hs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index f5786026..41e73639 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -1,3 +1,7 @@ +next +---- +* Added Eq, Show, Read, Generic and Ord instances to IsSecure + 0.8.1 ---- diff --git a/servant/src/Servant/API/IsSecure.hs b/servant/src/Servant/API/IsSecure.hs index 031f94a7..cbf1ab79 100644 --- a/servant/src/Servant/API/IsSecure.hs +++ b/servant/src/Servant/API/IsSecure.hs @@ -1,10 +1,12 @@ {-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveGeneric #-} module Servant.API.IsSecure ( -- $issecure IsSecure(..) ) where import Data.Typeable +import GHC.Generics (Generic) -- | Was this request made over an SSL connection? -- @@ -19,7 +21,7 @@ data IsSecure = Secure -- ^ the connection to the server -- is secure (HTTPS) | NotSecure -- ^ the connection to the server -- is not secure (HTTP) - deriving Typeable + deriving (Eq, Show, Read, Generic, Ord, Typeable) -- $issecure -- From 7a7f7d7cf5d8d04e378ee5847362ce1ebd6e88f7 Mon Sep 17 00:00:00 2001 From: Christian Klinger Date: Thu, 8 Sep 2016 00:03:44 +0200 Subject: [PATCH 25/34] changed ClientM to be a Reader of ClientEnv --- doc/tutorial/Client.lhs | 27 +++----- servant-client/CHANGELOG.md | 8 +++ servant-client/servant-client.cabal | 1 + servant-client/src/Servant/Client.hs | 30 +++++---- servant-client/src/Servant/Common/Req.hs | 69 +++++++++++++------ servant-client/test/Servant/ClientSpec.hs | 82 +++++++++++------------ 6 files changed, 126 insertions(+), 91 deletions(-) diff --git a/doc/tutorial/Client.lhs b/doc/tutorial/Client.lhs index a40ca7c6..fa825e2c 100644 --- a/doc/tutorial/Client.lhs +++ b/doc/tutorial/Client.lhs @@ -15,11 +15,10 @@ need to have some language extensions and imports: module Client where -import Control.Monad.Trans.Except (ExceptT, runExceptT) import Data.Aeson import Data.Proxy import GHC.Generics -import Network.HTTP.Client (Manager, newManager, defaultManagerSettings) +import Network.HTTP.Client (newManager, defaultManagerSettings) import Servant.API import Servant.Client ``` @@ -71,19 +70,13 @@ What we are going to get with **servant-client** here is 3 functions, one to que ``` haskell position :: Int -- ^ value for "x" -> Int -- ^ value for "y" - -> Manager -- ^ the HTTP client to use - -> BaseUrl -- ^ the URL at which the API can be found - -> ExceptT ServantError IO Position + -> ClientM Position hello :: Maybe String -- ^ an optional value for "name" - -> Manager -- ^ the HTTP client to use - -> BaseUrl -- ^ the URL at which the API can be found - -> ExceptT ServantError IO HelloMessage + -> ClientM HelloMessage marketing :: ClientInfo -- ^ value for the request body - -> Manager -- ^ the HTTP client to use - -> BaseUrl -- ^ the URL at which the API can be found - -> ExceptT ServantError IO Email + -> ClientM Email ``` Each function makes available as an argument any value that the response may @@ -120,17 +113,17 @@ data BaseUrl = BaseUrl That's it. Let's now write some code that uses our client functions. ``` haskell -queries :: Manager -> BaseUrl -> ExceptT ServantError IO (Position, HelloMessage, Email) -queries manager baseurl = do - pos <- position 10 10 manager baseurl - message <- hello (Just "servant") manager baseurl - em <- marketing (ClientInfo "Alp" "alp@foo.com" 26 ["haskell", "mathematics"]) manager baseurl +queries :: ClientM (Position, HelloMessage, Email) +queries = do + pos <- position 10 10 + message <- hello (Just "servant") + em <- marketing (ClientInfo "Alp" "alp@foo.com" 26 ["haskell", "mathematics"]) return (pos, message, em) run :: IO () run = do manager <- newManager defaultManagerSettings - res <- runExceptT (queries manager (BaseUrl Http "localhost" 8081 "")) + res <- runClientM queries (ClientEnv manager (BaseUrl Http "localhost" 8081 "")) case res of Left err -> putStrLn $ "Error: " ++ show err Right (pos, message, em) -> do diff --git a/servant-client/CHANGELOG.md b/servant-client/CHANGELOG.md index 3627608d..df037a86 100644 --- a/servant-client/CHANGELOG.md +++ b/servant-client/CHANGELOG.md @@ -1,3 +1,11 @@ +0.8.1 +----- + +* BACKWARDS INCOMPATIBLE: `client` now returns a ClientM which is a Reader for + BasicEnv. BasicEnv comprises the HttpManager and BaseUrl that have had to be + passed to each method returned by `client`. + + 0.7.1 ----- diff --git a/servant-client/servant-client.cabal b/servant-client/servant-client.cabal index edbca092..c49cfe0e 100644 --- a/servant-client/servant-client.cabal +++ b/servant-client/servant-client.cabal @@ -53,6 +53,7 @@ library , text >= 1.2 && < 1.3 , transformers >= 0.3 && < 0.6 , transformers-compat >= 0.4 && < 0.6 + , mtl hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall diff --git a/servant-client/src/Servant/Client.hs b/servant-client/src/Servant/Client.hs index 18581075..0b7bdeac 100644 --- a/servant-client/src/Servant/Client.hs +++ b/servant-client/src/Servant/Client.hs @@ -20,6 +20,8 @@ module Servant.Client , client , HasClient(..) , ClientM + , runClientM + , ClientEnv (ClientEnv) , mkAuthenticateReq , ServantError(..) , module Servant.Common.BaseUrl @@ -34,7 +36,7 @@ import Data.Proxy import Data.String.Conversions import Data.Text (unpack) import GHC.TypeLits -import Network.HTTP.Client (Manager, Response) +import Network.HTTP.Client (Response) import Network.HTTP.Media import qualified Network.HTTP.Types as H import qualified Network.HTTP.Types.Header as HTTP @@ -154,17 +156,17 @@ instance OVERLAPPABLE_ -- Note [Non-Empty Content Types] (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts) ) => HasClient (Verb method status cts' a) where - type Client (Verb method status cts' a) = Manager -> BaseUrl -> ClientM a - clientWithRoute Proxy req manager baseurl = - snd <$> performRequestCT (Proxy :: Proxy ct) method req manager baseurl + type Client (Verb method status cts' a) = ClientM a + clientWithRoute Proxy req = do + snd <$> performRequestCT (Proxy :: Proxy ct) method req where method = reflectMethod (Proxy :: Proxy method) instance OVERLAPPING_ (ReflectMethod method) => HasClient (Verb method status cts NoContent) where type Client (Verb method status cts NoContent) - = Manager -> BaseUrl -> ClientM NoContent - clientWithRoute Proxy req manager baseurl = - performRequestNoBody method req manager baseurl >> return NoContent + = ClientM NoContent + clientWithRoute Proxy req = do + performRequestNoBody method req >> return NoContent where method = reflectMethod (Proxy :: Proxy method) instance OVERLAPPING_ @@ -172,10 +174,10 @@ instance OVERLAPPING_ ( MimeUnrender ct a, BuildHeadersTo ls, ReflectMethod method, cts' ~ (ct ': cts) ) => HasClient (Verb method status cts' (Headers ls a)) where type Client (Verb method status cts' (Headers ls a)) - = Manager -> BaseUrl -> ClientM (Headers ls a) - clientWithRoute Proxy req manager baseurl = do + = ClientM (Headers ls a) + clientWithRoute Proxy req = do let method = reflectMethod (Proxy :: Proxy method) - (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) method req manager baseurl + (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) method req return $ Headers { getResponse = resp , getHeadersHList = buildHeadersTo hdrs } @@ -184,10 +186,10 @@ instance OVERLAPPING_ ( BuildHeadersTo ls, ReflectMethod method ) => HasClient (Verb method status cts (Headers ls NoContent)) where type Client (Verb method status cts (Headers ls NoContent)) - = Manager -> BaseUrl -> ClientM (Headers ls NoContent) - clientWithRoute Proxy req manager baseurl = do + = ClientM (Headers ls NoContent) + clientWithRoute Proxy req = do let method = reflectMethod (Proxy :: Proxy method) - hdrs <- performRequestNoBody method req manager baseurl + hdrs <- performRequestNoBody method req return $ Headers { getResponse = NoContent , getHeadersHList = buildHeadersTo hdrs } @@ -372,7 +374,7 @@ instance (KnownSymbol sym, HasClient api) -- back the full `Response`. instance HasClient Raw where type Client Raw - = H.Method -> Manager -> BaseUrl -> ClientM (Int, ByteString, MediaType, [HTTP.Header], Response ByteString) + = H.Method -> ClientM (Int, ByteString, MediaType, [HTTP.Header], Response ByteString) clientWithRoute :: Proxy Raw -> Req -> Client Raw clientWithRoute Proxy req httpMethod = do diff --git a/servant-client/src/Servant/Common/Req.hs b/servant-client/src/Servant/Common/Req.hs index ea610cce..7a8d7a1e 100644 --- a/servant-client/src/Servant/Common/Req.hs +++ b/servant-client/src/Servant/Common/Req.hs @@ -1,7 +1,10 @@ {-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} + module Servant.Common.Req where #if !MIN_VERSION_base(4,8,0) @@ -10,8 +13,18 @@ import Control.Applicative import Control.Exception import Control.Monad import Control.Monad.Catch (MonadThrow) -import Control.Monad.IO.Class + +#if MIN_VERSION_mtl(2,2,0) +import Control.Monad.Except (MonadError(..)) +#else +import Control.Monad.Error.Class (MonadError(..)) +#endif import Control.Monad.Trans.Except + + +import GHC.Generics +import Control.Monad.IO.Class () +import Control.Monad.Reader import Data.ByteString.Lazy hiding (pack, filter, map, null, elem) import Data.String import Data.String.Conversions @@ -19,9 +32,9 @@ import Data.Proxy import Data.Text (Text) import Data.Text.Encoding import Data.Typeable -import Network.HTTP.Client hiding (Proxy, path) import Network.HTTP.Media import Network.HTTP.Types +import Network.HTTP.Client hiding (Proxy, path) import qualified Network.HTTP.Types.Header as HTTP import Network.URI hiding (path) import Servant.API.ContentTypes @@ -149,20 +162,40 @@ parseRequest url = liftM disableStatusCheck (parseUrl url) displayHttpRequest :: Method -> String displayHttpRequest httpmethod = "HTTP " ++ cs httpmethod ++ " request" -type ClientM = ExceptT ServantError IO +data ClientEnv + = ClientEnv + { manager :: Manager + , baseUrl :: BaseUrl + } -performRequest :: Method -> Req -> Manager -> BaseUrl + +-- | @ClientM@ is the monad in which client functions run. Contains the +-- 'Manager' and 'BaseUrl' used for requests in the reader environment. + +newtype ClientM a = ClientM { runClientM' :: ReaderT ClientEnv (ExceptT ServantError IO) a } + deriving ( Functor, Applicative, Monad, MonadIO, Generic + , MonadReader ClientEnv + , MonadError ServantError + ) + +runClientM :: ClientM a -> ClientEnv -> IO (Either ServantError a) +runClientM cm env = runExceptT $ (flip runReaderT env) $ runClientM' cm + + +performRequest :: Method -> Req -> ClientM ( Int, ByteString, MediaType , [HTTP.Header], Response ByteString) -performRequest reqMethod req manager reqHost = do +performRequest reqMethod req = do + m <- asks manager + reqHost <- asks baseUrl partialRequest <- liftIO $ reqToRequest req reqHost let request = partialRequest { Client.method = reqMethod } - eResponse <- liftIO $ catchConnectionError $ Client.httpLbs request manager + eResponse <- liftIO $ catchConnectionError $ Client.httpLbs request m case eResponse of Left err -> - throwE . ConnectionError $ SomeException err + throwError . ConnectionError $ SomeException err Right response -> do let status = Client.responseStatus response @@ -172,28 +205,26 @@ performRequest reqMethod req manager reqHost = do ct <- case lookup "Content-Type" $ Client.responseHeaders response of Nothing -> pure $ "application"//"octet-stream" Just t -> case parseAccept t of - Nothing -> throwE $ InvalidContentTypeHeader (cs t) body + Nothing -> throwError $ InvalidContentTypeHeader (cs t) body Just t' -> pure t' unless (status_code >= 200 && status_code < 300) $ - throwE $ FailureResponse status ct body + throwError $ FailureResponse status ct body return (status_code, body, ct, hdrs, response) -performRequestCT :: MimeUnrender ct result => - Proxy ct -> Method -> Req -> Manager -> BaseUrl +performRequestCT :: MimeUnrender ct result => Proxy ct -> Method -> Req -> ClientM ([HTTP.Header], result) -performRequestCT ct reqMethod req manager reqHost = do +performRequestCT ct reqMethod req = do let acceptCT = contentType ct (_status, respBody, respCT, hdrs, _response) <- - performRequest reqMethod (req { reqAccept = [acceptCT] }) manager reqHost - unless (matches respCT (acceptCT)) $ throwE $ UnsupportedContentType respCT respBody + performRequest reqMethod (req { reqAccept = [acceptCT] }) + unless (matches respCT (acceptCT)) $ throwError $ UnsupportedContentType respCT respBody case mimeUnrender ct respBody of - Left err -> throwE $ DecodeFailure err respCT respBody + Left err -> throwError $ DecodeFailure err respCT respBody Right val -> return (hdrs, val) -performRequestNoBody :: Method -> Req -> Manager -> BaseUrl - -> ClientM [HTTP.Header] -performRequestNoBody reqMethod req manager reqHost = do - (_status, _body, _ct, hdrs, _response) <- performRequest reqMethod req manager reqHost +performRequestNoBody :: Method -> Req -> ClientM [HTTP.Header] +performRequestNoBody reqMethod req = do + (_status, _body, _ct, hdrs, _response) <- performRequest reqMethod req return hdrs catchConnectionError :: IO a -> IO (Either ServantError a) diff --git a/servant-client/test/Servant/ClientSpec.hs b/servant-client/test/Servant/ClientSpec.hs index da7c763b..1f0be75b 100644 --- a/servant-client/test/Servant/ClientSpec.hs +++ b/servant-client/test/Servant/ClientSpec.hs @@ -32,7 +32,7 @@ import Control.Applicative ((<$>)) import Control.Arrow (left) import Control.Concurrent (forkIO, killThread, ThreadId) import Control.Exception (bracket) -import Control.Monad.Trans.Except (throwE, runExceptT) +import Control.Monad.Trans.Except (throwE ) import Data.Aeson import qualified Data.ByteString.Lazy as BS import Data.Char (chr, isPrint) @@ -123,22 +123,22 @@ type Api = api :: Proxy Api api = Proxy -getGet :: C.Manager -> BaseUrl -> SCR.ClientM Person -getDeleteEmpty :: C.Manager -> BaseUrl -> SCR.ClientM NoContent -getCapture :: String -> C.Manager -> BaseUrl -> SCR.ClientM Person -getCaptureAll :: [String] -> C.Manager -> BaseUrl -> SCR.ClientM [Person] -getBody :: Person -> C.Manager -> BaseUrl -> SCR.ClientM Person -getQueryParam :: Maybe String -> C.Manager -> BaseUrl -> SCR.ClientM Person -getQueryParams :: [String] -> C.Manager -> BaseUrl -> SCR.ClientM [Person] -getQueryFlag :: Bool -> C.Manager -> BaseUrl -> SCR.ClientM Bool -getRawSuccess :: HTTP.Method -> C.Manager -> BaseUrl +getGet :: SCR.ClientM Person +getDeleteEmpty :: SCR.ClientM NoContent +getCapture :: String -> SCR.ClientM Person +getCaptureAll :: [String] -> SCR.ClientM [Person] +getBody :: Person -> SCR.ClientM Person +getQueryParam :: Maybe String -> SCR.ClientM Person +getQueryParams :: [String] -> SCR.ClientM [Person] +getQueryFlag :: Bool -> SCR.ClientM Bool +getRawSuccess :: HTTP.Method -> SCR.ClientM (Int, BS.ByteString, MediaType, [HTTP.Header], C.Response BS.ByteString) -getRawFailure :: HTTP.Method -> C.Manager -> BaseUrl +getRawFailure :: HTTP.Method -> SCR.ClientM (Int, BS.ByteString, MediaType, [HTTP.Header], C.Response BS.ByteString) -getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])] -> C.Manager -> BaseUrl +getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])] -> SCR.ClientM (String, Maybe Int, Bool, [(String, [Rational])]) -getRespHeaders :: C.Manager -> BaseUrl -> SCR.ClientM (Headers TestHeaders Bool) -getDeleteContentType :: C.Manager -> BaseUrl -> SCR.ClientM NoContent +getRespHeaders :: SCR.ClientM (Headers TestHeaders Bool) +getDeleteContentType :: SCR.ClientM NoContent getGet :<|> getDeleteEmpty :<|> getCapture @@ -242,42 +242,42 @@ sucessSpec :: Spec sucessSpec = beforeAll (startWaiApp server) $ afterAll endWaiApp $ do it "Servant.API.Get" $ \(_, baseUrl) -> do - (left show <$> runExceptT (getGet manager baseUrl)) `shouldReturn` Right alice + (left show <$> (runClientM getGet (ClientEnv manager baseUrl))) `shouldReturn` Right alice describe "Servant.API.Delete" $ do it "allows empty content type" $ \(_, baseUrl) -> do - (left show <$> runExceptT (getDeleteEmpty manager baseUrl)) `shouldReturn` Right NoContent + (left show <$> (runClientM getDeleteEmpty (ClientEnv manager baseUrl))) `shouldReturn` Right NoContent it "allows content type" $ \(_, baseUrl) -> do - (left show <$> runExceptT (getDeleteContentType manager baseUrl)) `shouldReturn` Right NoContent + (left show <$> (runClientM getDeleteContentType (ClientEnv manager baseUrl))) `shouldReturn` Right NoContent it "Servant.API.Capture" $ \(_, baseUrl) -> do - (left show <$> runExceptT (getCapture "Paula" manager baseUrl)) `shouldReturn` Right (Person "Paula" 0) + (left show <$> (runClientM (getCapture "Paula") (ClientEnv manager baseUrl))) `shouldReturn` Right (Person "Paula" 0) it "Servant.API.CaptureAll" $ \(_, baseUrl) -> do let expected = [(Person "Paula" 0), (Person "Peta" 1)] - (left show <$> runExceptT (getCaptureAll ["Paula", "Peta"] manager baseUrl)) `shouldReturn` Right expected + (left show <$> (runClientM (getCaptureAll ["Paula", "Peta"]) (ClientEnv manager baseUrl))) `shouldReturn` Right expected it "Servant.API.ReqBody" $ \(_, baseUrl) -> do let p = Person "Clara" 42 - (left show <$> runExceptT (getBody p manager baseUrl)) `shouldReturn` Right p + (left show <$> runClientM (getBody p) (ClientEnv manager baseUrl)) `shouldReturn` Right p it "Servant.API.QueryParam" $ \(_, baseUrl) -> do - left show <$> runExceptT (getQueryParam (Just "alice") manager baseUrl) `shouldReturn` Right alice - Left FailureResponse{..} <- runExceptT (getQueryParam (Just "bob") manager baseUrl) + left show <$> runClientM (getQueryParam (Just "alice")) (ClientEnv manager baseUrl) `shouldReturn` Right alice + Left FailureResponse{..} <- runClientM (getQueryParam (Just "bob")) (ClientEnv manager baseUrl) responseStatus `shouldBe` HTTP.Status 400 "bob not found" it "Servant.API.QueryParam.QueryParams" $ \(_, baseUrl) -> do - (left show <$> runExceptT (getQueryParams [] manager baseUrl)) `shouldReturn` Right [] - (left show <$> runExceptT (getQueryParams ["alice", "bob"] manager baseUrl)) + (left show <$> runClientM (getQueryParams []) (ClientEnv manager baseUrl)) `shouldReturn` Right [] + (left show <$> runClientM (getQueryParams ["alice", "bob"]) (ClientEnv manager baseUrl)) `shouldReturn` Right [Person "alice" 0, Person "bob" 1] context "Servant.API.QueryParam.QueryFlag" $ forM_ [False, True] $ \ flag -> it (show flag) $ \(_, baseUrl) -> do - (left show <$> runExceptT (getQueryFlag flag manager baseUrl)) `shouldReturn` Right flag + (left show <$> runClientM (getQueryFlag flag) (ClientEnv manager baseUrl)) `shouldReturn` Right flag it "Servant.API.Raw on success" $ \(_, baseUrl) -> do - res <- runExceptT (getRawSuccess HTTP.methodGet manager baseUrl) + res <- runClientM (getRawSuccess HTTP.methodGet) (ClientEnv manager baseUrl) case res of Left e -> assertFailure $ show e Right (code, body, ct, _, response) -> do @@ -286,7 +286,7 @@ sucessSpec = beforeAll (startWaiApp server) $ afterAll endWaiApp $ do C.responseStatus response `shouldBe` HTTP.ok200 it "Servant.API.Raw should return a Left in case of failure" $ \(_, baseUrl) -> do - res <- runExceptT (getRawFailure HTTP.methodGet manager baseUrl) + res <- runClientM (getRawFailure HTTP.methodGet) (ClientEnv manager baseUrl) case res of Right _ -> assertFailure "expected Left, but got Right" Left e -> do @@ -294,7 +294,7 @@ sucessSpec = beforeAll (startWaiApp server) $ afterAll endWaiApp $ do Servant.Client.responseBody e `shouldBe` "rawFailure" it "Returns headers appropriately" $ \(_, baseUrl) -> do - res <- runExceptT (getRespHeaders manager baseUrl) + res <- runClientM getRespHeaders (ClientEnv manager baseUrl) case res of Left e -> assertFailure $ show e Right val -> getHeaders val `shouldBe` [("X-Example1", "1729"), ("X-Example2", "eg2")] @@ -303,7 +303,7 @@ sucessSpec = beforeAll (startWaiApp server) $ afterAll endWaiApp $ do it "works for a combination of Capture, QueryParam, QueryFlag and ReqBody" $ \(_, baseUrl) -> property $ forAllShrink pathGen shrink $ \(NonEmpty cap) num flag body -> ioProperty $ do - result <- left show <$> runExceptT (getMultiple cap num flag body manager baseUrl) + result <- left show <$> runClientM (getMultiple cap num flag body) (ClientEnv manager baseUrl) return $ result === Right (cap, num, flag, body) @@ -315,9 +315,9 @@ wrappedApiSpec = describe "error status codes" $ do let test :: (WrappedApi, String) -> Spec test (WrappedApi api, desc) = it desc $ bracket (startWaiApp $ serveW api) endWaiApp $ \(_, baseUrl) -> do - let getResponse :: C.Manager -> BaseUrl -> SCR.ClientM () + let getResponse :: SCR.ClientM () getResponse = client api - Left FailureResponse{..} <- runExceptT (getResponse manager baseUrl) + Left FailureResponse{..} <- runClientM getResponse (ClientEnv manager baseUrl) responseStatus `shouldBe` (HTTP.Status 500 "error message") in mapM_ test $ (WrappedApi (Proxy :: Proxy (Delete '[JSON] ())), "Delete") : @@ -332,42 +332,42 @@ failSpec = beforeAll (startWaiApp failServer) $ afterAll endWaiApp $ do context "client returns errors appropriately" $ do it "reports FailureResponse" $ \(_, baseUrl) -> do let (_ :<|> getDeleteEmpty :<|> _) = client api - Left res <- runExceptT (getDeleteEmpty manager baseUrl) + Left res <- runClientM getDeleteEmpty (ClientEnv manager baseUrl) case res of FailureResponse (HTTP.Status 404 "Not Found") _ _ -> return () _ -> fail $ "expected 404 response, but got " <> show res it "reports DecodeFailure" $ \(_, baseUrl) -> do let (_ :<|> _ :<|> getCapture :<|> _) = client api - Left res <- runExceptT (getCapture "foo" manager baseUrl) + Left res <- runClientM (getCapture "foo") (ClientEnv manager baseUrl) case res of DecodeFailure _ ("application/json") _ -> return () _ -> fail $ "expected DecodeFailure, but got " <> show res it "reports ConnectionError" $ \_ -> do let (getGetWrongHost :<|> _) = client api - Left res <- runExceptT (getGetWrongHost manager (BaseUrl Http "127.0.0.1" 19872 "")) + Left res <- runClientM getGetWrongHost (ClientEnv manager (BaseUrl Http "127.0.0.1" 19872 "")) case res of ConnectionError _ -> return () _ -> fail $ "expected ConnectionError, but got " <> show res it "reports UnsupportedContentType" $ \(_, baseUrl) -> do let (getGet :<|> _ ) = client api - Left res <- runExceptT (getGet manager baseUrl) + Left res <- runClientM getGet (ClientEnv manager baseUrl) case res of UnsupportedContentType ("application/octet-stream") _ -> return () _ -> fail $ "expected UnsupportedContentType, but got " <> show res it "reports InvalidContentTypeHeader" $ \(_, baseUrl) -> do let (_ :<|> _ :<|> _ :<|> _ :<|> getBody :<|> _) = client api - Left res <- runExceptT (getBody alice manager baseUrl) + Left res <- runClientM (getBody alice) (ClientEnv manager baseUrl) case res of InvalidContentTypeHeader "fooooo" _ -> return () _ -> fail $ "expected InvalidContentTypeHeader, but got " <> show res data WrappedApi where WrappedApi :: (HasServer (api :: *) '[], Server api ~ Handler a, - HasClient api, Client api ~ (C.Manager -> BaseUrl -> SCR.ClientM ())) => + HasClient api, Client api ~ SCR.ClientM ()) => Proxy api -> WrappedApi basicAuthSpec :: Spec @@ -377,14 +377,14 @@ basicAuthSpec = beforeAll (startWaiApp basicAuthServer) $ afterAll endWaiApp $ d it "Authenticates a BasicAuth protected server appropriately" $ \(_,baseUrl) -> do let getBasic = client basicAuthAPI let basicAuthData = BasicAuthData "servant" "server" - (left show <$> runExceptT (getBasic basicAuthData manager baseUrl)) `shouldReturn` Right alice + (left show <$> runClientM (getBasic basicAuthData) (ClientEnv manager baseUrl)) `shouldReturn` Right alice context "Authentication is rejected when requests are not authenticated properly" $ do it "Authenticates a BasicAuth protected server appropriately" $ \(_,baseUrl) -> do let getBasic = client basicAuthAPI let basicAuthData = BasicAuthData "not" "password" - Left FailureResponse{..} <- runExceptT (getBasic basicAuthData manager baseUrl) + Left FailureResponse{..} <- runClientM (getBasic basicAuthData) (ClientEnv manager baseUrl) responseStatus `shouldBe` HTTP.Status 403 "Forbidden" genAuthSpec :: Spec @@ -394,14 +394,14 @@ genAuthSpec = beforeAll (startWaiApp genAuthServer) $ afterAll endWaiApp $ do it "Authenticates a AuthProtect protected server appropriately" $ \(_, baseUrl) -> do let getProtected = client genAuthAPI let authRequest = mkAuthenticateReq () (\_ req -> SCR.addHeader "AuthHeader" ("cool" :: String) req) - (left show <$> runExceptT (getProtected authRequest manager baseUrl)) `shouldReturn` Right alice + (left show <$> runClientM (getProtected authRequest) (ClientEnv manager baseUrl)) `shouldReturn` Right alice context "Authentication is rejected when requests are not authenticated properly" $ do it "Authenticates a AuthProtect protected server appropriately" $ \(_, baseUrl) -> do let getProtected = client genAuthAPI let authRequest = mkAuthenticateReq () (\_ req -> SCR.addHeader "Wrong" ("header" :: String) req) - Left FailureResponse{..} <- runExceptT (getProtected authRequest manager baseUrl) + Left FailureResponse{..} <- runClientM (getProtected authRequest) (ClientEnv manager baseUrl) responseStatus `shouldBe` (HTTP.Status 401 "Unauthorized") -- * utils From 782f8e154156911d954d5f88f32ec850d73a825b Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Thu, 8 Sep 2016 17:36:10 +0300 Subject: [PATCH 26/34] Move servant-mock to https://github.com/haskell-servant/servant-mock --- servant-mock/.ghci | 1 - servant-mock/LICENSE | 30 ---- servant-mock/Setup.hs | 2 - servant-mock/example/main.hs | 26 --- servant-mock/include/overlapping-compat.h | 8 - servant-mock/servant-mock.cabal | 72 --------- servant-mock/src/Servant/Mock.hs | 188 ---------------------- servant-mock/test/Servant/MockSpec.hs | 86 ---------- servant-mock/test/Spec.hs | 1 - servant-mock/tinc.yaml | 5 - sources.txt | 1 - stack-ghc-7.8.4.yaml | 5 - stack-ghc-8.0.1.yaml | 1 - stack.yaml | 1 - 14 files changed, 427 deletions(-) delete mode 100644 servant-mock/.ghci delete mode 100644 servant-mock/LICENSE delete mode 100644 servant-mock/Setup.hs delete mode 100644 servant-mock/example/main.hs delete mode 100644 servant-mock/include/overlapping-compat.h delete mode 100644 servant-mock/servant-mock.cabal delete mode 100644 servant-mock/src/Servant/Mock.hs delete mode 100644 servant-mock/test/Servant/MockSpec.hs delete mode 100644 servant-mock/test/Spec.hs delete mode 100644 servant-mock/tinc.yaml diff --git a/servant-mock/.ghci b/servant-mock/.ghci deleted file mode 100644 index 0215492d..00000000 --- a/servant-mock/.ghci +++ /dev/null @@ -1 +0,0 @@ -:set -Wall -itest -isrc -optP-include -optPdist/build/autogen/cabal_macros.h -Iinclude diff --git a/servant-mock/LICENSE b/servant-mock/LICENSE deleted file mode 100644 index 68d30586..00000000 --- a/servant-mock/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (c) 2015-2016, Servant Contributors - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of Alp Mestanogullari nor the names of other - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/servant-mock/Setup.hs b/servant-mock/Setup.hs deleted file mode 100644 index 44671092..00000000 --- a/servant-mock/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/servant-mock/example/main.hs b/servant-mock/example/main.hs deleted file mode 100644 index a602dc88..00000000 --- a/servant-mock/example/main.hs +++ /dev/null @@ -1,26 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE TypeOperators #-} - -{-# OPTIONS_GHC -fno-warn-unused-binds #-} - -import Data.Aeson -import GHC.Generics -import Network.Wai.Handler.Warp -import Servant -import Servant.Mock -import Test.QuickCheck.Arbitrary - -newtype User = User { username :: String } - deriving (Eq, Show, Arbitrary, Generic) - -instance ToJSON User - -type API = "user" :> Get '[JSON] User - -api :: Proxy API -api = Proxy - -main :: IO () -main = run 8080 (serve api $ mock api Proxy) diff --git a/servant-mock/include/overlapping-compat.h b/servant-mock/include/overlapping-compat.h deleted file mode 100644 index eef9d4ea..00000000 --- a/servant-mock/include/overlapping-compat.h +++ /dev/null @@ -1,8 +0,0 @@ -#if __GLASGOW_HASKELL__ >= 710 -#define OVERLAPPABLE_ {-# OVERLAPPABLE #-} -#define OVERLAPPING_ {-# OVERLAPPING #-} -#else -{-# LANGUAGE OverlappingInstances #-} -#define OVERLAPPABLE_ -#define OVERLAPPING_ -#endif diff --git a/servant-mock/servant-mock.cabal b/servant-mock/servant-mock.cabal deleted file mode 100644 index e7896482..00000000 --- a/servant-mock/servant-mock.cabal +++ /dev/null @@ -1,72 +0,0 @@ -name: servant-mock -version: 0.8.1 -synopsis: Derive a mock server for free from your servant API types -description: - Derive a mock server for free from your servant API types - . - See the @Servant.Mock@ module for the documentation and an example. -homepage: http://github.com/haskell-servant/servant -license: BSD3 -license-file: LICENSE -author: Servant Contributors -maintainer: haskell-servant-maintainers@googlegroups.com -copyright: 2015-2016 Servant Contributors -category: Web -build-type: Simple -extra-source-files: include/*.h -cabal-version: >=1.10 -bug-reports: http://github.com/haskell-servant/servant/issues -source-repository head - type: git - location: http://github.com/haskell-servant/servant.git - -flag example - description: Build the example too - default: True - -library - exposed-modules: - Servant.Mock - build-depends: - base >=4.7 && <5, - bytestring >= 0.10 && <0.11, - http-types >= 0.8 && <0.10, - servant == 0.8.*, - servant-server == 0.8.*, - transformers >= 0.3 && <0.6, - QuickCheck >= 2.7 && <2.10, - wai >= 3.0 && <3.3 - hs-source-dirs: src - default-language: Haskell2010 - include-dirs: include - ghc-options: -Wall - -executable mock-app - main-is: main.hs - hs-source-dirs: example - default-language: Haskell2010 - build-depends: aeson, base, servant-mock, servant-server, QuickCheck, warp - if flag(example) - buildable: True - else - buildable: False - ghc-options: -Wall - -test-suite spec - type: exitcode-stdio-1.0 - ghc-options: -Wall - default-language: Haskell2010 - hs-source-dirs: test - main-is: Spec.hs - other-modules: - Servant.MockSpec - build-depends: - base, - hspec, - hspec-wai, - QuickCheck, - servant, - servant-server, - servant-mock, - aeson, - wai diff --git a/servant-mock/src/Servant/Mock.hs b/servant-mock/src/Servant/Mock.hs deleted file mode 100644 index 0d0f4a48..00000000 --- a/servant-mock/src/Servant/Mock.hs +++ /dev/null @@ -1,188 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} - -#include "overlapping-compat.h" - --- | --- Module : Servant.Mock --- Copyright : 2015 Alp Mestanogullari --- License : BSD3 --- --- Maintainer : Alp Mestanogullari --- Stability : experimental --- Portability : portable --- --- Automatically derive a mock webserver that implements some API type, --- just from the said API type's definition. --- --- Using this module couldn't be simpler. Given some API type, like: --- --- > type API = "user" :> Get '[JSON] User --- --- that describes your web application, all you have to do is define --- a 'Proxy' to it: --- --- > myAPI :: Proxy API --- > myAPI = Proxy --- --- and call 'mock', which has the following type: --- --- @ --- 'mock' :: 'HasMock' api context => 'Proxy' api -> 'Proxy' context -> 'Server' api --- @ --- --- What this says is, given some API type @api@ that it knows it can --- "mock", 'mock' hands you an implementation of the API type. It does so --- by having each request handler generate a random value of the --- appropriate type (@User@ in our case). All you need for this to work is --- to provide 'Arbitrary' instances for the data types returned as response --- bodies, hence appearing next to 'Delete', 'Get', 'Patch', 'Post' and 'Put'. --- --- To put this all to work and run the mock server, just call 'serve' on the --- result of 'mock' to get an 'Application' that you can then run with warp. --- --- @ --- main :: IO () --- main = Network.Wai.Handler.Warp.run 8080 $ --- 'serve' myAPI ('mock' myAPI Proxy) --- @ -module Servant.Mock ( HasMock(..) ) where - -#if !MIN_VERSION_base(4,8,0) -import Control.Applicative -#endif -import Control.Monad.IO.Class -import Data.ByteString.Lazy.Char8 (pack) -import Data.Proxy -import GHC.TypeLits -import Network.HTTP.Types.Status -import Network.Wai -import Servant -import Servant.API.ContentTypes -import Test.QuickCheck.Arbitrary (Arbitrary (..), vector) -import Test.QuickCheck.Gen (Gen, generate) - --- | 'HasMock' defines an interpretation of API types --- than turns them into random-response-generating --- request handlers, hence providing an instance for --- all the combinators of the core /servant/ library. -class HasServer api context => HasMock api context where - -- | Calling this method creates request handlers of - -- the right type to implement the API described by - -- @api@ that just generate random response values of - -- the right type. E.g: - -- - -- @ - -- type API = "user" :> Get '[JSON] User - -- :<|> "book" :> Get '[JSON] Book - -- - -- api :: Proxy API - -- api = Proxy - -- - -- -- let's say we will start with the frontend, - -- -- and hence need a placeholder server - -- server :: Server API - -- server = mock api Proxy - -- @ - -- - -- What happens here is that @'Server' API@ - -- actually "means" 2 request handlers, of the following types: - -- - -- @ - -- getUser :: Handler User - -- getBook :: Handler Book - -- @ - -- - -- So under the hood, 'mock' uses the 'IO' bit to generate - -- random values of type 'User' and 'Book' every time these - -- endpoints are requested. - mock :: Proxy api -> Proxy context -> Server api - -instance (HasMock a context, HasMock b context) => HasMock (a :<|> b) context where - mock _ context = mock (Proxy :: Proxy a) context :<|> mock (Proxy :: Proxy b) context - -instance (KnownSymbol path, HasMock rest context) => HasMock (path :> rest) context where - mock _ = mock (Proxy :: Proxy rest) - -instance (KnownSymbol s, FromHttpApiData a, HasMock rest context) => HasMock (Capture s a :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance (KnownSymbol s, FromHttpApiData a, HasMock rest context) => HasMock (CaptureAll s a :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance (AllCTUnrender ctypes a, HasMock rest context) => HasMock (ReqBody ctypes a :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance HasMock rest context => HasMock (RemoteHost :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance HasMock rest context => HasMock (IsSecure :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance HasMock rest context => HasMock (Vault :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance HasMock rest context => HasMock (HttpVersion :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance (KnownSymbol s, FromHttpApiData a, HasMock rest context) - => HasMock (QueryParam s a :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance (KnownSymbol s, FromHttpApiData a, HasMock rest context) - => HasMock (QueryParams s a :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance (KnownSymbol s, HasMock rest context) => HasMock (QueryFlag s :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance (KnownSymbol h, FromHttpApiData a, HasMock rest context) => HasMock (Header h a :> rest) context where - mock _ context = \_ -> mock (Proxy :: Proxy rest) context - -instance (Arbitrary a, KnownNat status, ReflectMethod method, AllCTRender ctypes a) - => HasMock (Verb method status ctypes a) context where - mock _ _ = mockArbitrary - -instance OVERLAPPING_ - (GetHeaders (Headers headerTypes a), Arbitrary (HList headerTypes), - Arbitrary a, KnownNat status, ReflectMethod method, AllCTRender ctypes a) - => HasMock (Verb method status ctypes (Headers headerTypes a)) context where - mock _ _ = mockArbitrary - -instance HasMock Raw context where - mock _ _ = \_req respond -> do - bdy <- genBody - respond $ responseLBS status200 [] bdy - - where genBody = pack <$> generate (vector 100 :: Gen [Char]) - -instance (HasContextEntry context (NamedContext name subContext), HasMock rest subContext) => - HasMock (WithNamedContext name subContext rest) context where - - mock _ _ = mock (Proxy :: Proxy rest) (Proxy :: Proxy subContext) - -mockArbitrary :: (MonadIO m, Arbitrary a) => m a -mockArbitrary = liftIO (generate arbitrary) - --- utility instance -instance (Arbitrary (HList ls), Arbitrary a) - => Arbitrary (Headers ls a) where - arbitrary = Headers <$> arbitrary <*> arbitrary - -instance Arbitrary (HList '[]) where - arbitrary = pure HNil - -instance (Arbitrary a, Arbitrary (HList hs)) - => Arbitrary (HList (Header h a ': hs)) where - arbitrary = HCons <$> fmap Header arbitrary <*> arbitrary - -instance Arbitrary NoContent where - arbitrary = pure NoContent diff --git a/servant-mock/test/Servant/MockSpec.hs b/servant-mock/test/Servant/MockSpec.hs deleted file mode 100644 index 83401c73..00000000 --- a/servant-mock/test/Servant/MockSpec.hs +++ /dev/null @@ -1,86 +0,0 @@ -{-# LANGUAGE ConstraintKinds #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TypeOperators #-} - -module Servant.MockSpec where - -import Data.Aeson as Aeson -import Data.Proxy -import GHC.Generics -import Network.Wai -import Servant.API -import Test.Hspec hiding (pending) -import Test.Hspec.Wai -import Test.QuickCheck - -import Servant -import Servant.API.Internal.Test.ComprehensiveAPI -import Servant.Mock - --- This declaration simply checks that all instances are in place. -_ = mock comprehensiveAPI (Proxy :: Proxy '[NamedContext "foo" '[]]) - -data Body - = Body - | ArbitraryBody - deriving (Generic) - -instance ToJSON Body - -instance Arbitrary Body where - arbitrary = return ArbitraryBody - -data TestHeader - = TestHeader - | ArbitraryHeader - deriving (Show) - -instance ToHttpApiData TestHeader where - toHeader = toHeader . show - toUrlPiece = toUrlPiece . show - toQueryParam = toQueryParam . show - - -instance Arbitrary TestHeader where - arbitrary = return ArbitraryHeader - -spec :: Spec -spec = do - describe "mock" $ do - context "Get" $ do - let api :: Proxy (Get '[JSON] Body) - api = Proxy - app = serve api (mock api Proxy) - with (return app) $ do - it "serves arbitrary response bodies" $ do - get "/" `shouldRespondWith` 200{ - matchBody = Just $ Aeson.encode ArbitraryBody - } - - context "response headers" $ do - let withHeader :: Proxy (Get '[JSON] (Headers '[Header "foo" TestHeader] Body)) - withHeader = Proxy - withoutHeader :: Proxy (Get '[JSON] (Headers '[] Body)) - withoutHeader = Proxy - toApp :: (HasMock api '[]) => Proxy api -> IO Application - toApp api = return $ serve api (mock api (Proxy :: Proxy '[])) - with (toApp withHeader) $ do - it "serves arbitrary response bodies" $ do - get "/" `shouldRespondWith` 200{ - matchHeaders = return $ MatchHeader $ \ h -> - if h == [("Content-Type", "application/json"), ("foo", "ArbitraryHeader")] - then Nothing - else Just ("headers not correct\n") - } - - with (toApp withoutHeader) $ do - it "works for no additional headers" $ do - get "/" `shouldRespondWith` 200{ - matchHeaders = return $ MatchHeader $ \ h -> - if h == [("Content-Type", "application/json")] - then Nothing - else Just ("headers not correct\n") - } diff --git a/servant-mock/test/Spec.hs b/servant-mock/test/Spec.hs deleted file mode 100644 index a824f8c3..00000000 --- a/servant-mock/test/Spec.hs +++ /dev/null @@ -1 +0,0 @@ -{-# OPTIONS_GHC -F -pgmF hspec-discover #-} diff --git a/servant-mock/tinc.yaml b/servant-mock/tinc.yaml deleted file mode 100644 index ec6d448f..00000000 --- a/servant-mock/tinc.yaml +++ /dev/null @@ -1,5 +0,0 @@ -dependencies: - - name: servant - path: ../servant - - name: servant-server - path: ../servant-server diff --git a/sources.txt b/sources.txt index 06ff7ed8..6c75de5e 100644 --- a/sources.txt +++ b/sources.txt @@ -4,4 +4,3 @@ servant-client servant-docs servant-foreign servant-js -servant-mock diff --git a/stack-ghc-7.8.4.yaml b/stack-ghc-7.8.4.yaml index 0fe58482..c934dc41 100644 --- a/stack-ghc-7.8.4.yaml +++ b/stack-ghc-7.8.4.yaml @@ -5,7 +5,6 @@ packages: - servant-docs/ - servant-foreign/ - servant-js/ -- servant-mock/ - servant-server/ extra-deps: - base-compat-0.9.1 @@ -18,10 +17,6 @@ extra-deps: - hspec-expectations-0.7.2 - http-api-data-0.2.2 - primitive-0.6.1.0 -- servant-0.7.1 -- servant-client-0.7.1 -- servant-docs-0.7.1 -- servant-server-0.7.1 - should-not-typecheck-2.1.0 - time-locale-compat-0.1.1.1 - wai-app-static-3.1.5 diff --git a/stack-ghc-8.0.1.yaml b/stack-ghc-8.0.1.yaml index 8861e1a9..c5c8fa27 100644 --- a/stack-ghc-8.0.1.yaml +++ b/stack-ghc-8.0.1.yaml @@ -5,7 +5,6 @@ packages: - servant-docs/ - servant-foreign/ - servant-js/ -- servant-mock/ - servant-server/ extra-deps: [] flags: {} diff --git a/stack.yaml b/stack.yaml index 95599455..a1e5f8c9 100644 --- a/stack.yaml +++ b/stack.yaml @@ -5,7 +5,6 @@ packages: - servant-docs/ - servant-foreign/ - servant-js/ -- servant-mock/ - servant-server/ - doc/tutorial extra-deps: From f44b336bf10e9f5cb6d27a8c506e8b7cf01f33b1 Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Wed, 31 Aug 2016 13:32:12 +0300 Subject: [PATCH 27/34] Support http-api-data-0.3 --- servant-client/servant-client.cabal | 2 +- servant-server/servant-server.cabal | 2 +- servant-server/src/Servant/Server/Internal.hs | 7 +++++++ servant/servant.cabal | 2 +- stack.yaml | 1 + 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/servant-client/servant-client.cabal b/servant-client/servant-client.cabal index c49cfe0e..03155d96 100644 --- a/servant-client/servant-client.cabal +++ b/servant-client/servant-client.cabal @@ -41,7 +41,7 @@ library , base64-bytestring >= 1.0.0.1 && < 1.1 , bytestring >= 0.10 && < 0.11 , exceptions >= 0.8 && < 0.9 - , http-api-data >= 0.1 && < 0.3 + , http-api-data >= 0.1 && < 0.4 , http-client >= 0.4.18.1 && < 0.6 , http-client-tls >= 0.2.2 && < 0.4 , http-media >= 0.6.2 && < 0.7 diff --git a/servant-server/servant-server.cabal b/servant-server/servant-server.cabal index 29f3d8d3..284e7416 100644 --- a/servant-server/servant-server.cabal +++ b/servant-server/servant-server.cabal @@ -52,7 +52,7 @@ library , base64-bytestring >= 1.0 && < 1.1 , bytestring >= 0.10 && < 0.11 , containers >= 0.5 && < 0.6 - , http-api-data >= 0.1 && < 0.3 + , http-api-data >= 0.1 && < 0.4 , http-types >= 0.8 && < 0.10 , network-uri >= 2.6 && < 2.7 , mtl >= 2 && < 2.3 diff --git a/servant-server/src/Servant/Server/Internal.hs b/servant-server/src/Servant/Server/Internal.hs index de4a237a..2c94ef1c 100644 --- a/servant-server/src/Servant/Server/Internal.hs +++ b/servant-server/src/Servant/Server/Internal.hs @@ -43,10 +43,17 @@ import Network.Wai (Application, Request, Response, import Prelude () import Prelude.Compat import Web.HttpApiData (FromHttpApiData) +#if MIN_VERSION_http_api_data(0,3,0) +import Web.Internal.HttpApiData (parseHeaderMaybe, + parseQueryParamMaybe, + parseUrlPieceMaybe, + parseUrlPieces) +#else import Web.HttpApiData.Internal (parseHeaderMaybe, parseQueryParamMaybe, parseUrlPieceMaybe, parseUrlPieces) +#endif import Servant.API ((:<|>) (..), (:>), BasicAuth, Capture, CaptureAll, Verb, diff --git a/servant/servant.cabal b/servant/servant.cabal index 56a2cc6e..fb1cef5e 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -55,7 +55,7 @@ library , attoparsec >= 0.12 && < 0.14 , bytestring >= 0.10 && < 0.11 , case-insensitive >= 1.2 && < 1.3 - , http-api-data >= 0.1 && < 0.3 + , http-api-data >= 0.1 && < 0.4 , http-media >= 0.4 && < 0.7 , http-types >= 0.8 && < 0.10 , mtl >= 2.0 && < 2.3 diff --git a/stack.yaml b/stack.yaml index a1e5f8c9..70a45e22 100644 --- a/stack.yaml +++ b/stack.yaml @@ -8,4 +8,5 @@ packages: - servant-server/ - doc/tutorial extra-deps: +- http-api-data-0.3 resolver: lts-6.0 From 0870b3b2f55166237a4382481c7fe306f33ba733 Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Thu, 1 Sep 2016 21:24:49 -0300 Subject: [PATCH 28/34] Remove FromFormUrlEncoded and ToFormUrlEncoded. In favor of FromForm and ToForm from the new version of http-api-data. --- servant-client/servant-client.cabal | 1 + servant-client/test/Servant/ClientSpec.hs | 26 +++----- servant/CHANGELOG.md | 3 +- servant/src/Servant/API.hs | 4 +- servant/src/Servant/API/ContentTypes.hs | 67 ++++---------------- servant/test/Servant/API/ContentTypesSpec.hs | 17 ----- 6 files changed, 24 insertions(+), 94 deletions(-) diff --git a/servant-client/servant-client.cabal b/servant-client/servant-client.cabal index 03155d96..c0cf8bb9 100644 --- a/servant-client/servant-client.cabal +++ b/servant-client/servant-client.cabal @@ -78,6 +78,7 @@ test-suite spec , bytestring , deepseq , hspec == 2.* + , http-api-data , http-client , http-media , http-types diff --git a/servant-client/test/Servant/ClientSpec.hs b/servant-client/test/Servant/ClientSpec.hs index 1f0be75b..c3b957d4 100644 --- a/servant-client/test/Servant/ClientSpec.hs +++ b/servant-client/test/Servant/ClientSpec.hs @@ -30,7 +30,7 @@ module Servant.ClientSpec where import Control.Applicative ((<$>)) #endif import Control.Arrow (left) -import Control.Concurrent (forkIO, killThread, ThreadId) +import Control.Concurrent (ThreadId, forkIO, killThread) import Control.Exception (bracket) import Control.Monad.Trans.Except (throwE ) import Data.Aeson @@ -39,19 +39,20 @@ import Data.Char (chr, isPrint) import Data.Foldable (forM_) import Data.Monoid hiding (getLast) import Data.Proxy -import qualified Data.Text as T import GHC.Generics (Generic) import qualified Network.HTTP.Client as C import Network.HTTP.Media import qualified Network.HTTP.Types as HTTP import Network.Socket -import Network.Wai (Request, requestHeaders, responseLBS) +import Network.Wai (Request, requestHeaders, + responseLBS) import Network.Wai.Handler.Warp import System.IO.Unsafe (unsafePerformIO) import Test.Hspec import Test.Hspec.QuickCheck import Test.HUnit import Test.QuickCheck +import Web.FormUrlEncoded (FromForm, ToForm) import Servant.API import Servant.API.Internal.Test.ComprehensiveAPI @@ -82,19 +83,8 @@ data Person = Person { instance ToJSON Person instance FromJSON Person -instance ToFormUrlEncoded Person where - toFormUrlEncoded Person{..} = - [("name", T.pack name), ("age", T.pack (show age))] - -lookupEither :: (Show a, Eq a) => a -> [(a,b)] -> Either String b -lookupEither x xs = do - maybe (Left $ "could not find key " <> show x) return $ lookup x xs - -instance FromFormUrlEncoded Person where - fromFormUrlEncoded xs = do - n <- lookupEither "name" xs - a <- lookupEither "age" xs - return $ Person (T.unpack n) (read $ T.unpack a) +instance ToForm Person where +instance FromForm Person where alice :: Person alice = Person "Alice" 42 @@ -131,9 +121,9 @@ getBody :: Person -> SCR.ClientM Person getQueryParam :: Maybe String -> SCR.ClientM Person getQueryParams :: [String] -> SCR.ClientM [Person] getQueryFlag :: Bool -> SCR.ClientM Bool -getRawSuccess :: HTTP.Method +getRawSuccess :: HTTP.Method -> SCR.ClientM (Int, BS.ByteString, MediaType, [HTTP.Header], C.Response BS.ByteString) -getRawFailure :: HTTP.Method +getRawFailure :: HTTP.Method -> SCR.ClientM (Int, BS.ByteString, MediaType, [HTTP.Header], C.Response BS.ByteString) getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])] -> SCR.ClientM (String, Maybe Int, Bool, [(String, [Rational])]) diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index 41e73639..d07c9477 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -1,12 +1,13 @@ next ---- * Added Eq, Show, Read, Generic and Ord instances to IsSecure +* BACKWARDS INCOMPATIBLE replace use of `ToFromByteString` with `To/FromHttpApiData` for `GetHeaders/BuildHeadersTo` +* BACKWARD INCOMPATIBLE: Moved `From/ToFormUrlEncoded` classes, which were renamed to `From/ToForm` to `http-api-data` 0.8.1 ---- * Add `CaptureAll` combinator. Captures all of the remaining segments in a URL. -* BACKWARDS INCOMPATIBLE replace use of `ToFromByteString` with `To/FromHttpApiData` for `GetHeaders/BuildHeadersTo` 0.8 --- diff --git a/servant/src/Servant/API.hs b/servant/src/Servant/API.hs index cbb0db09..2eb0d8dc 100644 --- a/servant/src/Servant/API.hs +++ b/servant/src/Servant/API.hs @@ -62,10 +62,10 @@ import Servant.API.Alternative ((:<|>) (..)) import Servant.API.BasicAuth (BasicAuth,BasicAuthData(..)) import Servant.API.Capture (Capture, CaptureAll) import Servant.API.ContentTypes (Accept (..), FormUrlEncoded, - FromFormUrlEncoded (..), JSON, + JSON, MimeRender (..), NoContent (NoContent), MimeUnrender (..), OctetStream, - PlainText, ToFormUrlEncoded (..)) + PlainText) import Servant.API.Experimental.Auth (AuthProtect) import Servant.API.Header (Header (..)) import Servant.API.HttpVersion (HttpVersion (..)) diff --git a/servant/src/Servant/API/ContentTypes.hs b/servant/src/Servant/API/ContentTypes.hs index f10e2ba1..6969f7ee 100644 --- a/servant/src/Servant/API/ContentTypes.hs +++ b/servant/src/Servant/API/ContentTypes.hs @@ -66,15 +66,14 @@ module Servant.API.ContentTypes , AllMime(..) , AllMimeRender(..) , AllMimeUnrender(..) - , FromFormUrlEncoded(..) - , ToFormUrlEncoded(..) , eitherDecodeLenient , canHandleAcceptH ) where import Control.Arrow (left) import Control.Monad.Compat -import Data.Aeson (FromJSON(..), ToJSON(..), encode) +import Data.Aeson (FromJSON (..), ToJSON (..), + encode) import Data.Aeson.Parser (value) import Data.Aeson.Types (parseEither) import Data.Attoparsec.ByteString.Char8 (endOfInput, parseOnly, @@ -82,10 +81,8 @@ import Data.Attoparsec.ByteString.Char8 (endOfInput, parseOnly, import qualified Data.ByteString as BS import Data.ByteString.Lazy (ByteString, fromStrict, toStrict) -import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy.Char8 as BC import Data.Maybe (isJust) -import Data.Monoid.Compat import Data.String.Conversions (cs) import qualified Data.Text as TextS import qualified Data.Text.Encoding as TextS @@ -94,8 +91,9 @@ import qualified Data.Text.Lazy.Encoding as TextL import Data.Typeable import GHC.Generics (Generic) import qualified Network.HTTP.Media as M -import Network.URI (escapeURIString, - isUnreserved, unEscapeString) +import Web.FormUrlEncoded (FromForm, ToForm, + urlEncodeAsForm, + urlDecodeAsForm) import Prelude () import Prelude.Compat @@ -290,12 +288,12 @@ instance OVERLAPPABLE_ ToJSON a => MimeRender JSON a where mimeRender _ = encode --- | @encodeFormUrlEncoded . toFormUrlEncoded@ +-- | @urlEncodeAsForm" -- Note that the @mimeUnrender p (mimeRender p x) == Right x@ law only -- holds if every element of x is non-null (i.e., not @("", "")@) instance OVERLAPPABLE_ - ToFormUrlEncoded a => MimeRender FormUrlEncoded a where - mimeRender _ = encodeFormUrlEncoded . toFormUrlEncoded + ToForm a => MimeRender FormUrlEncoded a where + mimeRender _ = urlEncodeAsForm -- | `TextL.encodeUtf8` instance MimeRender PlainText TextL.Text where @@ -348,11 +346,11 @@ eitherDecodeLenient input = instance FromJSON a => MimeUnrender JSON a where mimeUnrender _ = eitherDecodeLenient --- | @decodeFormUrlEncoded >=> fromFormUrlEncoded@ +-- | @urlDecodeAsForm@ -- Note that the @mimeUnrender p (mimeRender p x) == Right x@ law only -- holds if every element of x is non-null (i.e., not @("", "")@) -instance FromFormUrlEncoded a => MimeUnrender FormUrlEncoded a where - mimeUnrender _ = decodeFormUrlEncoded >=> fromFormUrlEncoded +instance FromForm a => MimeUnrender FormUrlEncoded a where + mimeUnrender _ = left TextS.unpack . urlDecodeAsForm -- | @left show . TextL.decodeUtf8'@ instance MimeUnrender PlainText TextL.Text where @@ -375,49 +373,6 @@ instance MimeUnrender OctetStream BS.ByteString where mimeUnrender _ = Right . toStrict --------------------------------------------------------------------------- --- * FormUrlEncoded - --- | A type that can be converted to @application/x-www-form-urlencoded@ -class ToFormUrlEncoded a where - toFormUrlEncoded :: a -> [(TextS.Text, TextS.Text)] - -instance ToFormUrlEncoded [(TextS.Text, TextS.Text)] where - toFormUrlEncoded = id - --- | A type that can be converted from @application/x-www-form-urlencoded@, --- with the possibility of failure. -class FromFormUrlEncoded a where - fromFormUrlEncoded :: [(TextS.Text, TextS.Text)] -> Either String a - -instance FromFormUrlEncoded [(TextS.Text, TextS.Text)] where - fromFormUrlEncoded = return - -encodeFormUrlEncoded :: [(TextS.Text, TextS.Text)] -> ByteString -encodeFormUrlEncoded xs = - let escape :: TextS.Text -> ByteString - escape = cs . escapeURIString isUnreserved . cs - encodePair :: (TextS.Text, TextS.Text) -> ByteString - encodePair (k, "") = escape k - encodePair (k, v) = escape k <> "=" <> escape v - in B.intercalate "&" $ map encodePair xs - -decodeFormUrlEncoded :: ByteString -> Either String [(TextS.Text, TextS.Text)] -decodeFormUrlEncoded "" = return [] -decodeFormUrlEncoded q = do - let xs :: [TextS.Text] - xs = TextS.splitOn "&" . cs $ q - parsePair :: TextS.Text -> Either String (TextS.Text, TextS.Text) - parsePair p = - case TextS.splitOn "=" p of - [k,v] -> return ( unescape k - , unescape v - ) - [k] -> return ( unescape k, "" ) - _ -> Left $ "not a valid pair: " <> cs p - unescape :: TextS.Text -> TextS.Text - unescape = cs . unEscapeString . cs . TextS.intercalate "%20" . TextS.splitOn "+" - mapM parsePair xs -- $setup -- >>> import Servant.API diff --git a/servant/test/Servant/API/ContentTypesSpec.hs b/servant/test/Servant/API/ContentTypesSpec.hs index 1a155b5c..a0ae13d7 100644 --- a/servant/test/Servant/API/ContentTypesSpec.hs +++ b/servant/test/Servant/API/ContentTypesSpec.hs @@ -11,7 +11,6 @@ module Servant.API.ContentTypesSpec where import Prelude () import Prelude.Compat -import Control.Arrow import Data.Aeson import Data.ByteString.Char8 (ByteString, append, pack) import qualified Data.ByteString.Lazy as BSL @@ -25,7 +24,6 @@ import Data.String.Conversions (cs) import qualified Data.Text as TextS import qualified Data.Text.Lazy as TextL import GHC.Generics -import Network.URL (exportParams, importParams) import Test.Hspec import Test.QuickCheck import "quickcheck-instances" Test.QuickCheck.Instances () @@ -68,21 +66,6 @@ spec = describe "Servant.API.ContentTypes" $ do it "has mimeUnrender reverse mimeRender for valid top-level json " $ do property $ \x -> mimeUnrender p (mimeRender p x) == Right (x::SomeData) - describe "The FormUrlEncoded Content-Type type" $ do - let p = Proxy :: Proxy FormUrlEncoded - - it "has mimeUnrender reverse mimeRender" $ do - property $ \x -> mempty `notElem` x - ==> mimeUnrender p (mimeRender p x) == Right (x::[(TextS.Text,TextS.Text)]) - - it "has mimeUnrender reverse exportParams (Network.URL)" $ do - property $ \x -> mempty `notElem` x - ==> (mimeUnrender p . cs . exportParams . map (cs *** cs) $ x) == Right (x::[(TextS.Text,TextS.Text)]) - - it "has importParams (Network.URL) reverse mimeRender" $ do - property $ \x -> mempty `notElem` x - ==> (fmap (map (cs *** cs)) . importParams . cs . mimeRender p $ x) == Just (x::[(TextS.Text,TextS.Text)]) - describe "The PlainText Content-Type type" $ do let p = Proxy :: Proxy PlainText From 7cdebce96b6793405e935bf177159cefb13b4c82 Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Thu, 1 Sep 2016 21:45:05 -0300 Subject: [PATCH 29/34] Bounds and stack files --- servant/servant.cabal | 2 +- stack-ghc-7.8.4.yaml | 3 ++- stack-ghc-8.0.1.yaml | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/servant/servant.cabal b/servant/servant.cabal index fb1cef5e..6d3030bf 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -55,7 +55,7 @@ library , attoparsec >= 0.12 && < 0.14 , bytestring >= 0.10 && < 0.11 , case-insensitive >= 1.2 && < 1.3 - , http-api-data >= 0.1 && < 0.4 + , http-api-data >= 0.3 && < 0.4 , http-media >= 0.4 && < 0.7 , http-types >= 0.8 && < 0.10 , mtl >= 2.0 && < 2.3 diff --git a/stack-ghc-7.8.4.yaml b/stack-ghc-7.8.4.yaml index c934dc41..15c1245a 100644 --- a/stack-ghc-7.8.4.yaml +++ b/stack-ghc-7.8.4.yaml @@ -15,9 +15,10 @@ extra-deps: - hspec-core-2.2.3 - hspec-discover-2.2.3 - hspec-expectations-0.7.2 -- http-api-data-0.2.2 +- http-api-data-0.3 - primitive-0.6.1.0 - should-not-typecheck-2.1.0 - time-locale-compat-0.1.1.1 +- uri-bytestring-0.2.2.0 - wai-app-static-3.1.5 resolver: lts-2.22 diff --git a/stack-ghc-8.0.1.yaml b/stack-ghc-8.0.1.yaml index c5c8fa27..21506764 100644 --- a/stack-ghc-8.0.1.yaml +++ b/stack-ghc-8.0.1.yaml @@ -6,5 +6,7 @@ packages: - servant-foreign/ - servant-js/ - servant-server/ -extra-deps: [] +extra-deps: +- http-api-data-0.3 +- uri-bytestring-0.2.2.0 flags: {} From 501212e6b9b141691090161901d46661a4706cf3 Mon Sep 17 00:00:00 2001 From: "Julian K. Arni" Date: Fri, 2 Sep 2016 10:25:22 -0300 Subject: [PATCH 30/34] Review fixes --- servant-client/servant-client.cabal | 2 +- servant-client/test/Servant/ClientSpec.hs | 9 ++++----- servant-server/servant-server.cabal | 2 +- servant-server/src/Servant/Server/Internal.hs | 11 +---------- servant/src/Servant/API/ContentTypes.hs | 5 ++--- 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/servant-client/servant-client.cabal b/servant-client/servant-client.cabal index c0cf8bb9..327f3d2d 100644 --- a/servant-client/servant-client.cabal +++ b/servant-client/servant-client.cabal @@ -41,7 +41,7 @@ library , base64-bytestring >= 1.0.0.1 && < 1.1 , bytestring >= 0.10 && < 0.11 , exceptions >= 0.8 && < 0.9 - , http-api-data >= 0.1 && < 0.4 + , http-api-data >= 0.3 && < 0.4 , http-client >= 0.4.18.1 && < 0.6 , http-client-tls >= 0.2.2 && < 0.4 , http-media >= 0.6.2 && < 0.7 diff --git a/servant-client/test/Servant/ClientSpec.hs b/servant-client/test/Servant/ClientSpec.hs index c3b957d4..98d9e9b5 100644 --- a/servant-client/test/Servant/ClientSpec.hs +++ b/servant-client/test/Servant/ClientSpec.hs @@ -30,7 +30,7 @@ module Servant.ClientSpec where import Control.Applicative ((<$>)) #endif import Control.Arrow (left) -import Control.Concurrent (ThreadId, forkIO, killThread) +import Control.Concurrent (forkIO, killThread, ThreadId) import Control.Exception (bracket) import Control.Monad.Trans.Except (throwE ) import Data.Aeson @@ -44,8 +44,7 @@ import qualified Network.HTTP.Client as C import Network.HTTP.Media import qualified Network.HTTP.Types as HTTP import Network.Socket -import Network.Wai (Request, requestHeaders, - responseLBS) +import Network.Wai (Request, requestHeaders, responseLBS) import Network.Wai.Handler.Warp import System.IO.Unsafe (unsafePerformIO) import Test.Hspec @@ -121,9 +120,9 @@ getBody :: Person -> SCR.ClientM Person getQueryParam :: Maybe String -> SCR.ClientM Person getQueryParams :: [String] -> SCR.ClientM [Person] getQueryFlag :: Bool -> SCR.ClientM Bool -getRawSuccess :: HTTP.Method +getRawSuccess :: HTTP.Method -> SCR.ClientM (Int, BS.ByteString, MediaType, [HTTP.Header], C.Response BS.ByteString) -getRawFailure :: HTTP.Method +getRawFailure :: HTTP.Method -> SCR.ClientM (Int, BS.ByteString, MediaType, [HTTP.Header], C.Response BS.ByteString) getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])] -> SCR.ClientM (String, Maybe Int, Bool, [(String, [Rational])]) diff --git a/servant-server/servant-server.cabal b/servant-server/servant-server.cabal index 284e7416..f9b5f45f 100644 --- a/servant-server/servant-server.cabal +++ b/servant-server/servant-server.cabal @@ -52,7 +52,7 @@ library , base64-bytestring >= 1.0 && < 1.1 , bytestring >= 0.10 && < 0.11 , containers >= 0.5 && < 0.6 - , http-api-data >= 0.1 && < 0.4 + , http-api-data >= 0.3 && < 0.4 , http-types >= 0.8 && < 0.10 , network-uri >= 2.6 && < 2.7 , mtl >= 2 && < 2.3 diff --git a/servant-server/src/Servant/Server/Internal.hs b/servant-server/src/Servant/Server/Internal.hs index 2c94ef1c..fc91267b 100644 --- a/servant-server/src/Servant/Server/Internal.hs +++ b/servant-server/src/Servant/Server/Internal.hs @@ -42,19 +42,10 @@ import Network.Wai (Application, Request, Response, responseLBS, vault) import Prelude () import Prelude.Compat -import Web.HttpApiData (FromHttpApiData) -#if MIN_VERSION_http_api_data(0,3,0) -import Web.Internal.HttpApiData (parseHeaderMaybe, +import Web.HttpApiData (FromHttpApiData, parseHeaderMaybe, parseQueryParamMaybe, parseUrlPieceMaybe, parseUrlPieces) -#else -import Web.HttpApiData.Internal (parseHeaderMaybe, - parseQueryParamMaybe, - parseUrlPieceMaybe, - parseUrlPieces) -#endif - import Servant.API ((:<|>) (..), (:>), BasicAuth, Capture, CaptureAll, Verb, ReflectMethod(reflectMethod), diff --git a/servant/src/Servant/API/ContentTypes.hs b/servant/src/Servant/API/ContentTypes.hs index 6969f7ee..044f1c59 100644 --- a/servant/src/Servant/API/ContentTypes.hs +++ b/servant/src/Servant/API/ContentTypes.hs @@ -72,8 +72,7 @@ module Servant.API.ContentTypes import Control.Arrow (left) import Control.Monad.Compat -import Data.Aeson (FromJSON (..), ToJSON (..), - encode) +import Data.Aeson (FromJSON(..), ToJSON(..), encode) import Data.Aeson.Parser (value) import Data.Aeson.Types (parseEither) import Data.Attoparsec.ByteString.Char8 (endOfInput, parseOnly, @@ -288,7 +287,7 @@ instance OVERLAPPABLE_ ToJSON a => MimeRender JSON a where mimeRender _ = encode --- | @urlEncodeAsForm" +-- | @urlEncodeAsForm@ -- Note that the @mimeUnrender p (mimeRender p x) == Right x@ law only -- holds if every element of x is non-null (i.e., not @("", "")@) instance OVERLAPPABLE_ From 5d4b730b3e198e7c4a2690b5f0862172c84ca9ed Mon Sep 17 00:00:00 2001 From: Tim Habermaas Date: Fri, 16 Sep 2016 18:48:54 +0200 Subject: [PATCH 31/34] Fix typo in servant-js README --- servant-js/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servant-js/README.md b/servant-js/README.md index e92f9f2d..f2c99616 100644 --- a/servant-js/README.md +++ b/servant-js/README.md @@ -78,8 +78,8 @@ server counter = counterPlusOne counter -- (+1) on the TVar :<|> currentValue counter -- read the TVar server' :: TVar Counter -> Server TestApi' -server counter = server counter - :<|> serveDirectory www -- serve static files +server' counter = server counter + :<|> serveDirectory www -- serve static files runServer :: TVar Counter -- ^ shared variable for the counter -> Int -- ^ port the server should listen on From d7d22b8050d40028aa8733187de0c13aa9497ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Sat, 17 Sep 2016 11:46:26 -0400 Subject: [PATCH 32/34] tweake changelogs for the upcoming release --- servant-client/CHANGELOG.md | 5 ++--- servant/CHANGELOG.md | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/servant-client/CHANGELOG.md b/servant-client/CHANGELOG.md index df037a86..02a6ef39 100644 --- a/servant-client/CHANGELOG.md +++ b/servant-client/CHANGELOG.md @@ -1,11 +1,10 @@ -0.8.1 ------ +0.9 +--- * BACKWARDS INCOMPATIBLE: `client` now returns a ClientM which is a Reader for BasicEnv. BasicEnv comprises the HttpManager and BaseUrl that have had to be passed to each method returned by `client`. - 0.7.1 ----- diff --git a/servant/CHANGELOG.md b/servant/CHANGELOG.md index d07c9477..15a5532a 100644 --- a/servant/CHANGELOG.md +++ b/servant/CHANGELOG.md @@ -1,8 +1,9 @@ -next ----- +0.9 +--- + * Added Eq, Show, Read, Generic and Ord instances to IsSecure -* BACKWARDS INCOMPATIBLE replace use of `ToFromByteString` with `To/FromHttpApiData` for `GetHeaders/BuildHeadersTo` -* BACKWARD INCOMPATIBLE: Moved `From/ToFormUrlEncoded` classes, which were renamed to `From/ToForm` to `http-api-data` +* BACKWARDS INCOMPATIBLE: replace use of `ToFromByteString` with `To/FromHttpApiData` for `GetHeaders/BuildHeadersTo` +* BACKWARDS INCOMPATIBLE: Moved `From/ToFormUrlEncoded` classes, which were renamed to `From/ToForm` to `http-api-data` 0.8.1 ---- From bc1a3e7faaf040ae26463c58177927414f5bdbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Hahn?= Date: Sat, 17 Sep 2016 11:47:57 -0400 Subject: [PATCH 33/34] bump version --- doc/tutorial/tutorial.cabal | 12 ++++++------ servant-client/servant-client.cabal | 8 ++++---- servant-docs/servant-docs.cabal | 4 ++-- servant-foreign/servant-foreign.cabal | 4 ++-- servant-js/servant-js.cabal | 10 +++++----- servant-server/servant-server.cabal | 4 ++-- servant/servant.cabal | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/doc/tutorial/tutorial.cabal b/doc/tutorial/tutorial.cabal index 797ff5e2..18b54c40 100644 --- a/doc/tutorial/tutorial.cabal +++ b/doc/tutorial/tutorial.cabal @@ -1,5 +1,5 @@ name: tutorial -version: 0.8.1 +version: 0.9 synopsis: The servant tutorial homepage: http://haskell-servant.readthedocs.org/ license: BSD3 @@ -25,11 +25,11 @@ library , directory , blaze-markup , containers - , servant == 0.8.* - , servant-server == 0.8.* - , servant-client == 0.8.* - , servant-docs == 0.8.* - , servant-js == 0.8.* + , servant == 0.9.* + , servant-server == 0.9.* + , servant-client == 0.9.* + , servant-docs == 0.9.* + , servant-js == 0.9.* , warp , http-media , lucid diff --git a/servant-client/servant-client.cabal b/servant-client/servant-client.cabal index 327f3d2d..1e4e1e8b 100644 --- a/servant-client/servant-client.cabal +++ b/servant-client/servant-client.cabal @@ -1,5 +1,5 @@ name: servant-client -version: 0.8.1 +version: 0.9 synopsis: automatical derivation of querying functions for servant webservices description: This library lets you derive automatically Haskell functions that @@ -48,7 +48,7 @@ library , http-types >= 0.8.6 && < 0.10 , network-uri >= 2.6 && < 2.7 , safe >= 0.3.9 && < 0.4 - , servant == 0.8.* + , servant == 0.9.* , string-conversions >= 0.3 && < 0.5 , text >= 1.2 && < 1.3 , transformers >= 0.3 && < 0.6 @@ -85,9 +85,9 @@ test-suite spec , HUnit , network >= 2.6 , QuickCheck >= 2.7 - , servant == 0.8.* + , servant == 0.9.* , servant-client - , servant-server == 0.8.* + , servant-server == 0.9.* , text , wai , warp diff --git a/servant-docs/servant-docs.cabal b/servant-docs/servant-docs.cabal index 949abece..70bbeeff 100644 --- a/servant-docs/servant-docs.cabal +++ b/servant-docs/servant-docs.cabal @@ -1,5 +1,5 @@ name: servant-docs -version: 0.8.1 +version: 0.9 synopsis: generate API docs for your servant webservice description: Library for generating API docs from a servant API definition. @@ -41,7 +41,7 @@ library , http-media >= 0.6 , http-types >= 0.7 , lens - , servant == 0.8.* + , servant == 0.9.* , string-conversions , text , unordered-containers diff --git a/servant-foreign/servant-foreign.cabal b/servant-foreign/servant-foreign.cabal index 26be4dbd..c26b879b 100644 --- a/servant-foreign/servant-foreign.cabal +++ b/servant-foreign/servant-foreign.cabal @@ -1,5 +1,5 @@ name: servant-foreign -version: 0.8.1 +version: 0.9 synopsis: Helpers for generating clients for servant APIs in any programming language description: Helper types and functions for generating client functions for servant APIs in any programming language @@ -32,7 +32,7 @@ library , Servant.Foreign.Inflections build-depends: base == 4.* , lens == 4.* - , servant == 0.8.* + , servant == 0.9.* , text >= 1.2 && < 1.3 , http-types hs-source-dirs: src diff --git a/servant-js/servant-js.cabal b/servant-js/servant-js.cabal index 04ea1ff9..a79f5fda 100644 --- a/servant-js/servant-js.cabal +++ b/servant-js/servant-js.cabal @@ -1,5 +1,5 @@ name: servant-js -version: 0.8.1 +version: 0.9 synopsis: Automatically derive javascript functions to query servant webservices. description: Automatically derive javascript functions to query servant webservices. @@ -45,8 +45,8 @@ library , base-compat >= 0.9 , charset >= 0.3 , lens >= 4 - , servant-foreign == 0.8.* - , servant == 0.8.* + , servant-foreign == 0.9.* + , servant == 0.9.* , text >= 1.2 && < 1.3 hs-source-dirs: src @@ -68,8 +68,8 @@ executable counter , aeson >= 0.7 && < 1.1 , filepath >= 1 , lens >= 4 - , servant == 0.8.* - , servant-server == 0.8.* + , servant == 0.9.* + , servant-server == 0.9.* , servant-js , stm , transformers diff --git a/servant-server/servant-server.cabal b/servant-server/servant-server.cabal index f9b5f45f..cbd30cef 100644 --- a/servant-server/servant-server.cabal +++ b/servant-server/servant-server.cabal @@ -1,5 +1,5 @@ name: servant-server -version: 0.8.1 +version: 0.9 synopsis: A family of combinators for defining webservices APIs and serving them description: A family of combinators for defining webservices APIs and serving them @@ -58,7 +58,7 @@ library , mtl >= 2 && < 2.3 , network >= 2.6 && < 2.7 , safe >= 0.3 && < 0.4 - , servant == 0.8.* + , servant == 0.9.* , split >= 0.2 && < 0.3 , string-conversions >= 0.3 && < 0.5 , system-filepath >= 0.4 && < 0.5 diff --git a/servant/servant.cabal b/servant/servant.cabal index 6d3030bf..76421783 100644 --- a/servant/servant.cabal +++ b/servant/servant.cabal @@ -1,5 +1,5 @@ name: servant -version: 0.8.1 +version: 0.9 synopsis: A family of combinators for defining webservices APIs description: A family of combinators for defining webservices APIs and serving them From 32313d9baf7f05a8e15af912d75e02901a910961 Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Sat, 8 Oct 2016 15:08:07 +0100 Subject: [PATCH 34/34] Move servant-js to own repo --- servant-js/CHANGELOG.md | 23 -- servant-js/LICENSE | 30 -- servant-js/README.md | 99 ------ servant-js/Setup.hs | 2 - servant-js/TODO.md | 1 - servant-js/docs.sh | 52 ---- servant-js/examples/README.md | 17 - servant-js/examples/counter.hs | 104 ------- servant-js/examples/counter.md | 39 --- .../examples/www/angular/angular.min.js | 290 ------------------ servant-js/examples/www/angular/index.html | 39 --- servant-js/examples/www/angular/service.html | 39 --- servant-js/examples/www/axios/axios.min.js | 10 - servant-js/examples/www/axios/index.html | 40 --- servant-js/examples/www/index.html | 19 -- servant-js/examples/www/jquery/index.html | 40 --- servant-js/examples/www/jquery/jquery.min.js | 4 - servant-js/examples/www/vanilla/index.html | 39 --- servant-js/include/overlapping-compat.h | 8 - servant-js/servant-js.cabal | 96 ------ servant-js/src/Servant/JS.hs | 154 ---------- servant-js/src/Servant/JS/Angular.hs | 149 --------- servant-js/src/Servant/JS/Axios.hs | 137 --------- servant-js/src/Servant/JS/Internal.hs | 187 ----------- servant-js/src/Servant/JS/JQuery.hs | 103 ------- servant-js/src/Servant/JS/Vanilla.hs | 114 ------- servant-js/test/Servant/JSSpec.hs | 205 ------------- .../test/Servant/JSSpec/CustomHeaders.hs | 60 ---- servant-js/test/Spec.hs | 2 - servant-js/tinc.yaml | 7 - sources.txt | 1 - stack-ghc-7.8.4.yaml | 1 - stack-ghc-8.0.1.yaml | 1 - stack.yaml | 2 +- 34 files changed, 1 insertion(+), 2113 deletions(-) delete mode 100644 servant-js/CHANGELOG.md delete mode 100644 servant-js/LICENSE delete mode 100644 servant-js/README.md delete mode 100644 servant-js/Setup.hs delete mode 100644 servant-js/TODO.md delete mode 100644 servant-js/docs.sh delete mode 100644 servant-js/examples/README.md delete mode 100644 servant-js/examples/counter.hs delete mode 100644 servant-js/examples/counter.md delete mode 100644 servant-js/examples/www/angular/angular.min.js delete mode 100644 servant-js/examples/www/angular/index.html delete mode 100644 servant-js/examples/www/angular/service.html delete mode 100644 servant-js/examples/www/axios/axios.min.js delete mode 100644 servant-js/examples/www/axios/index.html delete mode 100644 servant-js/examples/www/index.html delete mode 100644 servant-js/examples/www/jquery/index.html delete mode 100644 servant-js/examples/www/jquery/jquery.min.js delete mode 100644 servant-js/examples/www/vanilla/index.html delete mode 100644 servant-js/include/overlapping-compat.h delete mode 100644 servant-js/servant-js.cabal delete mode 100644 servant-js/src/Servant/JS.hs delete mode 100644 servant-js/src/Servant/JS/Angular.hs delete mode 100644 servant-js/src/Servant/JS/Axios.hs delete mode 100644 servant-js/src/Servant/JS/Internal.hs delete mode 100644 servant-js/src/Servant/JS/JQuery.hs delete mode 100644 servant-js/src/Servant/JS/Vanilla.hs delete mode 100644 servant-js/test/Servant/JSSpec.hs delete mode 100644 servant-js/test/Servant/JSSpec/CustomHeaders.hs delete mode 100644 servant-js/test/Spec.hs delete mode 100644 servant-js/tinc.yaml diff --git a/servant-js/CHANGELOG.md b/servant-js/CHANGELOG.md deleted file mode 100644 index 770f2a72..00000000 --- a/servant-js/CHANGELOG.md +++ /dev/null @@ -1,23 +0,0 @@ -0.5 ----- - -* Extract javascript-obvlious types and helpers to *servant-foreign* -* Use `text` package instead of `String` -* Provide new targets for code generation along with the old jQuery one: vanilla Javascript and Angular.js -* Greatly simplify usage of this library by reducing down the API to just 2 functions: `jsForAPI` and `writeJSForAPI` + the choice of a code generator -* Support for the `HttpVersion`, `IsSecure`, `RemoteHost` and `Vault` combinators -* Remove matrix params. - -0.4 ---- -* `Delete` now is like `Get`, `Post`, `Put`, and `Patch` and returns a response body -* Extend `HeaderArg` to support more advanced HTTP header handling (https://github.com/haskell-servant/servant-jquery/pull/6) -* Support content-type aware combinators (but require that endpoints support JSON) -* Add support for Matrix params (https://github.com/haskell-servant/servant-jquery/pull/11) -* Add functions that directly generate the Javascript code from the API type without having to manually pattern match on the result. - -0.2.2 ------ - -* Fix an issue where toplevel Raw endpoints would generate a JS function with no name (https://github.com/haskell-servant/servant-jquery/issues/2) -* Replace dots by _ in paths (https://github.com/haskell-servant/servant-jquery/issues/1) diff --git a/servant-js/LICENSE b/servant-js/LICENSE deleted file mode 100644 index 9717a9ce..00000000 --- a/servant-js/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (c) 2014-2016, Zalora South East Asia Pte Ltd, Servant Contributors - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of Zalora South East Asia Pte Ltd nor the names of other - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/servant-js/README.md b/servant-js/README.md deleted file mode 100644 index f2c99616..00000000 --- a/servant-js/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# servant-js - -![servant](https://raw.githubusercontent.com/haskell-servant/servant/master/servant.png) - -This library lets you derive automatically Javascript functions that let you query each endpoint of a *servant* webservice. - -It contains a powerful system allowing you to generate functions for several frameworks (Angular, AXios, JQuery) as well as -vanilla (framework-free) javascript code. - -## Example - -Read more about the following example [here](https://github.com/haskell-servant/servant/tree/master/servant-js/examples#examples). - -``` haskell -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} - -import Control.Concurrent.STM -import Control.Monad.IO.Class -import Data.Aeson -import Data.Proxy -import GHC.Generics -import Network.Wai.Handler.Warp (run) -import Servant -import Servant.JS -import System.FilePath - --- * A simple Counter data type -newtype Counter = Counter { value :: Int } - deriving (Generic, Show, Num) - -instance ToJSON Counter - --- * Shared counter operations - --- Creating a counter that starts from 0 -newCounter :: IO (TVar Counter) -newCounter = newTVarIO 0 - --- Increasing the counter by 1 -counterPlusOne :: MonadIO m => TVar Counter -> m Counter -counterPlusOne counter = liftIO . atomically $ do - oldValue <- readTVar counter - let newValue = oldValue + 1 - writeTVar counter newValue - return newValue - -currentValue :: MonadIO m => TVar Counter -> m Counter -currentValue counter = liftIO $ readTVarIO counter - --- * Our API type -type TestApi = "counter" :> Post '[JSON] Counter -- endpoint for increasing the counter - :<|> "counter" :> Get '[JSON] Counter -- endpoint to get the current value - -type TestApi' = TestApi -- The API we want a JS handler for - :<|> Raw -- used for serving static files - --- this proxy only targets the proper endpoints of our API, --- not the static file serving bit -testApi :: Proxy TestApi -testApi = Proxy - --- this proxy targets everything -testApi' :: Proxy TestApi' -testApi' = Proxy - --- * Server-side handler - --- where our static files reside -www :: FilePath -www = "examples/www" - --- defining handlers -server :: TVar Counter -> Server TestApi -server counter = counterPlusOne counter -- (+1) on the TVar - :<|> currentValue counter -- read the TVar - -server' :: TVar Counter -> Server TestApi' -server' counter = server counter - :<|> serveDirectory www -- serve static files - -runServer :: TVar Counter -- ^ shared variable for the counter - -> Int -- ^ port the server should listen on - -> IO () -runServer var port = run port (serve testApi' $ server' var) - -main :: IO () -main = do - -- write the JS code to www/api.js at startup - writeJSForAPI testApi jquery (www "api.js") - - -- setup a shared counter - cnt <- newCounter - - -- listen to requests on port 8080 - runServer cnt 8080 -``` diff --git a/servant-js/Setup.hs b/servant-js/Setup.hs deleted file mode 100644 index 44671092..00000000 --- a/servant-js/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/servant-js/TODO.md b/servant-js/TODO.md deleted file mode 100644 index 8ee2b547..00000000 --- a/servant-js/TODO.md +++ /dev/null @@ -1 +0,0 @@ -- Investigate the best way to offer cross-origin requests \ No newline at end of file diff --git a/servant-js/docs.sh b/servant-js/docs.sh deleted file mode 100644 index 9e91c132..00000000 --- a/servant-js/docs.sh +++ /dev/null @@ -1,52 +0,0 @@ -SERVANT_DIR=/tmp/servant-js-gh-pages - -# Make a temporary clone - -rm -rf $SERVANT_DIR - -git clone . $SERVANT_DIR - -cd $SERVANT_DIR - -# Make sure to pull the latest - -git remote add haskell-servant git@github.com:haskell-servant/servant-js.git - -git fetch haskell-servant - -git reset --hard haskell-servant/gh-pages - -# Clear everything away - -git rm -rf $SERVANT_DIR/* - -# Switch back and build the haddocks - -cd - - -cabal configure --builddir=$SERVANT_DIR - -cabal haddock --hoogle --hyperlink-source --html-location='https://hackage.haskell.org/package/$pkg-$version/docs' --builddir=$SERVANT_DIR - -commit_hash=$(git rev-parse HEAD) - -# Move the HTML docs to the root - -cd $SERVANT_DIR - -rm * -rm -rf build -mv doc/html/servant-js/* . -rm -r doc/ - -# Add everything - -git add . - -git commit -m "Built from $commit_hash" - -# Push to update the pages - -git push haskell-servant HEAD:gh-pages - -rm -rf $SERVANT_DIR diff --git a/servant-js/examples/README.md b/servant-js/examples/README.md deleted file mode 100644 index 9e469882..00000000 --- a/servant-js/examples/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Examples - -## counter - -This example demonstrates a *servant* server that holds a shared variable (using a `TVar`) and exposes an endpoint for reading its current value and another one for increasing its current value by 1. - -In addition to that, it shows how you can generate the jquery-powered javascript functions corresponding to each endpoint, i.e one for reading the current value and one for increasing the value, and integrates all of that in a very simple HTML page. All these static files are served using the `serveDirectory` function from *servant*. - -To see this all in action, simply run: - -``` bash -$ cabal run counter -``` - -And point your browser to [http://localhost:8080/index.html](http://localhost:8080/index.html). - -Copies of the generated javascript functions and of the generated docs are included in `www/api.js` and `counter.md` respectively. \ No newline at end of file diff --git a/servant-js/examples/counter.hs b/servant-js/examples/counter.hs deleted file mode 100644 index 4040b053..00000000 --- a/servant-js/examples/counter.hs +++ /dev/null @@ -1,104 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TypeOperators #-} - -import Control.Concurrent.STM -import Control.Monad.IO.Class -import Data.Aeson -import Data.Proxy -import GHC.Generics -import Network.Wai.Handler.Warp (run) -import Servant -import Servant.JS -import qualified Servant.JS as SJS -import qualified Servant.JS.Angular as NG -import System.FilePath - --- * A simple Counter data type -newtype Counter = Counter { value :: Int } - deriving (Generic, Show, Num) - -instance ToJSON Counter - --- * Shared counter operations - --- Creating a counter that starts from 0 -newCounter :: IO (TVar Counter) -newCounter = newTVarIO 0 - --- Increasing the counter by 1 -counterPlusOne :: MonadIO m => TVar Counter -> m Counter -counterPlusOne counter = liftIO . atomically $ do - oldValue <- readTVar counter - let newValue = oldValue + 1 - writeTVar counter newValue - return newValue - -currentValue :: MonadIO m => TVar Counter -> m Counter -currentValue counter = liftIO $ readTVarIO counter - --- * Our API type -type TestApi = "counter" :> Post '[JSON] Counter -- endpoint for increasing the counter - :<|> "counter" :> Get '[JSON] Counter -- endpoint to get the current value - -type TestApi' = TestApi - :<|> Raw -- used for serving static files - --- this proxy only targets the proper endpoints of our API, --- not the static file serving bit -testApi :: Proxy TestApi -testApi = Proxy - --- this proxy targets everything -testApi' :: Proxy TestApi' -testApi' = Proxy - --- * Server-side handler - --- where our static files reside -www :: FilePath -www = "examples/www" - --- defining handlers of our endpoints -server :: TVar Counter -> Server TestApi -server counter = counterPlusOne counter -- (+1) on the TVar - :<|> currentValue counter -- read the TVar - --- the whole server, including static file serving -server' :: TVar Counter -> Server TestApi' -server' counter = server counter - :<|> serveDirectory www -- serve static files - -runServer :: TVar Counter -- ^ shared variable for the counter - -> Int -- ^ port the server should listen on - -> IO () -runServer var port = run port (serve testApi' $ server' var) - -writeServiceJS :: FilePath -> IO () -writeServiceJS fp = - writeJSForAPI testApi - (angularServiceWith (NG.defAngularOptions { NG.serviceName = "counterSvc" }) - (defCommonGeneratorOptions { SJS.moduleName = "counterApp" }) - ) - fp - -main :: IO () -main = do - -- write the JS code to www/api.js at startup - writeJSForAPI testApi jquery (www "jquery" "api.js") - - writeJSForAPI testApi vanillaJS (www "vanilla" "api.js") - - writeJSForAPI testApi (angular defAngularOptions) (www "angular" "api.js") - - writeJSForAPI testApi (axios defAxiosOptions) (www "axios" "api.js") - - writeServiceJS (www "angular" "api.service.js") - - -- setup a shared counter - cnt <- newCounter - - -- listen to requests on port 8080 - runServer cnt 8080 diff --git a/servant-js/examples/counter.md b/servant-js/examples/counter.md deleted file mode 100644 index 92214d57..00000000 --- a/servant-js/examples/counter.md +++ /dev/null @@ -1,39 +0,0 @@ -POST /counter -------------- - -**Response**: - - - Status code 201 - - Response body as below. - -``` javascript -{"value":0} -``` - -GET /doc --------- - -**Response**: - - - Status code 200 - - No response body - -GET /counter ------------- - -**Response**: - - - Status code 200 - - Response body as below. - -``` javascript -{"value":0} -``` - -GET / ------ - -**Response**: - - - Status code 200 - - No response body diff --git a/servant-js/examples/www/angular/angular.min.js b/servant-js/examples/www/angular/angular.min.js deleted file mode 100644 index b72d29a9..00000000 --- a/servant-js/examples/www/angular/angular.min.js +++ /dev/null @@ -1,290 +0,0 @@ -/* - AngularJS v1.4.2 - (c) 2010-2015 Google, Inc. http://angularjs.org - License: MIT -*/ -(function(O,U,t){'use strict';function J(b){return function(){var a=arguments[0],c;c="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.4.2/"+(b?b+"/":"")+a;for(a=1;a").append(b).html();try{return b[0].nodeType===Na?M(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+M(b)})}catch(d){return M(c)}}function yc(b){try{return decodeURIComponent(b)}catch(a){}}function zc(b){var a={},c,d;m((b||"").split("&"),function(b){b&&(c=b.replace(/\+/g, -"%20").split("="),d=yc(c[0]),w(d)&&(b=w(c[1])?yc(c[1]):!0,Xa.call(a,d)?G(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Qb(b){var a=[];m(b,function(b,d){G(b)?m(b,function(b){a.push(ma(d,!0)+(!0===b?"":"="+ma(b,!0)))}):a.push(ma(d,!0)+(!0===b?"":"="+ma(b,!0)))});return a.length?a.join("&"):""}function ob(b){return ma(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ma(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g, -"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,a?"%20":"+")}function Yd(b,a){var c,d,e=Oa.length;for(d=0;d/,">"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);c.debugInfoEnabled&&a.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);a.unshift("ng");d=eb(a,c.strictDi);d.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return d},e= -/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;O&&e.test(O.name)&&(c.debugInfoEnabled=!0,O.name=O.name.replace(e,""));if(O&&!f.test(O.name))return d();O.name=O.name.replace(f,"");ca.resumeBootstrap=function(b){m(b,function(b){a.push(b)});return d()};z(ca.resumeDeferredBootstrap)&&ca.resumeDeferredBootstrap()}function $d(){O.name="NG_ENABLE_DEBUG_INFO!"+O.name;O.location.reload()}function ae(b){b=ca.element(b).injector();if(!b)throw Fa("test");return b.get("$$testability")}function Bc(b,a){a=a|| -"_";return b.replace(be,function(b,d){return(d?a:"")+b.toLowerCase()})}function ce(){var b;if(!Cc){var a=pb();la=O.jQuery;w(a)&&(la=null===a?t:O[a]);la&&la.fn.on?(y=la,P(la.fn,{scope:Pa.scope,isolateScope:Pa.isolateScope,controller:Pa.controller,injector:Pa.injector,inheritedData:Pa.inheritedData}),b=la.cleanData,la.cleanData=function(a){var d;if(Rb)Rb=!1;else for(var e=0,f;null!=(f=a[e]);e++)(d=la._data(f,"events"))&&d.$destroy&&la(f).triggerHandler("$destroy");b(a)}):y=Q;ca.element=y;Cc=!0}}function Sb(b, -a,c){if(!b)throw Fa("areq",a||"?",c||"required");return b}function Qa(b,a,c){c&&G(b)&&(b=b[b.length-1]);Sb(z(b),a,"not a function, got "+(b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function Ra(b,a){if("hasOwnProperty"===b)throw Fa("badname",a);}function Dc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g")+d[2];for(d=d[0];d--;)c=c.lastChild;f=cb(f,c.childNodes);c=e.firstChild;c.textContent=""}else f.push(a.createTextNode(b));e.textContent="";e.innerHTML="";m(f,function(a){e.appendChild(a)});return e}function Q(b){if(b instanceof Q)return b;var a;L(b)&&(b=R(b),a=!0);if(!(this instanceof Q)){if(a&&"<"!=b.charAt(0))throw Ub("nosel");return new Q(b)}if(a){a= -U;var c;b=(c=Df.exec(b))?[a.createElement(c[1])]:(c=Nc(b,a))?c.childNodes:[]}Oc(this,b)}function Vb(b){return b.cloneNode(!0)}function tb(b,a){a||ub(b);if(b.querySelectorAll)for(var c=b.querySelectorAll("*"),d=0,e=c.length;dk&&this.remove(s.key);return b}},get:function(a){if(k").parent()[0])});var f=S(a,b,a,c,d,e);Z.$$addScopeClass(a);var g=null;return function(b,c,d){Sb(b,"scope");d=d||{};var e=d.parentBoundTranscludeFn,h=d.transcludeControllers;d=d.futureParentElement;e&&e.$$boundTransclude&&(e=e.$$boundTransclude);g||(g=(d=d&&d[0])?"foreignobject"!==ta(d)&&d.toString().match(/SVG/)?"svg":"html":"html");d="html"!==g?y(Yb(g,y("
").append(a).html())):c?Pa.clone.call(a):a;if(h)for(var k in h)d.data("$"+k+"Controller", -h[k].instance);Z.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,e);return d}}function S(a,b,c,d,e,f){function g(a,c,d,e){var f,k,l,s,n,B,C;if(p)for(C=Array(c.length),s=0;sE.priority)break;if(v=E.scope)E.templateUrl||(H(v)?(O("new/isolated scope",u||$,E,ba),u=E):O("new/isolated scope",u,E,ba)),$=$||E;w=E.name;!E.templateUrl&&E.controller&&(v=E.controller,N=N||ga(),O("'"+w+"' controller",N[w],E,ba),N[w]=E);if(v=E.transclude)K=!0,E.$$tlb||(O("transclusion",m,E,ba),m=E),"element"==v?(q=!0,F=E.priority,v=ba,ba=d.$$element=y(U.createComment(" "+w+": "+d[w]+" ")),b=ba[0],T(f,za.call(v,0),b),A=Z(v,e,F,g&&g.name,{nonTlbTranscludeDirective:m})):(v= -y(Vb(b)).contents(),ba.empty(),A=Z(v,e));if(E.template)if(I=!0,O("template",D,E,ba),D=E,v=z(E.template)?E.template(ba,d):E.template,v=fa(v),E.replace){g=E;v=Tb.test(v)?$c(Yb(E.templateNamespace,R(v))):[];b=v[0];if(1!=v.length||b.nodeType!==qa)throw ea("tplrt",w,"");T(f,ba,b);Ta={$attr:{}};v=ha(b,[],Ta);var Q=a.splice(xa+1,a.length-(xa+1));u&&ad(v);a=a.concat(v).concat(Q);J(d,Ta);Ta=a.length}else ba.html(v);if(E.templateUrl)I=!0,O("template",D,E,ba),D=E,E.replace&&(g=E),S=Mf(a.splice(xa,a.length-xa), -ba,d,f,K&&A,h,k,{controllerDirectives:N,newScopeDirective:$!==E&&$,newIsolateScopeDirective:u,templateDirective:D,nonTlbTranscludeDirective:m}),Ta=a.length;else if(E.compile)try{Aa=E.compile(ba,d,A),z(Aa)?n(null,Aa,M,P):Aa&&n(Aa.pre,Aa.post,M,P)}catch(Lf){c(Lf,ua(ba))}E.terminal&&(S.terminal=!0,F=Math.max(F,E.priority))}S.scope=$&&!0===$.scope;S.transcludeOnThisElement=K;S.templateOnThisElement=I;S.transclude=A;s.hasElementTranscludeDirective=q;return S}function ad(a){for(var b=0,c=a.length;bn.priority)&&-1!=n.restrict.indexOf(f)&&(k&&(n=Ob(n,{$$start:k,$$end:l})),b.push(n),h=n)}catch(x){c(x)}}return h}function A(b){if(e.hasOwnProperty(b))for(var c=a.get(b+"Directive"),d=0,f=c.length;d"+b+"";return c.childNodes[0].childNodes;default:return b}}function Q(a,b){if("srcdoc"==b)return I.HTML; -var c=ta(a);if("xlinkHref"==b||"form"==c&&"action"==b||"img"!=c&&("src"==b||"ngSrc"==b))return I.RESOURCE_URL}function V(a,c,d,e,f){var g=Q(a,e);f=h[e]||f;var l=b(d,!0,g,f);if(l){if("multiple"===e&&"select"===ta(a))throw ea("selmulti",ua(a));c.push({priority:100,compile:function(){return{pre:function(a,c,h){c=h.$$observers||(h.$$observers={});if(k.test(e))throw ea("nodomevents");var s=h[e];s!==d&&(l=s&&b(s,!0,g,f),d=s);l&&(h[e]=l(a),(c[e]||(c[e]=[])).$$inter=!0,(h.$$observers&&h.$$observers[e].$$scope|| -a).$watch(l,function(a,b){"class"===e&&a!=b?h.$updateClass(a,b):h.$set(e,a)}))}}}})}}function T(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g=a)return b;for(;a--;)8===b[a].nodeType&&Nf.call(b,a,1);return b}function Xe(){var b={},a=!1;this.register=function(a,d){Ra(a,"controller");H(a)?P(b,a):b[a]=d};this.allowGlobals=function(){a=!0};this.$get=["$injector","$window",function(c,d){function e(a,b,c,d){if(!a||!H(a.$scope))throw J("$controller")("noscp",d,b);a.$scope[b]=c}return function(f,g,h,l){var k,n,r;h=!0===h;l&&L(l)&&(r=l);if(L(f)){l=f.match(Xc);if(!l)throw Of("ctrlfmt", -f);n=l[1];r=r||l[3];f=b.hasOwnProperty(n)?b[n]:Dc(g.$scope,n,!0)||(a?Dc(d,n,!0):t);Qa(f,n,!0)}if(h)return h=(G(f)?f[f.length-1]:f).prototype,k=Object.create(h||null),r&&e(g,r,k,n||f.name),P(function(){var a=c.invoke(f,k,g,n);a!==k&&(H(a)||z(a))&&(k=a,r&&e(g,r,k,n||f.name));return k},{instance:k,identifier:r});k=c.instantiate(f,g,n);r&&e(g,r,k,n||f.name);return k}}]}function Ye(){this.$get=["$window",function(b){return y(b.document)}]}function Ze(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b, -arguments)}}]}function Zb(b){return H(b)?aa(b)?b.toISOString():db(b):b}function cf(){this.$get=function(){return function(b){if(!b)return"";var a=[];oc(b,function(b,d){null===b||A(b)||(G(b)?m(b,function(b,c){a.push(ma(d)+"="+ma(Zb(b)))}):a.push(ma(d)+"="+ma(Zb(b))))});return a.join("&")}}}function df(){this.$get=function(){return function(b){function a(b,e,f){null===b||A(b)||(G(b)?m(b,function(b){a(b,e+"[]")}):H(b)&&!aa(b)?oc(b,function(b,c){a(b,e+(f?"":"[")+c+(f?"":"]"))}):c.push(ma(e)+"="+ma(Zb(b))))} -if(!b)return"";var c=[];a(b,"",!0);return c.join("&")}}}function $b(b,a){if(L(b)){var c=b.replace(Pf,"").trim();if(c){var d=a("Content-Type");(d=d&&0===d.indexOf(cd))||(d=(d=c.match(Qf))&&Rf[d[0]].test(c));d&&(b=wc(c))}}return b}function dd(b){var a=ga(),c;L(b)?m(b.split("\n"),function(b){c=b.indexOf(":");var e=M(R(b.substr(0,c)));b=R(b.substr(c+1));e&&(a[e]=a[e]?a[e]+", "+b:b)}):H(b)&&m(b,function(b,c){var f=M(c),g=R(b);f&&(a[f]=a[f]?a[f]+", "+g:g)});return a}function ed(b){var a;return function(c){a|| -(a=dd(b));return c?(c=a[M(c)],void 0===c&&(c=null),c):a}}function fd(b,a,c,d){if(z(d))return d(b,a,c);m(d,function(d){b=d(b,a,c)});return b}function bf(){var b=this.defaults={transformResponse:[$b],transformRequest:[function(a){return H(a)&&"[object File]"!==sa.call(a)&&"[object Blob]"!==sa.call(a)&&"[object FormData]"!==sa.call(a)?db(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ia(ac),put:ia(ac),patch:ia(ac)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer"}, -a=!1;this.useApplyAsync=function(b){return w(b)?(a=!!b,this):a};var c=this.interceptors=[];this.$get=["$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector",function(d,e,f,g,h,l){function k(a){function c(a){var b=P({},a);b.data=a.data?fd(a.data,a.headers,a.status,e.transformResponse):a.data;a=a.status;return 200<=a&&300>a?b:h.reject(b)}function d(a,b){var c,e={};m(a,function(a,d){z(a)?(c=a(b),null!=c&&(e[d]=c)):e[d]=a});return e}if(!ca.isObject(a))throw J("$http")("badreq", -a);var e=P({method:"get",transformRequest:b.transformRequest,transformResponse:b.transformResponse,paramSerializer:b.paramSerializer},a);e.headers=function(a){var c=b.headers,e=P({},a.headers),f,g,h,c=P({},c.common,c[M(a.method)]);a:for(f in c){g=M(f);for(h in e)if(M(h)===g)continue a;e[f]=c[f]}return d(e,ia(a))}(a);e.method=rb(e.method);e.paramSerializer=L(e.paramSerializer)?l.get(e.paramSerializer):e.paramSerializer;var f=[function(a){var d=a.headers,e=fd(a.data,ed(d),t,a.transformRequest);A(e)&& -m(d,function(a,b){"content-type"===M(b)&&delete d[b]});A(a.withCredentials)&&!A(b.withCredentials)&&(a.withCredentials=b.withCredentials);return n(a,e).then(c,c)},t],g=h.when(e);for(m(x,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),g=g.then(a,k)}g.success=function(a){Qa(a,"fn");g.then(function(b){a(b.data,b.status,b.headers,e)});return g};g.error=function(a){Qa(a, -"fn");g.then(null,function(b){a(b.data,b.status,b.headers,e)});return g};return g}function n(c,f){function l(b,c,d,e){function f(){n(c,b,d,e)}N&&(200<=b&&300>b?N.put(S,[b,c,dd(d),e]):N.remove(S));a?g.$applyAsync(f):(f(),g.$$phase||g.$apply())}function n(a,b,d,e){b=Math.max(b,0);(200<=b&&300>b?I.resolve:I.reject)({data:a,status:b,headers:ed(d),config:c,statusText:e})}function x(a){n(a.data,a.status,ia(a.headers()),a.statusText)}function m(){var a=k.pendingRequests.indexOf(c);-1!==a&&k.pendingRequests.splice(a, -1)}var I=h.defer(),B=I.promise,N,D,q=c.headers,S=r(c.url,c.paramSerializer(c.params));k.pendingRequests.push(c);B.then(m,m);!c.cache&&!b.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(N=H(c.cache)?c.cache:H(b.cache)?b.cache:s);N&&(D=N.get(S),w(D)?D&&z(D.then)?D.then(x,x):G(D)?n(D[1],D[0],ia(D[2]),D[3]):n(D,200,{},"OK"):N.put(S,B));A(D)&&((D=gd(c.url)?e()[c.xsrfCookieName||b.xsrfCookieName]:t)&&(q[c.xsrfHeaderName||b.xsrfHeaderName]=D),d(c.method,S,f,l,q,c.timeout,c.withCredentials,c.responseType)); -return B}function r(a,b){0=l&&(u.resolve(C),x(p.$$intervalId),delete f[p.$$intervalId]);F||b.$apply()},h);f[p.$$intervalId]=u;return p}var f={};e.cancel=function(b){return b&&b.$$intervalId in f?(f[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete f[b.$$intervalId], -!0):!1};return e}]}function ge(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "), -DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a",ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"]},pluralCat:function(b){return 1===b?"one":"other"}}}}function bc(b){b=b.split("/");for(var a=b.length;a--;)b[a]=ob(b[a]); -return b.join("/")}function hd(b,a){var c=Ba(b);a.$$protocol=c.protocol;a.$$host=c.hostname;a.$$port=W(c.port)||Uf[c.protocol]||null}function id(b,a){var c="/"!==b.charAt(0);c&&(b="/"+b);var d=Ba(b);a.$$path=decodeURIComponent(c&&"/"===d.pathname.charAt(0)?d.pathname.substring(1):d.pathname);a.$$search=zc(d.search);a.$$hash=decodeURIComponent(d.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function ya(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Ja(b){var a=b.indexOf("#"); -return-1==a?b:b.substr(0,a)}function Bb(b){return b.replace(/(#.+)|#$/,"$1")}function cc(b){return b.substr(0,Ja(b).lastIndexOf("/")+1)}function dc(b,a){this.$$html5=!0;a=a||"";var c=cc(b);hd(b,this);this.$$parse=function(a){var b=ya(c,a);if(!L(b))throw Cb("ipthprfx",a,c);id(b,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Qb(this.$$search),b=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$parseLinkUrl= -function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;(f=ya(b,d))!==t?(g=f,g=(f=ya(a,f))!==t?c+(ya("/",f)||f):b+g):(f=ya(c,d))!==t?g=c+f:c==d+"/"&&(g=c);g&&this.$$parse(g);return!!g}}function ec(b,a){var c=cc(b);hd(b,this);this.$$parse=function(d){var e=ya(b,d)||ya(c,d),f;A(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",A(e)&&(b=d,this.replace())):(f=ya(a,e),A(f)&&(f=e));id(f,this);d=this.$$path;var e=b,g=/^\/[A-Z]:(\/.*)/;0===f.indexOf(e)&&(f=f.replace(e,""));g.exec(f)||(d=(f=g.exec(d))? -f[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Qb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$parseLinkUrl=function(a,c){return Ja(b)==Ja(a)?(this.$$parse(a),!0):!1}}function jd(b,a){this.$$html5=!0;ec.apply(this,arguments);var c=cc(b);this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;b==Ja(d)?f=d:(g=ya(c,d))?f=b+a+g:c===d+"/"&&(f= -c);f&&this.$$parse(f);return!!f};this.$$compose=function(){var c=Qb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+a+this.$$url}}function Db(b){return function(){return this[b]}}function kd(b,a){return function(c){if(A(c))return this[b];this[b]=a(c);this.$$compose();return this}}function ff(){var b="",a={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(a){return w(a)?(b=a,this):b};this.html5Mode=function(b){return ab(b)? -(a.enabled=b,this):H(b)?(ab(b.enabled)&&(a.enabled=b.enabled),ab(b.requireBase)&&(a.requireBase=b.requireBase),ab(b.rewriteLinks)&&(a.rewriteLinks=b.rewriteLinks),this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(c,d,e,f,g){function h(a,b,c){var e=k.url(),f=k.$$state;try{d.url(a,b,c),k.$$state=d.state()}catch(g){throw k.url(e),k.$$state=f,g;}}function l(a,b){c.$broadcast("$locationChangeSuccess",k.absUrl(),a,k.$$state,b)}var k,n;n=d.baseHref();var r=d.url(), -s;if(a.enabled){if(!n&&a.requireBase)throw Cb("nobase");s=r.substring(0,r.indexOf("/",r.indexOf("//")+2))+(n||"/");n=e.history?dc:jd}else s=Ja(r),n=ec;k=new n(s,"#"+b);k.$$parseLinkUrl(r,r);k.$$state=d.state();var x=/^\s*(javascript|mailto):/i;f.on("click",function(b){if(a.rewriteLinks&&!b.ctrlKey&&!b.metaKey&&!b.shiftKey&&2!=b.which&&2!=b.button){for(var e=y(b.target);"a"!==ta(e[0]);)if(e[0]===f[0]||!(e=e.parent())[0])return;var h=e.prop("href"),l=e.attr("href")||e.attr("xlink:href");H(h)&&"[object SVGAnimatedString]"=== -h.toString()&&(h=Ba(h.animVal).href);x.test(h)||!h||e.attr("target")||b.isDefaultPrevented()||!k.$$parseLinkUrl(h,l)||(b.preventDefault(),k.absUrl()!=d.url()&&(c.$apply(),g.angular["ff-684208-preventDefault"]=!0))}});Bb(k.absUrl())!=Bb(r)&&d.url(k.absUrl(),!0);var C=!0;d.onUrlChange(function(a,b){c.$evalAsync(function(){var d=k.absUrl(),e=k.$$state,f;k.$$parse(a);k.$$state=b;f=c.$broadcast("$locationChangeStart",a,d,b,e).defaultPrevented;k.absUrl()===a&&(f?(k.$$parse(d),k.$$state=e,h(d,!1,e)):(C= -!1,l(d,e)))});c.$$phase||c.$digest()});c.$watch(function(){var a=Bb(d.url()),b=Bb(k.absUrl()),f=d.state(),g=k.$$replace,n=a!==b||k.$$html5&&e.history&&f!==k.$$state;if(C||n)C=!1,c.$evalAsync(function(){var b=k.absUrl(),d=c.$broadcast("$locationChangeStart",b,a,k.$$state,f).defaultPrevented;k.absUrl()===b&&(d?(k.$$parse(a),k.$$state=f):(n&&h(b,g,f===k.$$state?null:k.$$state),l(a,f)))});k.$$replace=!1});return k}]}function gf(){var b=!0,a=this;this.debugEnabled=function(a){return w(a)?(b=a,this):b}; -this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||v;a=!1;try{a=!!e.apply}catch(l){}return a?function(){var a=[];m(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c= -e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function Ca(b,a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw da("isecfld",a);return b}function oa(b,a){if(b){if(b.constructor===b)throw da("isecfn",a);if(b.window===b)throw da("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw da("isecdom",a);if(b===Object)throw da("isecobj",a);}return b}function ld(b,a){if(b){if(b.constructor===b)throw da("isecfn", -a);if(b===Vf||b===Wf||b===Xf)throw da("isecff",a);}}function Yf(b,a){return"undefined"!==typeof b?b:a}function md(b,a){return"undefined"===typeof b?a:"undefined"===typeof a?b:b+a}function T(b,a){var c,d;switch(b.type){case q.Program:c=!0;m(b.body,function(b){T(b.expression,a);c=c&&b.expression.constant});b.constant=c;break;case q.Literal:b.constant=!0;b.toWatch=[];break;case q.UnaryExpression:T(b.argument,a);b.constant=b.argument.constant;b.toWatch=b.argument.toWatch;break;case q.BinaryExpression:T(b.left, -a);T(b.right,a);b.constant=b.left.constant&&b.right.constant;b.toWatch=b.left.toWatch.concat(b.right.toWatch);break;case q.LogicalExpression:T(b.left,a);T(b.right,a);b.constant=b.left.constant&&b.right.constant;b.toWatch=b.constant?[]:[b];break;case q.ConditionalExpression:T(b.test,a);T(b.alternate,a);T(b.consequent,a);b.constant=b.test.constant&&b.alternate.constant&&b.consequent.constant;b.toWatch=b.constant?[]:[b];break;case q.Identifier:b.constant=!1;b.toWatch=[b];break;case q.MemberExpression:T(b.object, -a);b.computed&&T(b.property,a);b.constant=b.object.constant&&(!b.computed||b.property.constant);b.toWatch=[b];break;case q.CallExpression:c=b.filter?!a(b.callee.name).$stateful:!1;d=[];m(b.arguments,function(b){T(b,a);c=c&&b.constant;b.constant||d.push.apply(d,b.toWatch)});b.constant=c;b.toWatch=b.filter&&!a(b.callee.name).$stateful?d:[b];break;case q.AssignmentExpression:T(b.left,a);T(b.right,a);b.constant=b.left.constant&&b.right.constant;b.toWatch=[b];break;case q.ArrayExpression:c=!0;d=[];m(b.elements, -function(b){T(b,a);c=c&&b.constant;b.constant||d.push.apply(d,b.toWatch)});b.constant=c;b.toWatch=d;break;case q.ObjectExpression:c=!0;d=[];m(b.properties,function(b){T(b.value,a);c=c&&b.value.constant;b.value.constant||d.push.apply(d,b.value.toWatch)});b.constant=c;b.toWatch=d;break;case q.ThisExpression:b.constant=!1,b.toWatch=[]}}function nd(b){if(1==b.length){b=b[0].expression;var a=b.toWatch;return 1!==a.length?a:a[0]!==b?a:t}}function od(b){return b.type===q.Identifier||b.type===q.MemberExpression} -function pd(b){if(1===b.body.length&&od(b.body[0].expression))return{type:q.AssignmentExpression,left:b.body[0].expression,right:{type:q.NGValueParameter},operator:"="}}function qd(b){return 0===b.body.length||1===b.body.length&&(b.body[0].expression.type===q.Literal||b.body[0].expression.type===q.ArrayExpression||b.body[0].expression.type===q.ObjectExpression)}function rd(b,a){this.astBuilder=b;this.$filter=a}function sd(b,a){this.astBuilder=b;this.$filter=a}function Eb(b,a,c,d){oa(b,d);a=a.split("."); -for(var e,f=0;1=this.promise.$$state.status&&d&&d.length&&b(function(){for(var b,e,f=0,g=d.length;fa)for(b in l++,f)e.hasOwnProperty(b)|| -(m--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,g,k=1m&&(E=4-m,u[E]||(u[E]=[]),u[E].push({msg:z(b.exp)?"fn: "+(b.exp.name||b.exp.toString()):b.exp,newVal:f,oldVal:h}));else if(b===d){s=!1;break a}}catch(A){g(A)}if(!(k=x.$$watchersCount&&x.$$childHead||x!==this&&x.$$nextSibling))for(;x!== -this&&!(k=x.$$nextSibling);)x=x.$parent}while(x=k);if((s||t.length)&&!m--)throw p.$$phase=null,c("infdig",a,u);}while(s||t.length);for(p.$$phase=null;w.length;)try{w.shift()()}catch(y){g(y)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this===p&&l.$$applicationDestroyed();s(this,-this.$$watchersCount);for(var b in this.$$listenerCount)x(this,this.$$listenerCount[b],b);a&&a.$$childHead==this&&(a.$$childHead=this.$$nextSibling);a&&a.$$childTail== -this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=v;this.$on=this.$watch=this.$watchGroup=function(){return v};this.$$listeners={};this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=this.$$watchers=null}},$eval:function(a,b){return h(a)(this,b)}, -$evalAsync:function(a,b){p.$$phase||t.length||l.defer(function(){t.length&&p.$digest()});t.push({scope:this,expression:a,locals:b})},$$postDigest:function(a){w.push(a)},$apply:function(a){try{return r("$apply"),this.$eval(a)}catch(b){g(b)}finally{p.$$phase=null;try{p.$digest()}catch(c){throw g(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&I.push(b);u()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]|| -(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,x(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,f=!1,h={name:a,targetScope:e,stopPropagation:function(){f=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=cb([h],arguments,1),l,n;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(n=d.length;lUa)throw Da("iequirks");var d=ia(pa);d.isEnabled=function(){return b};d.trustAs=c.trustAs;d.getTrusted=c.getTrusted;d.valueOf=c.valueOf;b||(d.trustAs= -d.getTrusted=function(a,b){return b},d.valueOf=Ya);d.parseAs=function(b,c){var e=a(c);return e.literal&&e.constant?e:a(c,function(a){return d.getTrusted(b,a)})};var e=d.parseAs,f=d.getTrusted,g=d.trustAs;m(pa,function(a,b){var c=M(b);d[hb("parse_as_"+c)]=function(b){return e(a,b)};d[hb("get_trusted_"+c)]=function(b){return f(a,b)};d[hb("trust_as_"+c)]=function(b){return g(a,b)}});return d}]}function of(){this.$get=["$window","$document",function(b,a){var c={},d=W((/android (\d+)/.exec(M((b.navigator|| -{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),f=a[0]||{},g,h=/^(Moz|webkit|ms)(?=[A-Z])/,l=f.body&&f.body.style,k=!1,n=!1;if(l){for(var r in l)if(k=h.exec(r)){g=k[0];g=g.substr(0,1).toUpperCase()+g.substr(1);break}g||(g="WebkitOpacity"in l&&"webkit");k=!!("transition"in l||g+"Transition"in l);n=!!("animation"in l||g+"Animation"in l);!d||k&&n||(k=L(l.webkitTransition),n=L(l.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hasEvent:function(a){if("input"=== -a&&11>=Ua)return!1;if(A(c[a])){var b=f.createElement("div");c[a]="on"+a in b}return c[a]},csp:fb(),vendorPrefix:g,transitions:k,animations:n,android:d}}]}function qf(){this.$get=["$templateCache","$http","$q","$sce",function(b,a,c,d){function e(f,g){e.totalPendingRequests++;L(f)&&b.get(f)||(f=d.getTrustedResourceUrl(f));var h=a.defaults&&a.defaults.transformResponse;G(h)?h=h.filter(function(a){return a!==$b}):h===$b&&(h=null);return a.get(f,{cache:b,transformResponse:h})["finally"](function(){e.totalPendingRequests--}).then(function(a){b.put(f, -a.data);return a.data},function(a){if(!g)throw ea("tpload",f,a.status,a.statusText);return c.reject(a)})}e.totalPendingRequests=0;return e}]}function rf(){this.$get=["$rootScope","$browser","$location",function(b,a,c){return{findBindings:function(a,b,c){a=a.getElementsByClassName("ng-binding");var g=[];m(a,function(a){var d=ca.element(a).data("$binding");d&&m(d,function(d){c?(new RegExp("(^|\\s)"+ud(b)+"(\\s|\\||$)")).test(d)&&g.push(a):-1!=d.indexOf(b)&&g.push(a)})});return g},findModels:function(a, -b,c){for(var g=["ng-","data-ng-","ng\\:"],h=0;hb;b=Math.abs(b);var g=Infinity===b;if(!g&&!isFinite(b))return"";var h=b+"",l="",k=!1,n=[];g&&(l="\u221e"); -if(!g&&-1!==h.indexOf("e")){var r=h.match(/([\d\.]+)e(-?)(\d+)/);r&&"-"==r[2]&&r[3]>e+1?b=0:(l=h,k=!0)}if(g||k)0b&&(l=b.toFixed(e),b=parseFloat(l));else{g=(h.split(Dd)[1]||"").length;A(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));b=+(Math.round(+(b.toString()+"e"+e)).toString()+"e"+-e);var g=(""+b).split(Dd),h=g[0],g=g[1]||"",r=0,s=a.lgSize,m=a.gSize;if(h.length>=s+m)for(r=h.length-s,k=0;kb&&(d="-",b=-b);for(b=""+b;b.length-c)e+=c;0===e&&-12==c&&(e=12);return Gb(e,a,d)}}function Hb(b,a){return function(c,d){var e=c["get"+b](),f=rb(a?"SHORT"+b:b);return d[f][e]}}function Ed(b){var a= -(new Date(b,0,1)).getDay();return new Date(b,0,(4>=a?5:12)-a)}function Fd(b){return function(a){var c=Ed(a.getFullYear());a=+new Date(a.getFullYear(),a.getMonth(),a.getDate()+(4-a.getDay()))-+c;a=1+Math.round(a/6048E5);return Gb(a,b)}}function jc(b,a){return 0>=b.getFullYear()?a.ERAS[0]:a.ERAS[1]}function zd(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,l=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=W(b[9]+b[10]),g=W(b[9]+b[11]));h.call(a,W(b[1]), -W(b[2])-1,W(b[3]));f=W(b[4]||0)-f;g=W(b[5]||0)-g;h=W(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));l.call(a,f,g,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e,f){var g="",h=[],l,k;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;L(c)&&(c=gg.test(c)?W(c):a(c));V(c)&&(c=new Date(c));if(!aa(c)||!isFinite(c.getTime()))return c;for(;e;)(k=hg.exec(e))?(h=cb(h,k,1),e=h.pop()):(h.push(e),e=null);var n=c.getTimezoneOffset(); -f&&(n=xc(f,c.getTimezoneOffset()),c=Pb(c,f,!0));m(h,function(a){l=ig[a];g+=l?l(c,b.DATETIME_FORMATS,n):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function bg(){return function(b,a){A(a)&&(a=2);return db(b,a)}}function cg(){return function(b,a,c){a=Infinity===Math.abs(Number(a))?Number(a):W(a);if(isNaN(a))return b;V(b)&&(b=b.toString());if(!G(b)&&!L(b))return b;c=!c||isNaN(c)?0:W(c);c=0>c&&c>=-b.length?b.length+c:c;return 0<=a?b.slice(c,c+a):0===c?b.slice(a,b.length):b.slice(Math.max(0, -c+a),c)}}function Bd(b){function a(a,c){c=c?-1:1;return a.map(function(a){var d=1,h=Ya;if(z(a))h=a;else if(L(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))d="-"==a.charAt(0)?-1:1,a=a.substring(1);if(""!==a&&(h=b(a),h.constant))var l=h(),h=function(a){return a[l]}}return{get:h,descending:d*c}})}function c(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}return function(b,e,f){if(!Ea(b))return b;G(e)||(e=[e]);0===e.length&&(e=["+"]);var g=a(e,f);b=Array.prototype.map.call(b, -function(a,b){return{value:a,predicateValues:g.map(function(d){var e=d.get(a);d=typeof e;if(null===e)d="string",e="null";else if("string"===d)e=e.toLowerCase();else if("object"===d)a:{if("function"===typeof e.valueOf&&(e=e.valueOf(),c(e)))break a;if(rc(e)&&(e=e.toString(),c(e)))break a;e=b}return{value:e,type:d}})}});b.sort(function(a,b){for(var c=0,d=0,e=g.length;db||37<=b&&40>=b||n(a,this,this.value)});if(e.hasEvent("paste"))a.on("paste cut",n)}a.on("change",l);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)}}function Kb(b,a){return function(c,d){var e,f;if(aa(c))return c;if(L(c)){'"'==c.charAt(0)&&'"'==c.charAt(c.length-1)&&(c=c.substring(1,c.length-1)); -if(jg.test(c))return new Date(c);b.lastIndex=0;if(e=b.exec(c))return e.shift(),f=d?{yyyy:d.getFullYear(),MM:d.getMonth()+1,dd:d.getDate(),HH:d.getHours(),mm:d.getMinutes(),ss:d.getSeconds(),sss:d.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},m(e,function(b,c){c=F};g.$observe("min",function(a){F=s(a);h.$validate()})}if(w(g.max)||g.ngMax){var u; -h.$validators.max=function(a){return!r(a)||A(u)||c(a)<=u};g.$observe("max",function(a){u=s(a);h.$validate()})}}}function Id(b,a,c,d){(d.$$hasNativeValidators=H(a[0].validity))&&d.$parsers.push(function(b){var c=a.prop("validity")||{};return c.badInput&&!c.typeMismatch?t:b})}function Jd(b,a,c,d,e){if(w(d)){b=b(d);if(!b.constant)throw J("ngModel")("constexpr",c,d);return b(a)}return e}function lc(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d(?:<\/\1>|)$/,Tb=/<|&#?\w+;/,Bf=/<([\w:]+)/,Cf=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,na={option:[1,'"],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};na.optgroup=na.option;na.tbody=na.tfoot=na.colgroup=na.caption=na.thead; -na.th=na.td;var Pa=Q.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===U.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),Q(O).on("load",a))},toString:function(){var b=[];m(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?y(this[b]):y(this[this.length+b])},length:0,push:lg,sort:[].sort,splice:[].splice},Ab={};m("multiple selected checked disabled readOnly required open".split(" "),function(b){Ab[M(b)]=b});var Tc={};m("input select option textarea button form details".split(" "), -function(b){Tc[b]=!0});var Uc={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};m({data:Wb,removeData:ub,hasData:function(b){for(var a in ib[b.ng339])return!0;return!1}},function(b,a){Q[a]=b});m({data:Wb,inheritedData:zb,scope:function(b){return y.data(b,"$scope")||zb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return y.data(b,"$isolateScope")||y.data(b,"$isolateScopeNoTemplate")},controller:Qc,injector:function(b){return zb(b, -"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:wb,css:function(b,a,c){a=hb(a);if(w(c))b.style[a]=c;else return b.style[a]},attr:function(b,a,c){var d=b.nodeType;if(d!==Na&&2!==d&&8!==d)if(d=M(a),Ab[d])if(w(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||v).specified?d:t;else if(w(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?t:b},prop:function(b,a,c){if(w(c))b[a]=c;else return b[a]}, -text:function(){function b(a,b){if(A(b)){var d=a.nodeType;return d===qa||d===Na?a.textContent:""}a.textContent=b}b.$dv="";return b}(),val:function(b,a){if(A(a)){if(b.multiple&&"select"===ta(b)){var c=[];m(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(A(a))return b.innerHTML;tb(b,!0);b.innerHTML=a},empty:Rc},function(b,a){Q.prototype[a]=function(a,d){var e,f,g=this.length;if(b!==Rc&&(2==b.length&&b!==wb&&b!==Qc? -a:d)===t){if(H(a)){for(e=0;e <= >= && || ! = |".split(" "),function(a){Mb[a]=!0});var rg={n:"\n",f:"\f",r:"\r", -t:"\t",v:"\v","'":"'",'"':'"'},gc=function(a){this.options=a};gc.prototype={constructor:gc,lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a|| -"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=w(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw da("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index","<=",">=");)a={type:q.BinaryExpression,operator:c.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a={type:q.BinaryExpression,operator:c.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a={type:q.BinaryExpression,operator:c.text, -left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+","-","!"))?{type:q.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.constants.hasOwnProperty(this.peek().text)?a=fa(this.constants[this.consume().text]):this.peek().identifier?a=this.identifier():this.peek().constant?a=this.constant(): -this.throwError("not a primary expression",this.peek());for(var c;c=this.expect("(","[",".");)"("===c.text?(a={type:q.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):"["===c.text?(a={type:q.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===c.text?a={type:q.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a=[a];for(var c={type:q.CallExpression,callee:this.identifier(), -arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return c},parseArguments:function(){var a=[];if(")"!==this.peekToken().text){do a.push(this.expression());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:q.Identifier,name:a.text}},constant:function(){return{type:q.Literal,value:this.consume().value}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break; -a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:q.ArrayExpression,elements:a}},object:function(){var a=[],c;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;c={type:q.Property,kind:"init"};this.peek().constant?c.key=this.constant():this.peek().identifier?c.key=this.identifier():this.throwError("invalid key",this.peek());this.consume(":");c.value=this.expression();a.push(c)}while(this.expect(","))}this.consume("}");return{type:q.ObjectExpression,properties:a}}, -throwError:function(a,c){throw da("syntax",c.text,a,c.index+1,this.text,this.text.substring(c.index));},consume:function(a){if(0===this.tokens.length)throw da("ueoe",this.text);var c=this.expect(a);c||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return c},peekToken:function(){if(0===this.tokens.length)throw da("ueoe",this.text);return this.tokens[0]},peek:function(a,c,d,e){return this.peekAhead(0,a,c,d,e)},peekAhead:function(a,c,d,e,f){if(this.tokens.length>a){a=this.tokens[a]; -var g=a.text;if(g===c||g===d||g===e||g===f||!(c||d||e||f))return a}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,e))?(this.tokens.shift(),a):!1},constants:{"true":{type:q.Literal,value:!0},"false":{type:q.Literal,value:!1},"null":{type:q.Literal,value:null},undefined:{type:q.Literal,value:t},"this":{type:q.ThisExpression}}};rd.prototype={compile:function(a,c){var d=this,e=this.astBuilder.ast(a);this.state={nextId:0,filters:{},expensiveChecks:c,fn:{vars:[],body:[],own:{}},assign:{vars:[], -body:[],own:{}},inputs:[]};T(e,d.$filter);var f="",g;this.stage="assign";if(g=pd(e))this.state.computing="assign",f=this.nextId(),this.recurse(g,f),f="fn.assign="+this.generateFunction("assign","s,v,l");g=nd(e.body);d.stage="inputs";m(g,function(a,c){var e="fn"+c;d.state[e]={vars:[],body:[],own:{}};d.state.computing=e;var f=d.nextId();d.recurse(a,f);d.return_(f);d.state.inputs.push(e);a.watchId=c});this.state.computing="fn";this.stage="main";this.recurse(e);f='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+ -"var fn="+this.generateFunction("fn","s,l,a,i")+f+this.watchFns()+"return fn;";f=(new Function("$filter","ensureSafeMemberName","ensureSafeObject","ensureSafeFunction","ifDefined","plus","text",f))(this.$filter,Ca,oa,ld,Yf,md,a);this.state=this.stage=t;f.literal=qd(e);f.constant=e.constant;return f},USE:"use",STRICT:"strict",watchFns:function(){var a=[],c=this.state.inputs,d=this;m(c,function(c){a.push("var "+c+"="+d.generateFunction(c,"s"))});c.length&&a.push("fn.inputs=["+c.join(",")+"];");return a.join("")}, -generateFunction:function(a,c){return"function("+c+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],c=this;m(this.state.filters,function(d,e){a.push(d+"=$filter("+c.escape(e)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length?"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,c,d,e,f,g){var h,l,k=this,n,r;e=e||v;if(!g&&w(a.watchId))c=c||this.nextId(),this.if_("i", -this.lazyAssign(c,this.computedMember("i",a.watchId)),this.lazyRecurse(a,c,d,e,f,!0));else switch(a.type){case q.Program:m(a.body,function(c,d){k.recurse(c.expression,t,t,function(a){l=a});d!==a.body.length-1?k.current().body.push(l,";"):k.return_(l)});break;case q.Literal:r=this.escape(a.value);this.assign(c,r);e(r);break;case q.UnaryExpression:this.recurse(a.argument,t,t,function(a){l=a});r=a.operator+"("+this.ifDefined(l,0)+")";this.assign(c,r);e(r);break;case q.BinaryExpression:this.recurse(a.left, -t,t,function(a){h=a});this.recurse(a.right,t,t,function(a){l=a});r="+"===a.operator?this.plus(h,l):"-"===a.operator?this.ifDefined(h,0)+a.operator+this.ifDefined(l,0):"("+h+")"+a.operator+"("+l+")";this.assign(c,r);e(r);break;case q.LogicalExpression:c=c||this.nextId();k.recurse(a.left,c);k.if_("&&"===a.operator?c:k.not(c),k.lazyRecurse(a.right,c));e(c);break;case q.ConditionalExpression:c=c||this.nextId();k.recurse(a.test,c);k.if_(c,k.lazyRecurse(a.alternate,c),k.lazyRecurse(a.consequent,c));e(c); -break;case q.Identifier:c=c||this.nextId();d&&(d.context="inputs"===k.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);Ca(a.name);k.if_("inputs"===k.stage||k.not(k.getHasOwnProperty("l",a.name)),function(){k.if_("inputs"===k.stage||"s",function(){f&&1!==f&&k.if_(k.not(k.nonComputedMember("s",a.name)),k.lazyAssign(k.nonComputedMember("s",a.name),"{}"));k.assign(c,k.nonComputedMember("s",a.name))})},c&&k.lazyAssign(c,k.nonComputedMember("l", -a.name)));(k.state.expensiveChecks||Fb(a.name))&&k.addEnsureSafeObject(c);e(c);break;case q.MemberExpression:h=d&&(d.context=this.nextId())||this.nextId();c=c||this.nextId();k.recurse(a.object,h,t,function(){k.if_(k.notNull(h),function(){if(a.computed)l=k.nextId(),k.recurse(a.property,l),k.addEnsureSafeMemberName(l),f&&1!==f&&k.if_(k.not(k.computedMember(h,l)),k.lazyAssign(k.computedMember(h,l),"{}")),r=k.ensureSafeObject(k.computedMember(h,l)),k.assign(c,r),d&&(d.computed=!0,d.name=l);else{Ca(a.property.name); -f&&1!==f&&k.if_(k.not(k.nonComputedMember(h,a.property.name)),k.lazyAssign(k.nonComputedMember(h,a.property.name),"{}"));r=k.nonComputedMember(h,a.property.name);if(k.state.expensiveChecks||Fb(a.property.name))r=k.ensureSafeObject(r);k.assign(c,r);d&&(d.computed=!1,d.name=a.property.name)}},function(){k.assign(c,"undefined")});e(c)},!!f);break;case q.CallExpression:c=c||this.nextId();a.filter?(l=k.filter(a.callee.name),n=[],m(a.arguments,function(a){var c=k.nextId();k.recurse(a,c);n.push(c)}),r=l+ -"("+n.join(",")+")",k.assign(c,r),e(c)):(l=k.nextId(),h={},n=[],k.recurse(a.callee,l,h,function(){k.if_(k.notNull(l),function(){k.addEnsureSafeFunction(l);m(a.arguments,function(a){k.recurse(a,k.nextId(),t,function(a){n.push(k.ensureSafeObject(a))})});h.name?(k.state.expensiveChecks||k.addEnsureSafeObject(h.context),r=k.member(h.context,h.name,h.computed)+"("+n.join(",")+")"):r=l+"("+n.join(",")+")";r=k.ensureSafeObject(r);k.assign(c,r)},function(){k.assign(c,"undefined")});e(c)}));break;case q.AssignmentExpression:l= -this.nextId();h={};if(!od(a.left))throw da("lval");this.recurse(a.left,t,h,function(){k.if_(k.notNull(h.context),function(){k.recurse(a.right,l);k.addEnsureSafeObject(k.member(h.context,h.name,h.computed));r=k.member(h.context,h.name,h.computed)+a.operator+l;k.assign(c,r);e(c||r)})},1);break;case q.ArrayExpression:n=[];m(a.elements,function(a){k.recurse(a,k.nextId(),t,function(a){n.push(a)})});r="["+n.join(",")+"]";this.assign(c,r);e(r);break;case q.ObjectExpression:n=[];m(a.properties,function(a){k.recurse(a.value, -k.nextId(),t,function(c){n.push(k.escape(a.key.type===q.Identifier?a.key.name:""+a.key.value)+":"+c)})});r="{"+n.join(",")+"}";this.assign(c,r);e(r);break;case q.ThisExpression:this.assign(c,"s");e("s");break;case q.NGValueParameter:this.assign(c,"v"),e("v")}},getHasOwnProperty:function(a,c){var d=a+"."+c,e=this.current().own;e.hasOwnProperty(d)||(e[d]=this.nextId(!1,a+"&&("+this.escape(c)+" in "+a+")"));return e[d]},assign:function(a,c){if(a)return this.current().body.push(a,"=",c,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)|| -(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,c){return"ifDefined("+a+","+this.escape(c)+")"},plus:function(a,c){return"plus("+a+","+c+")"},return_:function(a){this.current().body.push("return ",a,";")},if_:function(a,c,d){if(!0===a)c();else{var e=this.current().body;e.push("if(",a,"){");c();e.push("}");d&&(e.push("else{"),d(),e.push("}"))}},not:function(a){return"!("+a+")"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,c){return a+ -"."+c},computedMember:function(a,c){return a+"["+c+"]"},member:function(a,c,d){return d?this.computedMember(a,c):this.nonComputedMember(a,c)},addEnsureSafeObject:function(a){this.current().body.push(this.ensureSafeObject(a),";")},addEnsureSafeMemberName:function(a){this.current().body.push(this.ensureSafeMemberName(a),";")},addEnsureSafeFunction:function(a){this.current().body.push(this.ensureSafeFunction(a),";")},ensureSafeObject:function(a){return"ensureSafeObject("+a+",text)"},ensureSafeMemberName:function(a){return"ensureSafeMemberName("+ -a+",text)"},ensureSafeFunction:function(a){return"ensureSafeFunction("+a+",text)"},lazyRecurse:function(a,c,d,e,f,g){var h=this;return function(){h.recurse(a,c,d,e,f,g)}},lazyAssign:function(a,c){var d=this;return function(){d.assign(a,c)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(L(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(V(a))return a.toString();if(!0===a)return"true"; -if(!1===a)return"false";if(null===a)return"null";if("undefined"===typeof a)return"undefined";throw da("esc");},nextId:function(a,c){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(c?"="+c:""));return d},current:function(){return this.state[this.state.computing]}};sd.prototype={compile:function(a,c){var d=this,e=this.astBuilder.ast(a);this.expression=a;this.expensiveChecks=c;T(e,d.$filter);var f,g;if(f=pd(e))g=this.recurse(f);f=nd(e.body);var h;f&&(h=[],m(f,function(a,c){var e=d.recurse(a); -a.input=e;h.push(e);a.watchId=c}));var l=[];m(e.body,function(a){l.push(d.recurse(a.expression))});f=0===e.body.length?function(){}:1===e.body.length?l[0]:function(a,c){var d;m(l,function(e){d=e(a,c)});return d};g&&(f.assign=function(a,c,d){return g(a,d,c)});h&&(f.inputs=h);f.literal=qd(e);f.constant=e.constant;return f},recurse:function(a,c,d){var e,f,g=this,h;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case q.Literal:return this.value(a.value,c);case q.UnaryExpression:return f= -this.recurse(a.argument),this["unary"+a.operator](f,c);case q.BinaryExpression:return e=this.recurse(a.left),f=this.recurse(a.right),this["binary"+a.operator](e,f,c);case q.LogicalExpression:return e=this.recurse(a.left),f=this.recurse(a.right),this["binary"+a.operator](e,f,c);case q.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),c);case q.Identifier:return Ca(a.name,g.expression),g.identifier(a.name,g.expensiveChecks||Fb(a.name), -c,d,g.expression);case q.MemberExpression:return e=this.recurse(a.object,!1,!!d),a.computed||(Ca(a.property.name,g.expression),f=a.property.name),a.computed&&(f=this.recurse(a.property)),a.computed?this.computedMember(e,f,c,d,g.expression):this.nonComputedMember(e,f,g.expensiveChecks,c,d,g.expression);case q.CallExpression:return h=[],m(a.arguments,function(a){h.push(g.recurse(a))}),a.filter&&(f=this.$filter(a.callee.name)),a.filter||(f=this.recurse(a.callee,!0)),a.filter?function(a,d,e,g){for(var m= -[],q=0;q":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)>c(e,f,g,h);return d?{value:e}:e}},"binary<=":function(a,c,d){return function(e, -f,g,h){e=a(e,f,g,h)<=c(e,f,g,h);return d?{value:e}:e}},"binary>=":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)>=c(e,f,g,h);return d?{value:e}:e}},"binary&&":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)&&c(e,f,g,h);return d?{value:e}:e}},"binary||":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)||c(e,f,g,h);return d?{value:e}:e}},"ternary?:":function(a,c,d,e){return function(f,g,h,l){f=a(f,g,h,l)?c(f,g,h,l):d(f,g,h,l);return e?{value:f}:f}},value:function(a,c){return function(){return c? -{context:t,name:t,value:a}:a}},identifier:function(a,c,d,e,f){return function(g,h,l,k){g=h&&a in h?h:g;e&&1!==e&&g&&!g[a]&&(g[a]={});h=g?g[a]:t;c&&oa(h,f);return d?{context:g,name:a,value:h}:h}},computedMember:function(a,c,d,e,f){return function(g,h,l,k){var n=a(g,h,l,k),m,s;null!=n&&(m=c(g,h,l,k),Ca(m,f),e&&1!==e&&n&&!n[m]&&(n[m]={}),s=n[m],oa(s,f));return d?{context:n,name:m,value:s}:s}},nonComputedMember:function(a,c,d,e,f,g){return function(h,l,k,n){h=a(h,l,k,n);f&&1!==f&&h&&!h[c]&&(h[c]={}); -l=null!=h?h[c]:t;(d||Fb(c))&&oa(l,g);return e?{context:h,name:c,value:l}:l}},inputs:function(a,c){return function(d,e,f,g){return g?g[c]:a(d,e,f)}}};var hc=function(a,c,d){this.lexer=a;this.$filter=c;this.options=d;this.ast=new q(this.lexer);this.astCompiler=d.csp?new sd(this.ast,c):new rd(this.ast,c)};hc.prototype={constructor:hc,parse:function(a){return this.astCompiler.compile(a,this.options.expensiveChecks)}};ga();ga();var Zf=Object.prototype.valueOf,Da=J("$sce"),pa={HTML:"html",CSS:"css",URL:"url", -RESOURCE_URL:"resourceUrl",JS:"js"},ea=J("$compile"),X=U.createElement("a"),wd=Ba(O.location.href);xd.$inject=["$document"];Lc.$inject=["$provide"];yd.$inject=["$locale"];Ad.$inject=["$locale"];var Dd=".",ig={yyyy:Y("FullYear",4),yy:Y("FullYear",2,0,!0),y:Y("FullYear",1),MMMM:Hb("Month"),MMM:Hb("Month",!0),MM:Y("Month",2,1),M:Y("Month",1,1),dd:Y("Date",2),d:Y("Date",1),HH:Y("Hours",2),H:Y("Hours",1),hh:Y("Hours",2,-12),h:Y("Hours",1,-12),mm:Y("Minutes",2),m:Y("Minutes",1),ss:Y("Seconds",2),s:Y("Seconds", -1),sss:Y("Milliseconds",3),EEEE:Hb("Day"),EEE:Hb("Day",!0),a:function(a,c){return 12>a.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a,c,d){a=-1*d;return a=(0<=a?"+":"")+(Gb(Math[0=a.getFullYear()?c.ERANAMES[0]:c.ERANAMES[1]}},hg=/((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,gg=/^\-?\d+$/;zd.$inject=["$locale"];var dg=ra(M),eg=ra(rb);Bd.$inject= -["$parse"];var ie=ra({restrict:"E",compile:function(a,c){if(!c.href&&!c.xlinkHref)return function(a,c){if("a"===c[0].nodeName.toLowerCase()){var f="[object SVGAnimatedString]"===sa.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(f)||a.preventDefault()})}}}}),sb={};m(Ab,function(a,c){function d(a,d,f){a.$watch(f[e],function(a){f.$set(c,!!a)})}if("multiple"!=a){var e=wa("ng-"+c),f=d;"checked"===a&&(f=function(a,c,f){f.ngModel!==f[e]&&d(a,c,f)});sb[e]=function(){return{restrict:"A", -priority:100,link:f}}}});m(Uc,function(a,c){sb[c]=function(){return{priority:100,link:function(a,e,f){if("ngPattern"===c&&"/"==f.ngPattern.charAt(0)&&(e=f.ngPattern.match(kg))){f.$set("ngPattern",new RegExp(e[1],e[2]));return}a.$watch(f[c],function(a){f.$set(c,a)})}}}});m(["src","srcset","href"],function(a){var c=wa("ng-"+a);sb[c]=function(){return{priority:99,link:function(d,e,f){var g=a,h=a;"href"===a&&"[object SVGAnimatedString]"===sa.call(e.prop("href"))&&(h="xlinkHref",f.$attr[h]="xlink:href", -g=null);f.$observe(c,function(c){c?(f.$set(h,c),Ua&&g&&e.prop(g,f[h])):"href"===a&&f.$set(h,null)})}}}});var Ib={$addControl:v,$$renameControl:function(a,c){a.$name=c},$removeControl:v,$setValidity:v,$setDirty:v,$setPristine:v,$setSubmitted:v};Gd.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var Od=function(a){return["$timeout",function(c){return{name:"form",restrict:a?"EAC":"E",controller:Gd,compile:function(d,e){d.addClass(Va).addClass(mb);var f=e.name?"name":a&&e.ngForm?"ngForm": -!1;return{pre:function(a,d,e,k){if(!("action"in e)){var n=function(c){a.$apply(function(){k.$commitViewValue();k.$setSubmitted()});c.preventDefault()};d[0].addEventListener("submit",n,!1);d.on("$destroy",function(){c(function(){d[0].removeEventListener("submit",n,!1)},0,!1)})}var m=k.$$parentForm;f&&(Eb(a,k.$name,k,k.$name),e.$observe(f,function(c){k.$name!==c&&(Eb(a,k.$name,t,k.$name),m.$$renameControl(k,c),Eb(a,k.$name,k,k.$name))}));d.on("$destroy",function(){m.$removeControl(k);f&&Eb(a,e[f],t, -k.$name);P(k,Ib)})}}}}}]},je=Od(),we=Od(!0),jg=/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,sg=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,tg=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,ug=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,Pd=/^(\d{4})-(\d{2})-(\d{2})$/,Qd=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,mc=/^(\d{4})-W(\d\d)$/,Rd=/^(\d{4})-(\d\d)$/, -Sd=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Td={text:function(a,c,d,e,f,g){kb(a,c,d,e,f,g);kc(e)},date:lb("date",Pd,Kb(Pd,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":lb("datetimelocal",Qd,Kb(Qd,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:lb("time",Sd,Kb(Sd,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:lb("week",mc,function(a,c){if(aa(a))return a;if(L(a)){mc.lastIndex=0;var d=mc.exec(a);if(d){var e=+d[1],f=+d[2],g=d=0,h=0,l=0,k=Ed(e),f=7*(f-1);c&&(d=c.getHours(),g= -c.getMinutes(),h=c.getSeconds(),l=c.getMilliseconds());return new Date(e,0,k.getDate()+f,d,g,h,l)}}return NaN},"yyyy-Www"),month:lb("month",Rd,Kb(Rd,["yyyy","MM"]),"yyyy-MM"),number:function(a,c,d,e,f,g){Id(a,c,d,e);kb(a,c,d,e,f,g);e.$$parserName="number";e.$parsers.push(function(a){return e.$isEmpty(a)?null:ug.test(a)?parseFloat(a):t});e.$formatters.push(function(a){if(!e.$isEmpty(a)){if(!V(a))throw Lb("numfmt",a);a=a.toString()}return a});if(w(d.min)||d.ngMin){var h;e.$validators.min=function(a){return e.$isEmpty(a)|| -A(h)||a>=h};d.$observe("min",function(a){w(a)&&!V(a)&&(a=parseFloat(a,10));h=V(a)&&!isNaN(a)?a:t;e.$validate()})}if(w(d.max)||d.ngMax){var l;e.$validators.max=function(a){return e.$isEmpty(a)||A(l)||a<=l};d.$observe("max",function(a){w(a)&&!V(a)&&(a=parseFloat(a,10));l=V(a)&&!isNaN(a)?a:t;e.$validate()})}},url:function(a,c,d,e,f,g){kb(a,c,d,e,f,g);kc(e);e.$$parserName="url";e.$validators.url=function(a,c){var d=a||c;return e.$isEmpty(d)||sg.test(d)}},email:function(a,c,d,e,f,g){kb(a,c,d,e,f,g);kc(e); -e.$$parserName="email";e.$validators.email=function(a,c){var d=a||c;return e.$isEmpty(d)||tg.test(d)}},radio:function(a,c,d,e){A(d.name)&&c.attr("name",++nb);c.on("click",function(a){c[0].checked&&e.$setViewValue(d.value,a&&a.type)});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e,f,g,h,l){var k=Jd(l,a,"ngTrueValue",d.ngTrueValue,!0),n=Jd(l,a,"ngFalseValue",d.ngFalseValue,!1);c.on("click",function(a){e.$setViewValue(c[0].checked,a&& -a.type)});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return!1===a};e.$formatters.push(function(a){return ka(a,k)});e.$parsers.push(function(a){return a?k:n})},hidden:v,button:v,submit:v,reset:v,file:v},Fc=["$browser","$sniffer","$filter","$parse",function(a,c,d,e){return{restrict:"E",require:["?ngModel"],link:{pre:function(f,g,h,l){l[0]&&(Td[M(h.type)]||Td.text)(f,g,h,l[0],c,a,d,e)}}}}],vg=/^(true|false|\d+)$/,Oe=function(){return{restrict:"A",priority:100,compile:function(a, -c){return vg.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue,function(a){f.$set("value",a)})}}}},oe=["$compile",function(a){return{restrict:"AC",compile:function(c){a.$$addBindingClass(c);return function(c,e,f){a.$$addBindingInfo(e,f.ngBind);e=e[0];c.$watch(f.ngBind,function(a){e.textContent=a===t?"":a})}}}}],qe=["$interpolate","$compile",function(a,c){return{compile:function(d){c.$$addBindingClass(d);return function(d,f,g){d=a(f.attr(g.$attr.ngBindTemplate)); -c.$$addBindingInfo(f,d.expressions);f=f[0];g.$observe("ngBindTemplate",function(a){f.textContent=a===t?"":a})}}}}],pe=["$sce","$parse","$compile",function(a,c,d){return{restrict:"A",compile:function(e,f){var g=c(f.ngBindHtml),h=c(f.ngBindHtml,function(a){return(a||"").toString()});d.$$addBindingClass(e);return function(c,e,f){d.$$addBindingInfo(e,f.ngBindHtml);c.$watch(h,function(){e.html(a.getTrustedHtml(g(c))||"")})}}}}],Ne=ra({restrict:"A",require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}), -re=lc("",!0),te=lc("Odd",0),se=lc("Even",1),ue=Ma({compile:function(a,c){c.$set("ngCloak",t);a.removeClass("ng-cloak")}}),ve=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Kc={},wg={blur:!0,focus:!0};m("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var c=wa("ng-"+a);Kc[c]=["$parse","$rootScope",function(d,e){return{restrict:"A",compile:function(f,g){var h= -d(g[c],null,!0);return function(c,d){d.on(a,function(d){var f=function(){h(c,{$event:d})};wg[a]&&e.$$phase?c.$evalAsync(f):c.$apply(f)})}}}}]});var ye=["$animate",function(a){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var h,l,k;c.$watch(e.ngIf,function(c){c?l||g(function(c,f){l=f;c[c.length++]=U.createComment(" end ngIf: "+e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)}):(k&&(k.remove(),k=null),l&&(l.$destroy(),l=null),h&&(k= -qb(h.clone),a.leave(k).then(function(){k=null}),h=null))})}}}],ze=["$templateRequest","$anchorScroll","$animate",function(a,c,d){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:ca.noop,compile:function(e,f){var g=f.ngInclude||f.src,h=f.onload||"",l=f.autoscroll;return function(e,f,m,s,q){var t=0,F,u,p,v=function(){u&&(u.remove(),u=null);F&&(F.$destroy(),F=null);p&&(d.leave(p).then(function(){u=null}),u=p,p=null)};e.$watch(g,function(g){var m=function(){!w(l)||l&&!e.$eval(l)|| -c()},r=++t;g?(a(g,!0).then(function(a){if(r===t){var c=e.$new();s.template=a;a=q(c,function(a){v();d.enter(a,null,f).then(m)});F=c;p=a;F.$emit("$includeContentLoaded",g);e.$eval(h)}},function(){r===t&&(v(),e.$emit("$includeContentError",g))}),e.$emit("$includeContentRequested",g)):(v(),s.template=null)})}}}}],Qe=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(c,d,e,f){/SVG/.test(d[0].toString())?(d.empty(),a(Nc(f.template,U).childNodes)(c,function(a){d.append(a)}, -{futureParentElement:d})):(d.html(f.template),a(d.contents())(c))}}}],Ae=Ma({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Me=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,c,d,e){var f=c.attr(d.$attr.ngList)||", ",g="false"!==d.ngTrim,h=g?R(f):f;e.$parsers.push(function(a){if(!A(a)){var c=[];a&&m(a.split(h),function(a){a&&c.push(g?R(a):a)});return c}});e.$formatters.push(function(a){return G(a)?a.join(f):t});e.$isEmpty=function(a){return!a|| -!a.length}}}},mb="ng-valid",Kd="ng-invalid",Va="ng-pristine",Jb="ng-dirty",Md="ng-pending",Lb=new J("ngModel"),xg=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,c,d,e,f,g,h,l,k,n){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=t;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty= -!1;this.$valid=!0;this.$invalid=!1;this.$error={};this.$$success={};this.$pending=t;this.$name=n(d.name||"",!1)(a);var r=f(d.ngModel),s=r.assign,q=r,C=s,F=null,u,p=this;this.$$setOptions=function(a){if((p.$options=a)&&a.getterSetter){var c=f(d.ngModel+"()"),g=f(d.ngModel+"($$$p)");q=function(a){var d=r(a);z(d)&&(d=c(a));return d};C=function(a,c){z(r(a))?g(a,{$$$p:p.$modelValue}):s(a,p.$modelValue)}}else if(!r.assign)throw Lb("nonassign",d.ngModel,ua(e));};this.$render=v;this.$isEmpty=function(a){return A(a)|| -""===a||null===a||a!==a};var K=e.inheritedData("$formController")||Ib,y=0;Hd({ctrl:this,$element:e,set:function(a,c){a[c]=!0},unset:function(a,c){delete a[c]},parentForm:K,$animate:g});this.$setPristine=function(){p.$dirty=!1;p.$pristine=!0;g.removeClass(e,Jb);g.addClass(e,Va)};this.$setDirty=function(){p.$dirty=!0;p.$pristine=!1;g.removeClass(e,Va);g.addClass(e,Jb);K.$setDirty()};this.$setUntouched=function(){p.$touched=!1;p.$untouched=!0;g.setClass(e,"ng-untouched","ng-touched")};this.$setTouched= -function(){p.$touched=!0;p.$untouched=!1;g.setClass(e,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){h.cancel(F);p.$viewValue=p.$$lastCommittedViewValue;p.$render()};this.$validate=function(){if(!V(p.$modelValue)||!isNaN(p.$modelValue)){var a=p.$$rawModelValue,c=p.$valid,d=p.$modelValue,e=p.$options&&p.$options.allowInvalid;p.$$runValidators(a,p.$$lastCommittedViewValue,function(f){e||c===f||(p.$modelValue=f?a:t,p.$modelValue!==d&&p.$$writeModelToScope())})}};this.$$runValidators= -function(a,c,d){function e(){var d=!0;m(p.$validators,function(e,f){var h=e(a,c);d=d&&h;g(f,h)});return d?!0:(m(p.$asyncValidators,function(a,c){g(c,null)}),!1)}function f(){var d=[],e=!0;m(p.$asyncValidators,function(f,h){var k=f(a,c);if(!k||!z(k.then))throw Lb("$asyncValidators",k);g(h,t);d.push(k.then(function(){g(h,!0)},function(a){e=!1;g(h,!1)}))});d.length?k.all(d).then(function(){h(e)},v):h(!0)}function g(a,c){l===y&&p.$setValidity(a,c)}function h(a){l===y&&d(a)}y++;var l=y;(function(){var a= -p.$$parserName||"parse";if(u===t)g(a,null);else return u||(m(p.$validators,function(a,c){g(c,null)}),m(p.$asyncValidators,function(a,c){g(c,null)})),g(a,u),u;return!0})()?e()?f():h(!1):h(!1)};this.$commitViewValue=function(){var a=p.$viewValue;h.cancel(F);if(p.$$lastCommittedViewValue!==a||""===a&&p.$$hasNativeValidators)p.$$lastCommittedViewValue=a,p.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var c=p.$$lastCommittedViewValue;if(u=A(c)?t:!0)for(var d= -0;df||e.$isEmpty(c)||c.length<=f}}}}},Ic=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){if(e){var f=0;d.$observe("minlength",function(a){f=W(a)||0;e.$validate()});e.$validators.minlength=function(a,c){return e.$isEmpty(c)||c.length>=f}}}}};O.angular.bootstrap?console.log("WARNING: Tried to load angular more than once."):(ce(),ee(ca),y(U).ready(function(){Zd(U,Ac)}))})(window,document);!window.angular.$$csp()&&window.angular.element(document).find("head").prepend(''); -//# sourceMappingURL=angular.min.js.map diff --git a/servant-js/examples/www/angular/index.html b/servant-js/examples/www/angular/index.html deleted file mode 100644 index 46ecf5ae..00000000 --- a/servant-js/examples/www/angular/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - Servant: counter - - - - - -

Angular version

-{{ 'Counter: ' + counter }} - - - - diff --git a/servant-js/examples/www/angular/service.html b/servant-js/examples/www/angular/service.html deleted file mode 100644 index 8408ce61..00000000 --- a/servant-js/examples/www/angular/service.html +++ /dev/null @@ -1,39 +0,0 @@ - - - Servant: counter - - - - -

Angular version (Service version)

-{{ 'Counter: ' + counter }} - - - - - diff --git a/servant-js/examples/www/axios/axios.min.js b/servant-js/examples/www/axios/axios.min.js deleted file mode 100644 index 3e3e2da5..00000000 --- a/servant-js/examples/www/axios/axios.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/* axios v0.5.4 | (c) 2015 by Matt Zabriskie */ -var axios=function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){t.exports=n(1)},function(t,e,n){"use strict";var r=n(2),o=n(3),i=n(4),s=n(5),u=n(6);!function(){var t=n(9);t&&"function"==typeof t.polyfill&&t.polyfill()}();var a=t.exports=function c(t){t=o.merge({method:"get",headers:{},transformRequest:r.transformRequest,transformResponse:r.transformResponse},t),t.withCredentials=t.withCredentials||r.withCredentials;var e=[s,void 0],n=Promise.resolve(t);for(c.interceptors.request.forEach(function(t){e.unshift(t.fulfilled,t.rejected)}),c.interceptors.response.forEach(function(t){e.push(t.fulfilled,t.rejected)});e.length;)n=n.then(e.shift(),e.shift());return n.success=function(t){return i("success","then","https://github.com/mzabriskie/axios/blob/master/README.md#response-api"),n.then(function(e){t(e.data,e.status,e.headers,e.config)}),n},n.error=function(t){return i("error","catch","https://github.com/mzabriskie/axios/blob/master/README.md#response-api"),n.then(null,function(e){t(e.data,e.status,e.headers,e.config)}),n},n};a.defaults=r,a.all=function(t){return Promise.all(t)},a.spread=n(7),a.interceptors={request:new u,response:new u},function(){function t(){o.forEach(arguments,function(t){a[t]=function(e,n){return a(o.merge(n||{},{method:t,url:e}))}})}function e(){o.forEach(arguments,function(t){a[t]=function(e,n,r){return a(o.merge(r||{},{method:t,url:e,data:n}))}})}t("delete","get","head"),e("post","put","patch")}()},function(t,e,n){"use strict";var r=n(3),o=/^\)\]\}',?\n/,i={"Content-Type":"application/x-www-form-urlencoded"};t.exports={transformRequest:[function(t,e){return r.isFormData(t)?t:r.isArrayBuffer(t)?t:r.isArrayBufferView(t)?t.buffer:!r.isObject(t)||r.isFile(t)||r.isBlob(t)?t:(!r.isUndefined(e)&&r.isUndefined(e["Content-Type"])&&(e["Content-Type"]="application/json;charset=utf-8"),JSON.stringify(t))}],transformResponse:[function(t){if("string"==typeof t){t=t.replace(o,"");try{t=JSON.parse(t)}catch(e){}}return t}],headers:{common:{Accept:"application/json, text/plain, */*"},patch:r.merge(i),post:r.merge(i),put:r.merge(i)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"}},function(t){"use strict";function e(t){return"[object Array]"===m.call(t)}function n(t){return"[object ArrayBuffer]"===m.call(t)}function r(t){return"[object FormData]"===m.call(t)}function o(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer}function i(t){return"string"==typeof t}function s(t){return"number"==typeof t}function u(t){return"undefined"==typeof t}function a(t){return null!==t&&"object"==typeof t}function c(t){return"[object Date]"===m.call(t)}function f(t){return"[object File]"===m.call(t)}function l(t){return"[object Blob]"===m.call(t)}function p(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}function h(t,n){if(null!==t&&"undefined"!=typeof t){var r=e(t)||"object"==typeof t&&!isNaN(t.length);if("object"==typeof t||r||(t=[t]),r)for(var o=0,i=t.length;i>o;o++)n.call(null,t[o],o,t);else for(var s in t)t.hasOwnProperty(s)&&n.call(null,t[s],s,t)}}function d(){var t={};return h(arguments,function(e){h(e,function(e,n){t[n]=e})}),t}var m=Object.prototype.toString;t.exports={isArray:e,isArrayBuffer:n,isFormData:r,isArrayBufferView:o,isString:i,isNumber:s,isObject:a,isUndefined:u,isDate:c,isFile:f,isBlob:l,forEach:h,merge:d,trim:p}},function(t){"use strict";t.exports=function(t,e,n){try{console.warn("DEPRECATED method `"+t+"`."+(e?" Use `"+e+"` instead.":"")+" This method will be removed in a future release."),n&&console.warn("For more information about usage see "+n)}catch(r){}}},function(t,e,n){(function(e){"use strict";t.exports=function(t){return new Promise(function(r,o){try{"undefined"!=typeof window?n(8)(r,o,t):"undefined"!=typeof e&&n(8)(r,o,t)}catch(i){o(i)}})}}).call(e,n(10))},function(t,e,n){"use strict";function r(){this.handlers=[]}var o=n(3);r.prototype.use=function(t,e){return this.handlers.push({fulfilled:t,rejected:e}),this.handlers.length-1},r.prototype.eject=function(t){this.handlers[t]&&(this.handlers[t]=null)},r.prototype.forEach=function(t){o.forEach(this.handlers,function(e){null!==e&&t(e)})},t.exports=r},function(t){"use strict";t.exports=function(t){return function(e){t.apply(null,e)}}},function(t,e,n){"use strict";var r=n(2),o=n(3),i=n(11),s=n(12),u=n(13),a=n(14),c=n(15);t.exports=function(t,e,n){var f=a(n.data,n.headers,n.transformRequest),l=o.merge(r.headers.common,r.headers[n.method]||{},n.headers||{});o.isFormData(f)&&delete l["Content-Type"];var p=new(XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP");p.open(n.method.toUpperCase(),i(n.url,n.params),!0),p.onreadystatechange=function(){if(p&&4===p.readyState){var r=u(p.getAllResponseHeaders()),o=-1!==["text",""].indexOf(n.responseType||"")?p.responseText:p.response,i={data:a(o,r,n.transformResponse),status:p.status,statusText:p.statusText,headers:r,config:n};(p.status>=200&&p.status<300?t:e)(i),p=null}};var h=c(n.url)?s.read(n.xsrfCookieName||r.xsrfCookieName):void 0;if(h&&(l[n.xsrfHeaderName||r.xsrfHeaderName]=h),o.forEach(l,function(t,e){f||"content-type"!==e.toLowerCase()?p.setRequestHeader(e,t):delete l[e]}),n.withCredentials&&(p.withCredentials=!0),n.responseType)try{p.responseType=n.responseType}catch(d){if("json"!==p.responseType)throw d}o.isArrayBuffer(f)&&(f=new DataView(f)),p.send(f)}},function(t,e,n){var r;(function(t,o,i){/*! - * @overview es6-promise - a tiny implementation of Promises/A+. - * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) - * @license Licensed under MIT license - * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE - * @version 2.0.1 - */ -(function(){"use strict";function s(t){return"function"==typeof t||"object"==typeof t&&null!==t}function u(t){return"function"==typeof t}function a(t){return"object"==typeof t&&null!==t}function c(){}function f(){return function(){t.nextTick(d)}}function l(){var t=0,e=new X(d),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function p(){var t=new MessageChannel;return t.port1.onmessage=d,function(){t.port2.postMessage(0)}}function h(){return function(){setTimeout(d,1)}}function d(){for(var t=0;H>t;t+=2){var e=J[t],n=J[t+1];e(n),J[t]=void 0,J[t+1]=void 0}H=0}function m(){}function y(){return new TypeError("You cannot resolve a promise with itself")}function v(){return new TypeError("A promises callback cannot return that same promise.")}function w(t){try{return t.then}catch(e){return z.error=e,z}}function g(t,e,n,r){try{t.call(e,n,r)}catch(o){return o}}function b(t,e,n){L(function(t){var r=!1,o=g(n,e,function(n){r||(r=!0,e!==n?A(t,n):j(t,n))},function(e){r||(r=!0,T(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&o&&(r=!0,T(t,o))},t)}function _(t,e){e._state===Y?j(t,e._result):t._state===$?T(t,e._result):C(e,void 0,function(e){A(t,e)},function(e){T(t,e)})}function x(t,e){if(e.constructor===t.constructor)_(t,e);else{var n=w(e);n===z?T(t,z.error):void 0===n?j(t,e):u(n)?b(t,e,n):j(t,e)}}function A(t,e){t===e?T(t,y()):s(e)?x(t,e):j(t,e)}function E(t){t._onerror&&t._onerror(t._result),R(t)}function j(t,e){t._state===K&&(t._result=e,t._state=Y,0===t._subscribers.length||L(R,t))}function T(t,e){t._state===K&&(t._state=$,t._result=e,L(E,t))}function C(t,e,n,r){var o=t._subscribers,i=o.length;t._onerror=null,o[i]=e,o[i+Y]=n,o[i+$]=r,0===i&&t._state&&L(R,t)}function R(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r,o,i=t._result,s=0;s1)throw new Error("Second argument not supported");if("object"!=typeof t)throw new TypeError("Argument must be an object");return c.prototype=t,new c},0),L=function(t,e){J[H]=t,J[H+1]=e,H+=2,2===H&&U()},I="undefined"!=typeof window?window:{},X=I.MutationObserver||I.WebKitMutationObserver,V="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,J=new Array(1e3);U="undefined"!=typeof t&&"[object process]"==={}.toString.call(t)?f():X?l():V?p():h();var K=void 0,Y=1,$=2,z=new S,G=new S;D.prototype._validateInput=function(t){return q(t)},D.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},D.prototype._init=function(){this._result=new Array(this.length)};var W=D;D.prototype._enumerate=function(){for(var t=this.length,e=this.promise,n=this._input,r=0;e._state===K&&t>r;r++)this._eachEntry(n[r],r)},D.prototype._eachEntry=function(t,e){var n=this._instanceConstructor;a(t)?t.constructor===n&&t._state!==K?(t._onerror=null,this._settledAt(t._state,e,t._result)):this._willSettleAt(n.resolve(t),e):(this._remaining--,this._result[e]=this._makeResult(Y,e,t))},D.prototype._settledAt=function(t,e,n){var r=this.promise;r._state===K&&(this._remaining--,this._abortOnReject&&t===$?T(r,n):this._result[e]=this._makeResult(t,e,n)),0===this._remaining&&j(r,this._result)},D.prototype._makeResult=function(t,e,n){return n},D.prototype._willSettleAt=function(t,e){var n=this;C(t,void 0,function(t){n._settledAt(Y,e,t)},function(t){n._settledAt($,e,t)})};var Q=function(t,e){return new W(this,t,!0,e).promise},Z=function(t,e){function n(t){A(i,t)}function r(t){T(i,t)}var o=this,i=new o(m,e);if(!q(t))return T(i,new TypeError("You must pass an array to race.")),i;for(var s=t.length,u=0;i._state===K&&s>u;u++)C(o.resolve(t[u]),void 0,n,r);return i},te=function(t,e){var n=this;if(t&&"object"==typeof t&&t.constructor===n)return t;var r=new n(m,e);return A(r,t),r},ee=function(t,e){var n=this,r=new n(m,e);return T(r,t),r},ne=0,re=M;M.all=Q,M.race=Z,M.resolve=te,M.reject=ee,M.prototype={constructor:M,then:function(t,e){var n=this,r=n._state;if(r===Y&&!t||r===$&&!e)return this;var o=new this.constructor(m),i=n._result;if(r){var s=arguments[r-1];L(function(){P(r,o,s,i)})}else C(n,o,t,e);return o},"catch":function(t){return this.then(null,t)}};var oe=function(){var t;t="undefined"!=typeof o?o:"undefined"!=typeof window&&window.document?window:self;var e="Promise"in t&&"resolve"in t.Promise&&"reject"in t.Promise&&"all"in t.Promise&&"race"in t.Promise&&function(){var e;return new t.Promise(function(t){e=t}),u(e)}();e||(t.Promise=re)},ie={Promise:re,polyfill:oe};n(16).amd?(r=function(){return ie}.call(e,n,e,i),!(void 0!==r&&(i.exports=r))):"undefined"!=typeof i&&i.exports?i.exports=ie:"undefined"!=typeof this&&(this.ES6Promise=ie)}).call(this)}).call(e,n(10),function(){return this}(),n(17)(t))},function(t){function e(){if(!i){i=!0;for(var t,e=o.length;e;){t=o,o=[];for(var n=-1;++n0&&(t+=(-1===t.indexOf("?")?"?":"&")+n.join("&")),t}},function(t,e,n){"use strict";var r=n(3);t.exports={write:function(t,e,n,o,i,s){var u=[];u.push(t+"="+encodeURIComponent(e)),r.isNumber(n)&&u.push("expires="+new Date(n).toGMTString()),r.isString(o)&&u.push("path="+o),r.isString(i)&&u.push("domain="+i),s===!0&&u.push("secure"),document.cookie=u.join("; ")},read:function(t){var e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}},function(t,e,n){"use strict";var r=n(3);t.exports=function(t){var e,n,o,i={};return t?(r.forEach(t.split("\n"),function(t){o=t.indexOf(":"),e=r.trim(t.substr(0,o)).toLowerCase(),n=r.trim(t.substr(o+1)),e&&(i[e]=i[e]?i[e]+", "+n:n)}),i):i}},function(t,e,n){"use strict";var r=n(3);t.exports=function(t,e,n){return r.forEach(n,function(n){t=n(t,e)}),t}},function(t,e,n){"use strict";function r(t){var e=t;return s&&(u.setAttribute("href",e),e=u.href),u.setAttribute("href",e),{href:u.href,protocol:u.protocol?u.protocol.replace(/:$/,""):"",host:u.host,search:u.search?u.search.replace(/^\?/,""):"",hash:u.hash?u.hash.replace(/^#/,""):"",hostname:u.hostname,port:u.port,pathname:"/"===u.pathname.charAt(0)?u.pathname:"/"+u.pathname}}var o,i=n(3),s=/(msie|trident)/i.test(navigator.userAgent),u=document.createElement("a");o=r(window.location.href),t.exports=function(t){var e=i.isString(t)?r(t):t;return e.protocol===o.protocol&&e.host===o.host}},function(t){t.exports=function(){throw new Error("define cannot be used indirect")}},function(t){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}}]); -//# sourceMappingURL=axios.min.map \ No newline at end of file diff --git a/servant-js/examples/www/axios/index.html b/servant-js/examples/www/axios/index.html deleted file mode 100644 index 2f3a0d7c..00000000 --- a/servant-js/examples/www/axios/index.html +++ /dev/null @@ -1,40 +0,0 @@ - - - Servant: counter - - - -

Axios version

-Counter: 0 - - - - - - - diff --git a/servant-js/examples/www/index.html b/servant-js/examples/www/index.html deleted file mode 100644 index b9411ac1..00000000 --- a/servant-js/examples/www/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - Servant: counter - - - - - - - - - - - diff --git a/servant-js/examples/www/jquery/index.html b/servant-js/examples/www/jquery/index.html deleted file mode 100644 index eb1a5b6c..00000000 --- a/servant-js/examples/www/jquery/index.html +++ /dev/null @@ -1,40 +0,0 @@ - - - Servant: counter - - - -

JQuery version

-Counter: 0 - - - - - - - diff --git a/servant-js/examples/www/jquery/jquery.min.js b/servant-js/examples/www/jquery/jquery.min.js deleted file mode 100644 index ab28a247..00000000 --- a/servant-js/examples/www/jquery/jquery.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; -if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("